1219820Sjeff/*
2219820Sjeff * Copyright (c) 2005 Topspin Communications.  All rights reserved.
3219820Sjeff * Copyright (c) 2005, 2006, 2007 Cisco Systems.  All rights reserved.
4219820Sjeff * Copyright (c) 2005 PathScale, Inc.  All rights reserved.
5219820Sjeff * Copyright (c) 2006 Mellanox Technologies.  All rights reserved.
6219820Sjeff *
7219820Sjeff * This software is available to you under a choice of one of two
8219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
9219820Sjeff * General Public License (GPL) Version 2, available from the file
10219820Sjeff * COPYING in the main directory of this source tree, or the
11219820Sjeff * OpenIB.org BSD license below:
12219820Sjeff *
13219820Sjeff *     Redistribution and use in source and binary forms, with or
14219820Sjeff *     without modification, are permitted provided that the following
15219820Sjeff *     conditions are met:
16219820Sjeff *
17219820Sjeff *      - Redistributions of source code must retain the above
18219820Sjeff *        copyright notice, this list of conditions and the following
19219820Sjeff *        disclaimer.
20219820Sjeff *
21219820Sjeff *      - Redistributions in binary form must reproduce the above
22219820Sjeff *        copyright notice, this list of conditions and the following
23219820Sjeff *        disclaimer in the documentation and/or other materials
24219820Sjeff *        provided with the distribution.
25219820Sjeff *
26219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33219820Sjeff * SOFTWARE.
34219820Sjeff */
35219820Sjeff
36219820Sjeff#include <linux/file.h>
37219820Sjeff#include <linux/fs.h>
38219820Sjeff
39219820Sjeff#include <asm/uaccess.h>
40219820Sjeff#include <asm/fcntl.h>
41219820Sjeff
42219820Sjeff#include "uverbs.h"
43219820Sjeff
44219820Sjeffstatic struct lock_class_key pd_lock_key;
45219820Sjeffstatic struct lock_class_key mr_lock_key;
46219820Sjeffstatic struct lock_class_key cq_lock_key;
47219820Sjeffstatic struct lock_class_key qp_lock_key;
48219820Sjeffstatic struct lock_class_key ah_lock_key;
49219820Sjeffstatic struct lock_class_key srq_lock_key;
50219820Sjeff
51219820Sjeff#define INIT_UDATA(udata, ibuf, obuf, ilen, olen)			\
52219820Sjeff	do {								\
53219820Sjeff		(udata)->inbuf  = (void __user *) (ibuf);		\
54219820Sjeff		(udata)->outbuf = (void __user *) (obuf);		\
55219820Sjeff		(udata)->inlen  = (ilen);				\
56219820Sjeff		(udata)->outlen = (olen);				\
57219820Sjeff	} while (0)
58219820Sjeff
59219820Sjeff/*
60219820Sjeff * The ib_uobject locking scheme is as follows:
61219820Sjeff *
62219820Sjeff * - ib_uverbs_idr_lock protects the uverbs idrs themselves, so it
63219820Sjeff *   needs to be held during all idr operations.  When an object is
64219820Sjeff *   looked up, a reference must be taken on the object's kref before
65219820Sjeff *   dropping this lock.
66219820Sjeff *
67219820Sjeff * - Each object also has an rwsem.  This rwsem must be held for
68219820Sjeff *   reading while an operation that uses the object is performed.
69219820Sjeff *   For example, while registering an MR, the associated PD's
70219820Sjeff *   uobject.mutex must be held for reading.  The rwsem must be held
71219820Sjeff *   for writing while initializing or destroying an object.
72219820Sjeff *
73219820Sjeff * - In addition, each object has a "live" flag.  If this flag is not
74219820Sjeff *   set, then lookups of the object will fail even if it is found in
75219820Sjeff *   the idr.  This handles a reader that blocks and does not acquire
76219820Sjeff *   the rwsem until after the object is destroyed.  The destroy
77219820Sjeff *   operation will set the live flag to 0 and then drop the rwsem;
78219820Sjeff *   this will allow the reader to acquire the rwsem, see that the
79219820Sjeff *   live flag is 0, and then drop the rwsem and its reference to
80219820Sjeff *   object.  The underlying storage will not be freed until the last
81219820Sjeff *   reference to the object is dropped.
82219820Sjeff */
83219820Sjeff
84219820Sjeffstatic void init_uobj(struct ib_uobject *uobj, u64 user_handle,
85219820Sjeff		      struct ib_ucontext *context, struct lock_class_key *key)
86219820Sjeff{
87219820Sjeff	uobj->user_handle = user_handle;
88219820Sjeff	uobj->context     = context;
89219820Sjeff	kref_init(&uobj->ref);
90219820Sjeff	init_rwsem(&uobj->mutex);
91219820Sjeff	lockdep_set_class(&uobj->mutex, key);
92219820Sjeff	uobj->live        = 0;
93219820Sjeff}
94219820Sjeff
95219820Sjeffstatic void release_uobj(struct kref *kref)
96219820Sjeff{
97219820Sjeff	kfree(container_of(kref, struct ib_uobject, ref));
98219820Sjeff}
99219820Sjeff
100219820Sjeffstatic void put_uobj(struct ib_uobject *uobj)
101219820Sjeff{
102219820Sjeff	kref_put(&uobj->ref, release_uobj);
103219820Sjeff}
104219820Sjeff
105219820Sjeffstatic void put_uobj_read(struct ib_uobject *uobj)
106219820Sjeff{
107219820Sjeff	up_read(&uobj->mutex);
108219820Sjeff	put_uobj(uobj);
109219820Sjeff}
110219820Sjeff
111219820Sjeffstatic void put_uobj_write(struct ib_uobject *uobj)
112219820Sjeff{
113219820Sjeff	up_write(&uobj->mutex);
114219820Sjeff	put_uobj(uobj);
115219820Sjeff}
116219820Sjeff
117219820Sjeffstatic int idr_add_uobj(struct idr *idr, struct ib_uobject *uobj)
118219820Sjeff{
119219820Sjeff	int ret;
120219820Sjeff
121219820Sjeffretry:
122219820Sjeff	if (!idr_pre_get(idr, GFP_KERNEL))
123219820Sjeff		return -ENOMEM;
124219820Sjeff
125219820Sjeff	spin_lock(&ib_uverbs_idr_lock);
126219820Sjeff	ret = idr_get_new(idr, uobj, &uobj->id);
127219820Sjeff	spin_unlock(&ib_uverbs_idr_lock);
128219820Sjeff
129219820Sjeff	if (ret == -EAGAIN)
130219820Sjeff		goto retry;
131219820Sjeff
132219820Sjeff	return ret;
133219820Sjeff}
134219820Sjeff
135219820Sjeffvoid idr_remove_uobj(struct idr *idr, struct ib_uobject *uobj)
136219820Sjeff{
137219820Sjeff	spin_lock(&ib_uverbs_idr_lock);
138219820Sjeff	idr_remove(idr, uobj->id);
139219820Sjeff	spin_unlock(&ib_uverbs_idr_lock);
140219820Sjeff}
141219820Sjeff
142219820Sjeffstatic struct ib_uobject *__idr_get_uobj(struct idr *idr, int id,
143219820Sjeff					 struct ib_ucontext *context)
144219820Sjeff{
145219820Sjeff	struct ib_uobject *uobj;
146219820Sjeff
147219820Sjeff	spin_lock(&ib_uverbs_idr_lock);
148219820Sjeff	uobj = idr_find(idr, id);
149219820Sjeff	if (uobj) {
150219820Sjeff		if (uobj->context == context)
151219820Sjeff			kref_get(&uobj->ref);
152219820Sjeff		else
153219820Sjeff			uobj = NULL;
154219820Sjeff	}
155219820Sjeff	spin_unlock(&ib_uverbs_idr_lock);
156219820Sjeff
157219820Sjeff	return uobj;
158219820Sjeff}
159219820Sjeff
160219820Sjeffstatic struct ib_uobject *idr_read_uobj(struct idr *idr, int id,
161219820Sjeff					struct ib_ucontext *context, int nested)
162219820Sjeff{
163219820Sjeff	struct ib_uobject *uobj;
164219820Sjeff
165219820Sjeff	uobj = __idr_get_uobj(idr, id, context);
166219820Sjeff	if (!uobj)
167219820Sjeff		return NULL;
168219820Sjeff
169219820Sjeff	if (nested)
170219820Sjeff		down_read_nested(&uobj->mutex, SINGLE_DEPTH_NESTING);
171219820Sjeff	else
172219820Sjeff		down_read(&uobj->mutex);
173219820Sjeff	if (!uobj->live) {
174219820Sjeff		put_uobj_read(uobj);
175219820Sjeff		return NULL;
176219820Sjeff	}
177219820Sjeff
178219820Sjeff	return uobj;
179219820Sjeff}
180219820Sjeff
181219820Sjeffstatic struct ib_uobject *idr_write_uobj(struct idr *idr, int id,
182219820Sjeff					 struct ib_ucontext *context)
183219820Sjeff{
184219820Sjeff	struct ib_uobject *uobj;
185219820Sjeff
186219820Sjeff	uobj = __idr_get_uobj(idr, id, context);
187219820Sjeff	if (!uobj)
188219820Sjeff		return NULL;
189219820Sjeff
190219820Sjeff	down_write(&uobj->mutex);
191219820Sjeff	if (!uobj->live) {
192219820Sjeff		put_uobj_write(uobj);
193219820Sjeff		return NULL;
194219820Sjeff	}
195219820Sjeff
196219820Sjeff	return uobj;
197219820Sjeff}
198219820Sjeff
199219820Sjeffstatic void *idr_read_obj(struct idr *idr, int id, struct ib_ucontext *context,
200219820Sjeff			  int nested)
201219820Sjeff{
202219820Sjeff	struct ib_uobject *uobj;
203219820Sjeff
204219820Sjeff	uobj = idr_read_uobj(idr, id, context, nested);
205219820Sjeff	return uobj ? uobj->object : NULL;
206219820Sjeff}
207219820Sjeff
208219820Sjeffstatic struct ib_pd *idr_read_pd(int pd_handle, struct ib_ucontext *context)
209219820Sjeff{
210219820Sjeff	return idr_read_obj(&ib_uverbs_pd_idr, pd_handle, context, 0);
211219820Sjeff}
212219820Sjeff
213219820Sjeffstatic void put_pd_read(struct ib_pd *pd)
214219820Sjeff{
215219820Sjeff	put_uobj_read(pd->uobject);
216219820Sjeff}
217219820Sjeff
218219820Sjeffstatic struct ib_cq *idr_read_cq(int cq_handle, struct ib_ucontext *context, int nested)
219219820Sjeff{
220219820Sjeff	return idr_read_obj(&ib_uverbs_cq_idr, cq_handle, context, nested);
221219820Sjeff}
222219820Sjeff
223219820Sjeffstatic void put_cq_read(struct ib_cq *cq)
224219820Sjeff{
225219820Sjeff	put_uobj_read(cq->uobject);
226219820Sjeff}
227219820Sjeff
228219820Sjeffstatic struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context)
229219820Sjeff{
230219820Sjeff	return idr_read_obj(&ib_uverbs_ah_idr, ah_handle, context, 0);
231219820Sjeff}
232219820Sjeff
233219820Sjeffstatic void put_ah_read(struct ib_ah *ah)
234219820Sjeff{
235219820Sjeff	put_uobj_read(ah->uobject);
236219820Sjeff}
237219820Sjeff
238219820Sjeffstatic struct ib_qp *idr_read_qp(int qp_handle, struct ib_ucontext *context)
239219820Sjeff{
240219820Sjeff	return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context, 0);
241219820Sjeff}
242219820Sjeff
243219820Sjeffstatic void put_qp_read(struct ib_qp *qp)
244219820Sjeff{
245219820Sjeff	put_uobj_read(qp->uobject);
246219820Sjeff}
247219820Sjeff
248219820Sjeffstatic struct ib_srq *idr_read_srq(int srq_handle, struct ib_ucontext *context)
249219820Sjeff{
250219820Sjeff	return idr_read_obj(&ib_uverbs_srq_idr, srq_handle, context, 0);
251219820Sjeff}
252219820Sjeff
253219820Sjeffstatic void put_srq_read(struct ib_srq *srq)
254219820Sjeff{
255219820Sjeff	put_uobj_read(srq->uobject);
256219820Sjeff}
257219820Sjeff
258219820Sjeffstatic struct ib_xrcd *idr_read_xrcd(int xrcd_handle,
259219820Sjeff				     struct ib_ucontext *context,
260219820Sjeff				     struct ib_uobject **uobj)
261219820Sjeff{
262219820Sjeff	*uobj = idr_read_uobj(&ib_uverbs_xrc_domain_idr, xrcd_handle,
263219820Sjeff			      context, 0);
264219820Sjeff	return *uobj ? (*uobj)->object : NULL;
265219820Sjeff}
266219820Sjeff
267219820Sjeffstatic void put_xrcd_read(struct ib_uobject *uobj)
268219820Sjeff{
269219820Sjeff	put_uobj_read(uobj);
270219820Sjeff}
271219820Sjeff
272219820Sjeffssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
273219820Sjeff			      const char __user *buf,
274219820Sjeff			      int in_len, int out_len)
275219820Sjeff{
276219820Sjeff	struct ib_uverbs_get_context      cmd;
277219820Sjeff	struct ib_uverbs_get_context_resp resp;
278219820Sjeff	struct ib_udata                   udata;
279219820Sjeff	struct ib_device                 *ibdev = file->device->ib_dev;
280219820Sjeff	struct ib_ucontext		 *ucontext;
281219820Sjeff	struct file			 *filp;
282219820Sjeff	int ret;
283219820Sjeff
284219820Sjeff	if (out_len < sizeof resp)
285219820Sjeff		return -ENOSPC;
286219820Sjeff
287219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
288219820Sjeff		return -EFAULT;
289219820Sjeff
290219820Sjeff	mutex_lock(&file->mutex);
291219820Sjeff
292219820Sjeff	if (file->ucontext) {
293219820Sjeff		ret = -EINVAL;
294219820Sjeff		goto err;
295219820Sjeff	}
296219820Sjeff
297219820Sjeff	INIT_UDATA(&udata, buf + sizeof cmd,
298219820Sjeff		   (unsigned long) cmd.response + sizeof resp,
299219820Sjeff		   in_len - sizeof cmd, out_len - sizeof resp);
300219820Sjeff
301219820Sjeff	ucontext = ibdev->alloc_ucontext(ibdev, &udata);
302219820Sjeff	if (IS_ERR(ucontext)) {
303219820Sjeff		ret = PTR_ERR(file->ucontext);
304219820Sjeff		goto err;
305219820Sjeff	}
306219820Sjeff
307219820Sjeff	ucontext->device = ibdev;
308219820Sjeff	INIT_LIST_HEAD(&ucontext->pd_list);
309219820Sjeff	INIT_LIST_HEAD(&ucontext->mr_list);
310219820Sjeff	INIT_LIST_HEAD(&ucontext->mw_list);
311219820Sjeff	INIT_LIST_HEAD(&ucontext->cq_list);
312219820Sjeff	INIT_LIST_HEAD(&ucontext->qp_list);
313219820Sjeff	INIT_LIST_HEAD(&ucontext->srq_list);
314219820Sjeff	INIT_LIST_HEAD(&ucontext->ah_list);
315255932Salfred	INIT_LIST_HEAD(&ucontext->xrcd_list);
316219820Sjeff	ucontext->closing = 0;
317219820Sjeff
318219820Sjeff	resp.num_comp_vectors = file->device->num_comp_vectors;
319219820Sjeff
320219820Sjeff	filp = ib_uverbs_alloc_event_file(file, 1, &resp.async_fd);
321219820Sjeff	if (IS_ERR(filp)) {
322219820Sjeff		ret = PTR_ERR(filp);
323219820Sjeff		goto err_free;
324219820Sjeff	}
325219820Sjeff
326219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
327219820Sjeff			 &resp, sizeof resp)) {
328219820Sjeff		ret = -EFAULT;
329219820Sjeff		goto err_file;
330219820Sjeff	}
331219820Sjeff
332219820Sjeff	file->async_file = filp->private_data;
333219820Sjeff
334219820Sjeff	INIT_IB_EVENT_HANDLER(&file->event_handler, file->device->ib_dev,
335219820Sjeff			      ib_uverbs_event_handler);
336219820Sjeff	ret = ib_register_event_handler(&file->event_handler);
337219820Sjeff	if (ret)
338219820Sjeff		goto err_file;
339219820Sjeff
340219820Sjeff	kref_get(&file->async_file->ref);
341219820Sjeff	kref_get(&file->ref);
342219820Sjeff	file->ucontext = ucontext;
343219820Sjeff
344219820Sjeff	fd_install(resp.async_fd, filp);
345219820Sjeff
346219820Sjeff	mutex_unlock(&file->mutex);
347219820Sjeff
348219820Sjeff	return in_len;
349219820Sjeff
350219820Sjefferr_file:
351219820Sjeff	put_unused_fd(resp.async_fd);
352219820Sjeff	fput(filp);
353219820Sjeff
354219820Sjefferr_free:
355219820Sjeff	ibdev->dealloc_ucontext(ucontext);
356219820Sjeff
357219820Sjefferr:
358219820Sjeff	mutex_unlock(&file->mutex);
359219820Sjeff	return ret;
360219820Sjeff}
361219820Sjeff
362219820Sjeffssize_t ib_uverbs_query_device(struct ib_uverbs_file *file,
363219820Sjeff			       const char __user *buf,
364219820Sjeff			       int in_len, int out_len)
365219820Sjeff{
366219820Sjeff	struct ib_uverbs_query_device      cmd;
367219820Sjeff	struct ib_uverbs_query_device_resp resp;
368219820Sjeff	struct ib_device_attr              attr;
369219820Sjeff	int                                ret;
370219820Sjeff
371219820Sjeff	if (out_len < sizeof resp)
372219820Sjeff		return -ENOSPC;
373219820Sjeff
374219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
375219820Sjeff		return -EFAULT;
376219820Sjeff
377219820Sjeff	ret = ib_query_device(file->device->ib_dev, &attr);
378219820Sjeff	if (ret)
379219820Sjeff		return ret;
380219820Sjeff
381219820Sjeff	memset(&resp, 0, sizeof resp);
382219820Sjeff
383219820Sjeff	resp.fw_ver 		       = attr.fw_ver;
384219820Sjeff	resp.node_guid 		       = file->device->ib_dev->node_guid;
385219820Sjeff	resp.sys_image_guid 	       = attr.sys_image_guid;
386219820Sjeff	resp.max_mr_size 	       = attr.max_mr_size;
387219820Sjeff	resp.page_size_cap 	       = attr.page_size_cap;
388219820Sjeff	resp.vendor_id 		       = attr.vendor_id;
389219820Sjeff	resp.vendor_part_id 	       = attr.vendor_part_id;
390219820Sjeff	resp.hw_ver 		       = attr.hw_ver;
391219820Sjeff	resp.max_qp 		       = attr.max_qp;
392219820Sjeff	resp.max_qp_wr 		       = attr.max_qp_wr;
393219820Sjeff	resp.device_cap_flags 	       = attr.device_cap_flags;
394219820Sjeff	resp.max_sge 		       = attr.max_sge;
395219820Sjeff	resp.max_sge_rd 	       = attr.max_sge_rd;
396219820Sjeff	resp.max_cq 		       = attr.max_cq;
397219820Sjeff	resp.max_cqe 		       = attr.max_cqe;
398219820Sjeff	resp.max_mr 		       = attr.max_mr;
399219820Sjeff	resp.max_pd 		       = attr.max_pd;
400219820Sjeff	resp.max_qp_rd_atom 	       = attr.max_qp_rd_atom;
401219820Sjeff	resp.max_ee_rd_atom 	       = attr.max_ee_rd_atom;
402219820Sjeff	resp.max_res_rd_atom 	       = attr.max_res_rd_atom;
403219820Sjeff	resp.max_qp_init_rd_atom       = attr.max_qp_init_rd_atom;
404219820Sjeff	resp.max_ee_init_rd_atom       = attr.max_ee_init_rd_atom;
405219820Sjeff	resp.atomic_cap 	       = attr.atomic_cap;
406219820Sjeff	resp.max_ee 		       = attr.max_ee;
407219820Sjeff	resp.max_rdd 		       = attr.max_rdd;
408219820Sjeff	resp.max_mw 		       = attr.max_mw;
409219820Sjeff	resp.max_raw_ipv6_qp 	       = attr.max_raw_ipv6_qp;
410219820Sjeff	resp.max_raw_ethy_qp 	       = attr.max_raw_ethy_qp;
411219820Sjeff	resp.max_mcast_grp 	       = attr.max_mcast_grp;
412219820Sjeff	resp.max_mcast_qp_attach       = attr.max_mcast_qp_attach;
413219820Sjeff	resp.max_total_mcast_qp_attach = attr.max_total_mcast_qp_attach;
414219820Sjeff	resp.max_ah 		       = attr.max_ah;
415219820Sjeff	resp.max_fmr 		       = attr.max_fmr;
416219820Sjeff	resp.max_map_per_fmr 	       = attr.max_map_per_fmr;
417219820Sjeff	resp.max_srq 		       = attr.max_srq;
418219820Sjeff	resp.max_srq_wr 	       = attr.max_srq_wr;
419219820Sjeff	resp.max_srq_sge 	       = attr.max_srq_sge;
420219820Sjeff	resp.max_pkeys 		       = attr.max_pkeys;
421219820Sjeff	resp.local_ca_ack_delay        = attr.local_ca_ack_delay;
422219820Sjeff	resp.phys_port_cnt	       = file->device->ib_dev->phys_port_cnt;
423219820Sjeff
424219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
425219820Sjeff			 &resp, sizeof resp))
426219820Sjeff		return -EFAULT;
427219820Sjeff
428219820Sjeff	return in_len;
429219820Sjeff}
430219820Sjeff
431219820Sjeffssize_t ib_uverbs_query_port(struct ib_uverbs_file *file,
432219820Sjeff			     const char __user *buf,
433219820Sjeff			     int in_len, int out_len)
434219820Sjeff{
435219820Sjeff	struct ib_uverbs_query_port      cmd;
436219820Sjeff	struct ib_uverbs_query_port_resp resp;
437219820Sjeff	struct ib_port_attr              attr;
438219820Sjeff	int                              ret;
439219820Sjeff
440219820Sjeff	if (out_len < sizeof resp)
441219820Sjeff		return -ENOSPC;
442219820Sjeff
443219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
444219820Sjeff		return -EFAULT;
445219820Sjeff
446219820Sjeff	ret = ib_query_port(file->device->ib_dev, cmd.port_num, &attr);
447219820Sjeff	if (ret)
448219820Sjeff		return ret;
449219820Sjeff
450219820Sjeff	memset(&resp, 0, sizeof resp);
451219820Sjeff
452219820Sjeff	resp.state 	     = attr.state;
453219820Sjeff	resp.max_mtu 	     = attr.max_mtu;
454219820Sjeff	resp.active_mtu      = attr.active_mtu;
455219820Sjeff	resp.gid_tbl_len     = attr.gid_tbl_len;
456219820Sjeff	resp.port_cap_flags  = attr.port_cap_flags;
457219820Sjeff	resp.max_msg_sz      = attr.max_msg_sz;
458219820Sjeff	resp.bad_pkey_cntr   = attr.bad_pkey_cntr;
459219820Sjeff	resp.qkey_viol_cntr  = attr.qkey_viol_cntr;
460219820Sjeff	resp.pkey_tbl_len    = attr.pkey_tbl_len;
461219820Sjeff	resp.lid 	     = attr.lid;
462219820Sjeff	resp.sm_lid 	     = attr.sm_lid;
463219820Sjeff	resp.lmc 	     = attr.lmc;
464219820Sjeff	resp.max_vl_num      = attr.max_vl_num;
465219820Sjeff	resp.sm_sl 	     = attr.sm_sl;
466219820Sjeff	resp.subnet_timeout  = attr.subnet_timeout;
467219820Sjeff	resp.init_type_reply = attr.init_type_reply;
468219820Sjeff	resp.active_width    = attr.active_width;
469219820Sjeff	resp.active_speed    = attr.active_speed;
470219820Sjeff	resp.phys_state      = attr.phys_state;
471219820Sjeff	resp.link_layer	     = attr.link_layer;
472219820Sjeff
473219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
474219820Sjeff			 &resp, sizeof resp))
475219820Sjeff		return -EFAULT;
476219820Sjeff
477219820Sjeff	return in_len;
478219820Sjeff}
479219820Sjeff
480219820Sjeffssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
481219820Sjeff			   const char __user *buf,
482219820Sjeff			   int in_len, int out_len)
483219820Sjeff{
484219820Sjeff	struct ib_uverbs_alloc_pd      cmd;
485219820Sjeff	struct ib_uverbs_alloc_pd_resp resp;
486219820Sjeff	struct ib_udata                udata;
487219820Sjeff	struct ib_uobject             *uobj;
488219820Sjeff	struct ib_pd                  *pd;
489219820Sjeff	int                            ret;
490219820Sjeff
491219820Sjeff	if (out_len < sizeof resp)
492219820Sjeff		return -ENOSPC;
493219820Sjeff
494219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
495219820Sjeff		return -EFAULT;
496219820Sjeff
497219820Sjeff	INIT_UDATA(&udata, buf + sizeof cmd,
498219820Sjeff		   (unsigned long) cmd.response + sizeof resp,
499219820Sjeff		   in_len - sizeof cmd, out_len - sizeof resp);
500219820Sjeff
501219820Sjeff	uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
502219820Sjeff	if (!uobj)
503219820Sjeff		return -ENOMEM;
504219820Sjeff
505219820Sjeff	init_uobj(uobj, 0, file->ucontext, &pd_lock_key);
506219820Sjeff	down_write(&uobj->mutex);
507219820Sjeff
508219820Sjeff	pd = file->device->ib_dev->alloc_pd(file->device->ib_dev,
509219820Sjeff					    file->ucontext, &udata);
510219820Sjeff	if (IS_ERR(pd)) {
511219820Sjeff		ret = PTR_ERR(pd);
512219820Sjeff		goto err;
513219820Sjeff	}
514219820Sjeff
515219820Sjeff	pd->device  = file->device->ib_dev;
516219820Sjeff	pd->uobject = uobj;
517219820Sjeff	atomic_set(&pd->usecnt, 0);
518219820Sjeff
519219820Sjeff	uobj->object = pd;
520219820Sjeff	ret = idr_add_uobj(&ib_uverbs_pd_idr, uobj);
521219820Sjeff	if (ret)
522219820Sjeff		goto err_idr;
523219820Sjeff
524219820Sjeff	memset(&resp, 0, sizeof resp);
525219820Sjeff	resp.pd_handle = uobj->id;
526219820Sjeff
527219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
528219820Sjeff			 &resp, sizeof resp)) {
529219820Sjeff		ret = -EFAULT;
530219820Sjeff		goto err_copy;
531219820Sjeff	}
532219820Sjeff
533219820Sjeff	mutex_lock(&file->mutex);
534219820Sjeff	list_add_tail(&uobj->list, &file->ucontext->pd_list);
535219820Sjeff	mutex_unlock(&file->mutex);
536219820Sjeff
537219820Sjeff	uobj->live = 1;
538219820Sjeff
539219820Sjeff	up_write(&uobj->mutex);
540219820Sjeff
541219820Sjeff	return in_len;
542219820Sjeff
543219820Sjefferr_copy:
544219820Sjeff	idr_remove_uobj(&ib_uverbs_pd_idr, uobj);
545219820Sjeff
546219820Sjefferr_idr:
547219820Sjeff	ib_dealloc_pd(pd);
548219820Sjeff
549219820Sjefferr:
550219820Sjeff	put_uobj_write(uobj);
551219820Sjeff	return ret;
552219820Sjeff}
553219820Sjeff
554219820Sjeffssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
555219820Sjeff			     const char __user *buf,
556219820Sjeff			     int in_len, int out_len)
557219820Sjeff{
558219820Sjeff	struct ib_uverbs_dealloc_pd cmd;
559219820Sjeff	struct ib_uobject          *uobj;
560219820Sjeff	int                         ret;
561219820Sjeff
562219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
563219820Sjeff		return -EFAULT;
564219820Sjeff
565219820Sjeff	uobj = idr_write_uobj(&ib_uverbs_pd_idr, cmd.pd_handle, file->ucontext);
566219820Sjeff	if (!uobj)
567219820Sjeff		return -EINVAL;
568219820Sjeff
569219820Sjeff	ret = ib_dealloc_pd(uobj->object);
570219820Sjeff	if (!ret)
571219820Sjeff		uobj->live = 0;
572219820Sjeff
573219820Sjeff	put_uobj_write(uobj);
574219820Sjeff
575219820Sjeff	if (ret)
576219820Sjeff		return ret;
577219820Sjeff
578219820Sjeff	idr_remove_uobj(&ib_uverbs_pd_idr, uobj);
579219820Sjeff
580219820Sjeff	mutex_lock(&file->mutex);
581219820Sjeff	list_del(&uobj->list);
582219820Sjeff	mutex_unlock(&file->mutex);
583219820Sjeff
584219820Sjeff	put_uobj(uobj);
585219820Sjeff
586219820Sjeff	return in_len;
587219820Sjeff}
588219820Sjeff
589219820Sjeffssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
590219820Sjeff			 const char __user *buf, int in_len,
591219820Sjeff			 int out_len)
592219820Sjeff{
593219820Sjeff	struct ib_uverbs_reg_mr      cmd;
594219820Sjeff	struct ib_uverbs_reg_mr_resp resp;
595219820Sjeff	struct ib_udata              udata;
596219820Sjeff	struct ib_uobject           *uobj;
597219820Sjeff	struct ib_pd                *pd;
598219820Sjeff	struct ib_mr                *mr;
599219820Sjeff	int                          ret;
600219820Sjeff
601219820Sjeff	if (out_len < sizeof resp)
602219820Sjeff		return -ENOSPC;
603219820Sjeff
604219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
605219820Sjeff		return -EFAULT;
606219820Sjeff
607219820Sjeff	INIT_UDATA(&udata, buf + sizeof cmd,
608219820Sjeff		   (unsigned long) cmd.response + sizeof resp,
609219820Sjeff		   in_len - sizeof cmd, out_len - sizeof resp);
610219820Sjeff
611219820Sjeff	if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK))
612219820Sjeff		return -EINVAL;
613219820Sjeff
614219820Sjeff	/*
615219820Sjeff	 * Local write permission is required if remote write or
616219820Sjeff	 * remote atomic permission is also requested.
617219820Sjeff	 */
618219820Sjeff	if (cmd.access_flags & (IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_REMOTE_WRITE) &&
619219820Sjeff	    !(cmd.access_flags & IB_ACCESS_LOCAL_WRITE))
620219820Sjeff		return -EINVAL;
621219820Sjeff
622219820Sjeff	uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
623219820Sjeff	if (!uobj)
624219820Sjeff		return -ENOMEM;
625219820Sjeff
626219820Sjeff	init_uobj(uobj, 0, file->ucontext, &mr_lock_key);
627219820Sjeff	down_write(&uobj->mutex);
628219820Sjeff
629219820Sjeff	pd = idr_read_pd(cmd.pd_handle, file->ucontext);
630219820Sjeff	if (!pd) {
631219820Sjeff		ret = -EINVAL;
632219820Sjeff		goto err_free;
633219820Sjeff	}
634219820Sjeff
635219820Sjeff	mr = pd->device->reg_user_mr(pd, cmd.start, cmd.length, cmd.hca_va,
636255932Salfred				     cmd.access_flags, &udata, 0);
637219820Sjeff	if (IS_ERR(mr)) {
638219820Sjeff		ret = PTR_ERR(mr);
639219820Sjeff		goto err_put;
640219820Sjeff	}
641219820Sjeff
642219820Sjeff	mr->device  = pd->device;
643219820Sjeff	mr->pd      = pd;
644219820Sjeff	mr->uobject = uobj;
645219820Sjeff	atomic_inc(&pd->usecnt);
646219820Sjeff	atomic_set(&mr->usecnt, 0);
647219820Sjeff
648219820Sjeff	uobj->object = mr;
649219820Sjeff	ret = idr_add_uobj(&ib_uverbs_mr_idr, uobj);
650219820Sjeff	if (ret)
651219820Sjeff		goto err_unreg;
652219820Sjeff
653219820Sjeff	memset(&resp, 0, sizeof resp);
654219820Sjeff	resp.lkey      = mr->lkey;
655219820Sjeff	resp.rkey      = mr->rkey;
656219820Sjeff	resp.mr_handle = uobj->id;
657219820Sjeff
658219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
659219820Sjeff			 &resp, sizeof resp)) {
660219820Sjeff		ret = -EFAULT;
661219820Sjeff		goto err_copy;
662219820Sjeff	}
663219820Sjeff
664219820Sjeff	put_pd_read(pd);
665219820Sjeff
666219820Sjeff	mutex_lock(&file->mutex);
667219820Sjeff	list_add_tail(&uobj->list, &file->ucontext->mr_list);
668219820Sjeff	mutex_unlock(&file->mutex);
669219820Sjeff
670219820Sjeff	uobj->live = 1;
671219820Sjeff
672219820Sjeff	up_write(&uobj->mutex);
673219820Sjeff
674219820Sjeff	return in_len;
675219820Sjeff
676219820Sjefferr_copy:
677219820Sjeff	idr_remove_uobj(&ib_uverbs_mr_idr, uobj);
678219820Sjeff
679219820Sjefferr_unreg:
680219820Sjeff	ib_dereg_mr(mr);
681219820Sjeff
682219820Sjefferr_put:
683219820Sjeff	put_pd_read(pd);
684219820Sjeff
685219820Sjefferr_free:
686219820Sjeff	put_uobj_write(uobj);
687219820Sjeff	return ret;
688219820Sjeff}
689219820Sjeff
690219820Sjeffssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
691219820Sjeff			   const char __user *buf, int in_len,
692219820Sjeff			   int out_len)
693219820Sjeff{
694219820Sjeff	struct ib_uverbs_dereg_mr cmd;
695219820Sjeff	struct ib_mr             *mr;
696219820Sjeff	struct ib_uobject	 *uobj;
697219820Sjeff	int                       ret = -EINVAL;
698219820Sjeff
699219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
700219820Sjeff		return -EFAULT;
701219820Sjeff
702219820Sjeff	uobj = idr_write_uobj(&ib_uverbs_mr_idr, cmd.mr_handle, file->ucontext);
703219820Sjeff	if (!uobj)
704219820Sjeff		return -EINVAL;
705219820Sjeff
706219820Sjeff	mr = uobj->object;
707219820Sjeff
708219820Sjeff	ret = ib_dereg_mr(mr);
709219820Sjeff	if (!ret)
710219820Sjeff		uobj->live = 0;
711219820Sjeff
712219820Sjeff	put_uobj_write(uobj);
713219820Sjeff
714219820Sjeff	if (ret)
715219820Sjeff		return ret;
716219820Sjeff
717219820Sjeff	idr_remove_uobj(&ib_uverbs_mr_idr, uobj);
718219820Sjeff
719219820Sjeff	mutex_lock(&file->mutex);
720219820Sjeff	list_del(&uobj->list);
721219820Sjeff	mutex_unlock(&file->mutex);
722219820Sjeff
723219820Sjeff	put_uobj(uobj);
724219820Sjeff
725219820Sjeff	return in_len;
726219820Sjeff}
727219820Sjeff
728219820Sjeffssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file,
729219820Sjeff				      const char __user *buf, int in_len,
730219820Sjeff				      int out_len)
731219820Sjeff{
732219820Sjeff	struct ib_uverbs_create_comp_channel	   cmd;
733219820Sjeff	struct ib_uverbs_create_comp_channel_resp  resp;
734219820Sjeff	struct file				  *filp;
735219820Sjeff
736219820Sjeff	if (out_len < sizeof resp)
737219820Sjeff		return -ENOSPC;
738219820Sjeff
739219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
740219820Sjeff		return -EFAULT;
741219820Sjeff
742219820Sjeff	filp = ib_uverbs_alloc_event_file(file, 0, &resp.fd);
743219820Sjeff	if (IS_ERR(filp))
744219820Sjeff		return PTR_ERR(filp);
745219820Sjeff
746219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
747219820Sjeff			 &resp, sizeof resp)) {
748219820Sjeff		put_unused_fd(resp.fd);
749219820Sjeff		fput(filp);
750219820Sjeff		return -EFAULT;
751219820Sjeff	}
752219820Sjeff
753219820Sjeff	fd_install(resp.fd, filp);
754219820Sjeff	return in_len;
755219820Sjeff}
756219820Sjeff
757219820Sjeffssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
758219820Sjeff			    const char __user *buf, int in_len,
759219820Sjeff			    int out_len)
760219820Sjeff{
761219820Sjeff	struct ib_uverbs_create_cq      cmd;
762219820Sjeff	struct ib_uverbs_create_cq_resp resp;
763219820Sjeff	struct ib_udata                 udata;
764219820Sjeff	struct ib_ucq_object           *obj;
765219820Sjeff	struct ib_uverbs_event_file    *ev_file = NULL;
766219820Sjeff	struct ib_cq                   *cq;
767219820Sjeff	int                             ret;
768219820Sjeff
769219820Sjeff	if (out_len < sizeof resp)
770219820Sjeff		return -ENOSPC;
771219820Sjeff
772219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
773219820Sjeff		return -EFAULT;
774219820Sjeff
775219820Sjeff	INIT_UDATA(&udata, buf + sizeof cmd,
776219820Sjeff		   (unsigned long) cmd.response + sizeof resp,
777219820Sjeff		   in_len - sizeof cmd, out_len - sizeof resp);
778219820Sjeff
779219820Sjeff	if (cmd.comp_vector >= file->device->num_comp_vectors)
780219820Sjeff		return -EINVAL;
781219820Sjeff
782219820Sjeff	obj = kmalloc(sizeof *obj, GFP_KERNEL);
783219820Sjeff	if (!obj)
784219820Sjeff		return -ENOMEM;
785219820Sjeff
786219820Sjeff	init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, &cq_lock_key);
787219820Sjeff	down_write(&obj->uobject.mutex);
788219820Sjeff
789219820Sjeff	if (cmd.comp_channel >= 0) {
790219820Sjeff		ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel);
791219820Sjeff		if (!ev_file) {
792219820Sjeff			ret = -EINVAL;
793219820Sjeff			goto err;
794219820Sjeff		}
795219820Sjeff	}
796219820Sjeff
797219820Sjeff	obj->uverbs_file	   = file;
798219820Sjeff	obj->comp_events_reported  = 0;
799219820Sjeff	obj->async_events_reported = 0;
800219820Sjeff	INIT_LIST_HEAD(&obj->comp_list);
801219820Sjeff	INIT_LIST_HEAD(&obj->async_list);
802219820Sjeff
803219820Sjeff	cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe,
804219820Sjeff					     cmd.comp_vector,
805219820Sjeff					     file->ucontext, &udata);
806219820Sjeff	if (IS_ERR(cq)) {
807219820Sjeff		ret = PTR_ERR(cq);
808219820Sjeff		goto err_file;
809219820Sjeff	}
810219820Sjeff
811219820Sjeff	cq->device        = file->device->ib_dev;
812219820Sjeff	cq->uobject       = &obj->uobject;
813219820Sjeff	cq->comp_handler  = ib_uverbs_comp_handler;
814219820Sjeff	cq->event_handler = ib_uverbs_cq_event_handler;
815219820Sjeff	cq->cq_context    = ev_file;
816219820Sjeff	atomic_set(&cq->usecnt, 0);
817219820Sjeff
818219820Sjeff	obj->uobject.object = cq;
819219820Sjeff	ret = idr_add_uobj(&ib_uverbs_cq_idr, &obj->uobject);
820219820Sjeff	if (ret)
821219820Sjeff		goto err_free;
822219820Sjeff
823219820Sjeff	memset(&resp, 0, sizeof resp);
824219820Sjeff	resp.cq_handle = obj->uobject.id;
825219820Sjeff	resp.cqe       = cq->cqe;
826219820Sjeff
827219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
828219820Sjeff			 &resp, sizeof resp)) {
829219820Sjeff		ret = -EFAULT;
830219820Sjeff		goto err_copy;
831219820Sjeff	}
832219820Sjeff
833219820Sjeff	mutex_lock(&file->mutex);
834219820Sjeff	list_add_tail(&obj->uobject.list, &file->ucontext->cq_list);
835219820Sjeff	mutex_unlock(&file->mutex);
836219820Sjeff
837219820Sjeff	obj->uobject.live = 1;
838219820Sjeff
839219820Sjeff	up_write(&obj->uobject.mutex);
840219820Sjeff
841219820Sjeff	return in_len;
842219820Sjeff
843219820Sjefferr_copy:
844219820Sjeff	idr_remove_uobj(&ib_uverbs_cq_idr, &obj->uobject);
845219820Sjeff
846219820Sjefferr_free:
847219820Sjeff	ib_destroy_cq(cq);
848219820Sjeff
849219820Sjefferr_file:
850219820Sjeff	if (ev_file)
851219820Sjeff		ib_uverbs_release_ucq(file, ev_file, obj);
852219820Sjeff
853219820Sjefferr:
854219820Sjeff	put_uobj_write(&obj->uobject);
855219820Sjeff	return ret;
856219820Sjeff}
857219820Sjeff
858219820Sjeffssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
859219820Sjeff			    const char __user *buf, int in_len,
860219820Sjeff			    int out_len)
861219820Sjeff{
862219820Sjeff	struct ib_uverbs_resize_cq	cmd;
863219820Sjeff	struct ib_uverbs_resize_cq_resp	resp;
864219820Sjeff	struct ib_udata                 udata;
865219820Sjeff	struct ib_cq			*cq;
866219820Sjeff	int				ret = -EINVAL;
867219820Sjeff
868219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
869219820Sjeff		return -EFAULT;
870219820Sjeff
871219820Sjeff	INIT_UDATA(&udata, buf + sizeof cmd,
872219820Sjeff		   (unsigned long) cmd.response + sizeof resp,
873219820Sjeff		   in_len - sizeof cmd, out_len - sizeof resp);
874219820Sjeff
875219820Sjeff	cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
876219820Sjeff	if (!cq)
877219820Sjeff		return -EINVAL;
878219820Sjeff
879219820Sjeff	ret = cq->device->resize_cq(cq, cmd.cqe, &udata);
880219820Sjeff	if (ret)
881219820Sjeff		goto out;
882219820Sjeff
883219820Sjeff	resp.cqe = cq->cqe;
884219820Sjeff
885219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
886219820Sjeff			 &resp, sizeof resp.cqe))
887219820Sjeff		ret = -EFAULT;
888219820Sjeff
889219820Sjeffout:
890219820Sjeff	put_cq_read(cq);
891219820Sjeff
892219820Sjeff	return ret ? ret : in_len;
893219820Sjeff}
894219820Sjeff
895219820Sjeffssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
896219820Sjeff			  const char __user *buf, int in_len,
897219820Sjeff			  int out_len)
898219820Sjeff{
899219820Sjeff	struct ib_uverbs_poll_cq       cmd;
900219820Sjeff	struct ib_uverbs_poll_cq_resp *resp;
901219820Sjeff	struct ib_cq                  *cq;
902219820Sjeff	struct ib_wc                  *wc;
903219820Sjeff	int                            ret = 0;
904219820Sjeff	int                            i;
905219820Sjeff	int                            rsize;
906219820Sjeff
907219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
908219820Sjeff		return -EFAULT;
909219820Sjeff
910219820Sjeff	wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL);
911219820Sjeff	if (!wc)
912219820Sjeff		return -ENOMEM;
913219820Sjeff
914219820Sjeff	rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc);
915219820Sjeff	resp = kmalloc(rsize, GFP_KERNEL);
916219820Sjeff	if (!resp) {
917219820Sjeff		ret = -ENOMEM;
918219820Sjeff		goto out_wc;
919219820Sjeff	}
920219820Sjeff
921219820Sjeff	cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
922219820Sjeff	if (!cq) {
923219820Sjeff		ret = -EINVAL;
924219820Sjeff		goto out;
925219820Sjeff	}
926219820Sjeff
927219820Sjeff	resp->count = ib_poll_cq(cq, cmd.ne, wc);
928219820Sjeff
929219820Sjeff	put_cq_read(cq);
930219820Sjeff
931219820Sjeff	for (i = 0; i < resp->count; i++) {
932219820Sjeff		resp->wc[i].wr_id 	   = wc[i].wr_id;
933219820Sjeff		resp->wc[i].status 	   = wc[i].status;
934219820Sjeff		resp->wc[i].opcode 	   = wc[i].opcode;
935219820Sjeff		resp->wc[i].vendor_err 	   = wc[i].vendor_err;
936219820Sjeff		resp->wc[i].byte_len 	   = wc[i].byte_len;
937219820Sjeff		resp->wc[i].ex.imm_data    = (__u32 __force) wc[i].ex.imm_data;
938219820Sjeff		resp->wc[i].qp_num 	   = wc[i].qp->qp_num;
939219820Sjeff		resp->wc[i].src_qp 	   = wc[i].src_qp;
940219820Sjeff		resp->wc[i].wc_flags 	   = wc[i].wc_flags;
941219820Sjeff		resp->wc[i].pkey_index 	   = wc[i].pkey_index;
942219820Sjeff		resp->wc[i].slid 	   = wc[i].slid;
943219820Sjeff		resp->wc[i].sl 		   = wc[i].sl;
944219820Sjeff		resp->wc[i].dlid_path_bits = wc[i].dlid_path_bits;
945219820Sjeff		resp->wc[i].port_num 	   = wc[i].port_num;
946219820Sjeff	}
947219820Sjeff
948219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response, resp, rsize))
949219820Sjeff		ret = -EFAULT;
950219820Sjeff
951219820Sjeffout:
952219820Sjeff	kfree(resp);
953219820Sjeff
954219820Sjeffout_wc:
955219820Sjeff	kfree(wc);
956219820Sjeff	return ret ? ret : in_len;
957219820Sjeff}
958219820Sjeff
959219820Sjeffssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,
960219820Sjeff				const char __user *buf, int in_len,
961219820Sjeff				int out_len)
962219820Sjeff{
963219820Sjeff	struct ib_uverbs_req_notify_cq cmd;
964219820Sjeff	struct ib_cq                  *cq;
965219820Sjeff
966219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
967219820Sjeff		return -EFAULT;
968219820Sjeff
969219820Sjeff	cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
970219820Sjeff	if (!cq)
971219820Sjeff		return -EINVAL;
972219820Sjeff
973219820Sjeff	ib_req_notify_cq(cq, cmd.solicited_only ?
974219820Sjeff			 IB_CQ_SOLICITED : IB_CQ_NEXT_COMP);
975219820Sjeff
976219820Sjeff	put_cq_read(cq);
977219820Sjeff
978219820Sjeff	return in_len;
979219820Sjeff}
980219820Sjeff
981219820Sjeffssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
982219820Sjeff			     const char __user *buf, int in_len,
983219820Sjeff			     int out_len)
984219820Sjeff{
985219820Sjeff	struct ib_uverbs_destroy_cq      cmd;
986219820Sjeff	struct ib_uverbs_destroy_cq_resp resp;
987219820Sjeff	struct ib_uobject		*uobj;
988219820Sjeff	struct ib_cq               	*cq;
989219820Sjeff	struct ib_ucq_object        	*obj;
990219820Sjeff	struct ib_uverbs_event_file	*ev_file;
991219820Sjeff	int                        	 ret = -EINVAL;
992219820Sjeff
993219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
994219820Sjeff		return -EFAULT;
995219820Sjeff
996219820Sjeff	uobj = idr_write_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext);
997219820Sjeff	if (!uobj)
998219820Sjeff		return -EINVAL;
999219820Sjeff	cq      = uobj->object;
1000219820Sjeff	ev_file = cq->cq_context;
1001219820Sjeff	obj     = container_of(cq->uobject, struct ib_ucq_object, uobject);
1002219820Sjeff
1003219820Sjeff	ret = ib_destroy_cq(cq);
1004219820Sjeff	if (!ret)
1005219820Sjeff		uobj->live = 0;
1006219820Sjeff
1007219820Sjeff	put_uobj_write(uobj);
1008219820Sjeff
1009219820Sjeff	if (ret)
1010219820Sjeff		return ret;
1011219820Sjeff
1012219820Sjeff	idr_remove_uobj(&ib_uverbs_cq_idr, uobj);
1013219820Sjeff
1014219820Sjeff	mutex_lock(&file->mutex);
1015219820Sjeff	list_del(&uobj->list);
1016219820Sjeff	mutex_unlock(&file->mutex);
1017219820Sjeff
1018219820Sjeff	ib_uverbs_release_ucq(file, ev_file, obj);
1019219820Sjeff
1020219820Sjeff	memset(&resp, 0, sizeof resp);
1021219820Sjeff	resp.comp_events_reported  = obj->comp_events_reported;
1022219820Sjeff	resp.async_events_reported = obj->async_events_reported;
1023219820Sjeff
1024219820Sjeff	put_uobj(uobj);
1025219820Sjeff
1026219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
1027219820Sjeff			 &resp, sizeof resp))
1028219820Sjeff		return -EFAULT;
1029219820Sjeff
1030219820Sjeff	return in_len;
1031219820Sjeff}
1032219820Sjeff
1033219820Sjeffssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
1034219820Sjeff			    const char __user *buf, int in_len,
1035219820Sjeff			    int out_len)
1036219820Sjeff{
1037219820Sjeff	struct ib_uverbs_create_qp      cmd;
1038219820Sjeff	struct ib_uverbs_create_qp_resp resp;
1039219820Sjeff	struct ib_udata                 udata;
1040219820Sjeff	struct ib_uqp_object           *obj;
1041219820Sjeff	struct ib_pd                   *pd;
1042219820Sjeff	struct ib_cq                   *scq, *rcq;
1043219820Sjeff	struct ib_srq                  *srq;
1044219820Sjeff	struct ib_qp                   *qp;
1045219820Sjeff	struct ib_qp_init_attr          attr;
1046219820Sjeff	struct ib_xrcd		       *xrcd;
1047219820Sjeff	struct ib_uobject	       *xrcd_uobj;
1048219820Sjeff	int ret;
1049219820Sjeff
1050219820Sjeff	if (out_len < sizeof resp)
1051219820Sjeff		return -ENOSPC;
1052219820Sjeff
1053219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
1054219820Sjeff		return -EFAULT;
1055219820Sjeff
1056219820Sjeff	INIT_UDATA(&udata, buf + sizeof cmd,
1057219820Sjeff		   (unsigned long) cmd.response + sizeof resp,
1058219820Sjeff		   in_len - sizeof cmd, out_len - sizeof resp);
1059219820Sjeff
1060219820Sjeff	obj = kmalloc(sizeof *obj, GFP_KERNEL);
1061219820Sjeff	if (!obj)
1062219820Sjeff		return -ENOMEM;
1063219820Sjeff
1064219820Sjeff	init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext, &qp_lock_key);
1065219820Sjeff	down_write(&obj->uevent.uobject.mutex);
1066219820Sjeff
1067219820Sjeff	srq = (cmd.is_srq && cmd.qp_type != IB_QPT_XRC) ?
1068219820Sjeff		idr_read_srq(cmd.srq_handle, file->ucontext) : NULL;
1069219820Sjeff	xrcd = cmd.qp_type == IB_QPT_XRC ?
1070219820Sjeff		idr_read_xrcd(cmd.srq_handle, file->ucontext, &xrcd_uobj) : NULL;
1071219820Sjeff	pd  = idr_read_pd(cmd.pd_handle, file->ucontext);
1072219820Sjeff	scq = idr_read_cq(cmd.send_cq_handle, file->ucontext, 0);
1073219820Sjeff	rcq = cmd.recv_cq_handle == cmd.send_cq_handle ?
1074219820Sjeff		scq : idr_read_cq(cmd.recv_cq_handle, file->ucontext, 1);
1075219820Sjeff
1076219820Sjeff	if (!pd || !scq || !rcq || (cmd.is_srq && !srq) ||
1077219820Sjeff	    (cmd.qp_type == IB_QPT_XRC && !xrcd)) {
1078219820Sjeff		ret = -EINVAL;
1079219820Sjeff		goto err_put;
1080219820Sjeff	}
1081219820Sjeff
1082219820Sjeff	attr.create_flags  = 0;
1083219820Sjeff	attr.event_handler = ib_uverbs_qp_event_handler;
1084219820Sjeff	attr.qp_context    = file;
1085219820Sjeff	attr.send_cq       = scq;
1086219820Sjeff	attr.recv_cq       = rcq;
1087219820Sjeff	attr.srq           = srq;
1088219820Sjeff	attr.sq_sig_type   = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
1089219820Sjeff	attr.qp_type       = cmd.qp_type;
1090255932Salfred	attr.xrcd    = xrcd;
1091219820Sjeff	attr.create_flags  = 0;
1092219820Sjeff
1093219820Sjeff	attr.cap.max_send_wr     = cmd.max_send_wr;
1094219820Sjeff	attr.cap.max_recv_wr     = cmd.max_recv_wr;
1095219820Sjeff	attr.cap.max_send_sge    = cmd.max_send_sge;
1096219820Sjeff	attr.cap.max_recv_sge    = cmd.max_recv_sge;
1097219820Sjeff	attr.cap.max_inline_data = cmd.max_inline_data;
1098219820Sjeff
1099219820Sjeff	obj->uevent.events_reported     = 0;
1100219820Sjeff	INIT_LIST_HEAD(&obj->uevent.event_list);
1101219820Sjeff	INIT_LIST_HEAD(&obj->mcast_list);
1102219820Sjeff
1103219820Sjeff	qp = pd->device->create_qp(pd, &attr, &udata);
1104219820Sjeff	if (IS_ERR(qp)) {
1105219820Sjeff		ret = PTR_ERR(qp);
1106219820Sjeff		goto err_put;
1107219820Sjeff	}
1108219820Sjeff
1109219820Sjeff	qp->device     	  = pd->device;
1110219820Sjeff	qp->pd         	  = pd;
1111219820Sjeff	qp->send_cq    	  = attr.send_cq;
1112219820Sjeff	qp->recv_cq    	  = attr.recv_cq;
1113219820Sjeff	qp->srq	       	  = attr.srq;
1114219820Sjeff	qp->uobject       = &obj->uevent.uobject;
1115219820Sjeff	qp->event_handler = attr.event_handler;
1116219820Sjeff	qp->qp_context    = attr.qp_context;
1117219820Sjeff	qp->qp_type	  = attr.qp_type;
1118255932Salfred	qp->xrcd	  = attr.xrcd;
1119219820Sjeff	atomic_inc(&pd->usecnt);
1120219820Sjeff	atomic_inc(&attr.send_cq->usecnt);
1121219820Sjeff	atomic_inc(&attr.recv_cq->usecnt);
1122219820Sjeff	if (attr.srq)
1123219820Sjeff		atomic_inc(&attr.srq->usecnt);
1124255932Salfred	else if (attr.xrcd)
1125255932Salfred		atomic_inc(&attr.xrcd->usecnt);
1126219820Sjeff
1127219820Sjeff	obj->uevent.uobject.object = qp;
1128219820Sjeff	ret = idr_add_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject);
1129219820Sjeff	if (ret)
1130219820Sjeff		goto err_destroy;
1131219820Sjeff
1132219820Sjeff	memset(&resp, 0, sizeof resp);
1133219820Sjeff	resp.qpn             = qp->qp_num;
1134219820Sjeff	resp.qp_handle       = obj->uevent.uobject.id;
1135219820Sjeff	resp.max_recv_sge    = attr.cap.max_recv_sge;
1136219820Sjeff	resp.max_send_sge    = attr.cap.max_send_sge;
1137219820Sjeff	resp.max_recv_wr     = attr.cap.max_recv_wr;
1138219820Sjeff	resp.max_send_wr     = attr.cap.max_send_wr;
1139219820Sjeff	resp.max_inline_data = attr.cap.max_inline_data;
1140219820Sjeff
1141219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
1142219820Sjeff			 &resp, sizeof resp)) {
1143219820Sjeff		ret = -EFAULT;
1144219820Sjeff		goto err_copy;
1145219820Sjeff	}
1146219820Sjeff
1147219820Sjeff	put_pd_read(pd);
1148219820Sjeff	put_cq_read(scq);
1149219820Sjeff	if (rcq != scq)
1150219820Sjeff		put_cq_read(rcq);
1151219820Sjeff	if (srq)
1152219820Sjeff		put_srq_read(srq);
1153219820Sjeff	if (xrcd)
1154219820Sjeff		put_xrcd_read(xrcd_uobj);
1155219820Sjeff
1156219820Sjeff	mutex_lock(&file->mutex);
1157219820Sjeff	list_add_tail(&obj->uevent.uobject.list, &file->ucontext->qp_list);
1158219820Sjeff	mutex_unlock(&file->mutex);
1159219820Sjeff
1160219820Sjeff	obj->uevent.uobject.live = 1;
1161219820Sjeff
1162219820Sjeff	up_write(&obj->uevent.uobject.mutex);
1163219820Sjeff
1164219820Sjeff	return in_len;
1165219820Sjeff
1166219820Sjefferr_copy:
1167219820Sjeff	idr_remove_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject);
1168219820Sjeff
1169219820Sjefferr_destroy:
1170219820Sjeff	ib_destroy_qp(qp);
1171219820Sjeff
1172219820Sjefferr_put:
1173219820Sjeff	if (pd)
1174219820Sjeff		put_pd_read(pd);
1175219820Sjeff	if (scq)
1176219820Sjeff		put_cq_read(scq);
1177219820Sjeff	if (rcq && rcq != scq)
1178219820Sjeff		put_cq_read(rcq);
1179219820Sjeff	if (srq)
1180219820Sjeff		put_srq_read(srq);
1181219820Sjeff	if (xrcd)
1182219820Sjeff		put_xrcd_read(xrcd_uobj);
1183219820Sjeff
1184219820Sjeff	put_uobj_write(&obj->uevent.uobject);
1185219820Sjeff	return ret;
1186219820Sjeff}
1187219820Sjeff
1188219820Sjeffssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file,
1189219820Sjeff			   const char __user *buf, int in_len,
1190219820Sjeff			   int out_len)
1191219820Sjeff{
1192219820Sjeff	struct ib_uverbs_query_qp      cmd;
1193219820Sjeff	struct ib_uverbs_query_qp_resp resp;
1194219820Sjeff	struct ib_qp                   *qp;
1195219820Sjeff	struct ib_qp_attr              *attr;
1196219820Sjeff	struct ib_qp_init_attr         *init_attr;
1197219820Sjeff	int                            ret;
1198219820Sjeff
1199219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
1200219820Sjeff		return -EFAULT;
1201219820Sjeff
1202219820Sjeff	attr      = kmalloc(sizeof *attr, GFP_KERNEL);
1203219820Sjeff	init_attr = kmalloc(sizeof *init_attr, GFP_KERNEL);
1204219820Sjeff	if (!attr || !init_attr) {
1205219820Sjeff		ret = -ENOMEM;
1206219820Sjeff		goto out;
1207219820Sjeff	}
1208219820Sjeff
1209219820Sjeff	qp = idr_read_qp(cmd.qp_handle, file->ucontext);
1210219820Sjeff	if (!qp) {
1211219820Sjeff		ret = -EINVAL;
1212219820Sjeff		goto out;
1213219820Sjeff	}
1214219820Sjeff
1215219820Sjeff	ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr);
1216219820Sjeff
1217219820Sjeff	put_qp_read(qp);
1218219820Sjeff
1219219820Sjeff	if (ret)
1220219820Sjeff		goto out;
1221219820Sjeff
1222219820Sjeff	memset(&resp, 0, sizeof resp);
1223219820Sjeff
1224219820Sjeff	resp.qp_state               = attr->qp_state;
1225219820Sjeff	resp.cur_qp_state           = attr->cur_qp_state;
1226219820Sjeff	resp.path_mtu               = attr->path_mtu;
1227219820Sjeff	resp.path_mig_state         = attr->path_mig_state;
1228219820Sjeff	resp.qkey                   = attr->qkey;
1229219820Sjeff	resp.rq_psn                 = attr->rq_psn;
1230219820Sjeff	resp.sq_psn                 = attr->sq_psn;
1231219820Sjeff	resp.dest_qp_num            = attr->dest_qp_num;
1232219820Sjeff	resp.qp_access_flags        = attr->qp_access_flags;
1233219820Sjeff	resp.pkey_index             = attr->pkey_index;
1234219820Sjeff	resp.alt_pkey_index         = attr->alt_pkey_index;
1235219820Sjeff	resp.sq_draining            = attr->sq_draining;
1236219820Sjeff	resp.max_rd_atomic          = attr->max_rd_atomic;
1237219820Sjeff	resp.max_dest_rd_atomic     = attr->max_dest_rd_atomic;
1238219820Sjeff	resp.min_rnr_timer          = attr->min_rnr_timer;
1239219820Sjeff	resp.port_num               = attr->port_num;
1240219820Sjeff	resp.timeout                = attr->timeout;
1241219820Sjeff	resp.retry_cnt              = attr->retry_cnt;
1242219820Sjeff	resp.rnr_retry              = attr->rnr_retry;
1243219820Sjeff	resp.alt_port_num           = attr->alt_port_num;
1244219820Sjeff	resp.alt_timeout            = attr->alt_timeout;
1245219820Sjeff
1246219820Sjeff	memcpy(resp.dest.dgid, attr->ah_attr.grh.dgid.raw, 16);
1247219820Sjeff	resp.dest.flow_label        = attr->ah_attr.grh.flow_label;
1248219820Sjeff	resp.dest.sgid_index        = attr->ah_attr.grh.sgid_index;
1249219820Sjeff	resp.dest.hop_limit         = attr->ah_attr.grh.hop_limit;
1250219820Sjeff	resp.dest.traffic_class     = attr->ah_attr.grh.traffic_class;
1251219820Sjeff	resp.dest.dlid              = attr->ah_attr.dlid;
1252219820Sjeff	resp.dest.sl                = attr->ah_attr.sl;
1253219820Sjeff	resp.dest.src_path_bits     = attr->ah_attr.src_path_bits;
1254219820Sjeff	resp.dest.static_rate       = attr->ah_attr.static_rate;
1255219820Sjeff	resp.dest.is_global         = !!(attr->ah_attr.ah_flags & IB_AH_GRH);
1256219820Sjeff	resp.dest.port_num          = attr->ah_attr.port_num;
1257219820Sjeff
1258219820Sjeff	memcpy(resp.alt_dest.dgid, attr->alt_ah_attr.grh.dgid.raw, 16);
1259219820Sjeff	resp.alt_dest.flow_label    = attr->alt_ah_attr.grh.flow_label;
1260219820Sjeff	resp.alt_dest.sgid_index    = attr->alt_ah_attr.grh.sgid_index;
1261219820Sjeff	resp.alt_dest.hop_limit     = attr->alt_ah_attr.grh.hop_limit;
1262219820Sjeff	resp.alt_dest.traffic_class = attr->alt_ah_attr.grh.traffic_class;
1263219820Sjeff	resp.alt_dest.dlid          = attr->alt_ah_attr.dlid;
1264219820Sjeff	resp.alt_dest.sl            = attr->alt_ah_attr.sl;
1265219820Sjeff	resp.alt_dest.src_path_bits = attr->alt_ah_attr.src_path_bits;
1266219820Sjeff	resp.alt_dest.static_rate   = attr->alt_ah_attr.static_rate;
1267219820Sjeff	resp.alt_dest.is_global     = !!(attr->alt_ah_attr.ah_flags & IB_AH_GRH);
1268219820Sjeff	resp.alt_dest.port_num      = attr->alt_ah_attr.port_num;
1269219820Sjeff
1270219820Sjeff	resp.max_send_wr            = init_attr->cap.max_send_wr;
1271219820Sjeff	resp.max_recv_wr            = init_attr->cap.max_recv_wr;
1272219820Sjeff	resp.max_send_sge           = init_attr->cap.max_send_sge;
1273219820Sjeff	resp.max_recv_sge           = init_attr->cap.max_recv_sge;
1274219820Sjeff	resp.max_inline_data        = init_attr->cap.max_inline_data;
1275219820Sjeff	resp.sq_sig_all             = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR;
1276219820Sjeff
1277219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
1278219820Sjeff			 &resp, sizeof resp))
1279219820Sjeff		ret = -EFAULT;
1280219820Sjeff
1281219820Sjeffout:
1282219820Sjeff	kfree(attr);
1283219820Sjeff	kfree(init_attr);
1284219820Sjeff
1285219820Sjeff	return ret ? ret : in_len;
1286219820Sjeff}
1287219820Sjeff
1288219820Sjeffssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
1289219820Sjeff			    const char __user *buf, int in_len,
1290219820Sjeff			    int out_len)
1291219820Sjeff{
1292219820Sjeff	struct ib_uverbs_modify_qp cmd;
1293219820Sjeff	struct ib_udata            udata;
1294219820Sjeff	struct ib_qp              *qp;
1295219820Sjeff	struct ib_qp_attr         *attr;
1296219820Sjeff	int                        ret;
1297219820Sjeff
1298219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
1299219820Sjeff		return -EFAULT;
1300219820Sjeff
1301219820Sjeff	INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd,
1302219820Sjeff		   out_len);
1303219820Sjeff
1304219820Sjeff	attr = kmalloc(sizeof *attr, GFP_KERNEL);
1305219820Sjeff	if (!attr)
1306219820Sjeff		return -ENOMEM;
1307219820Sjeff
1308219820Sjeff	qp = idr_read_qp(cmd.qp_handle, file->ucontext);
1309219820Sjeff	if (!qp) {
1310219820Sjeff		ret = -EINVAL;
1311219820Sjeff		goto out;
1312219820Sjeff	}
1313219820Sjeff
1314219820Sjeff	attr->qp_state 		  = cmd.qp_state;
1315219820Sjeff	attr->cur_qp_state 	  = cmd.cur_qp_state;
1316219820Sjeff	attr->path_mtu 		  = cmd.path_mtu;
1317219820Sjeff	attr->path_mig_state 	  = cmd.path_mig_state;
1318219820Sjeff	attr->qkey 		  = cmd.qkey;
1319219820Sjeff	attr->rq_psn 		  = cmd.rq_psn;
1320219820Sjeff	attr->sq_psn 		  = cmd.sq_psn;
1321219820Sjeff	attr->dest_qp_num 	  = cmd.dest_qp_num;
1322219820Sjeff	attr->qp_access_flags 	  = cmd.qp_access_flags;
1323219820Sjeff	attr->pkey_index 	  = cmd.pkey_index;
1324219820Sjeff	attr->alt_pkey_index 	  = cmd.alt_pkey_index;
1325219820Sjeff	attr->en_sqd_async_notify = cmd.en_sqd_async_notify;
1326219820Sjeff	attr->max_rd_atomic 	  = cmd.max_rd_atomic;
1327219820Sjeff	attr->max_dest_rd_atomic  = cmd.max_dest_rd_atomic;
1328219820Sjeff	attr->min_rnr_timer 	  = cmd.min_rnr_timer;
1329219820Sjeff	attr->port_num 		  = cmd.port_num;
1330219820Sjeff	attr->timeout 		  = cmd.timeout;
1331219820Sjeff	attr->retry_cnt 	  = cmd.retry_cnt;
1332219820Sjeff	attr->rnr_retry 	  = cmd.rnr_retry;
1333219820Sjeff	attr->alt_port_num 	  = cmd.alt_port_num;
1334219820Sjeff	attr->alt_timeout 	  = cmd.alt_timeout;
1335219820Sjeff
1336219820Sjeff	memcpy(attr->ah_attr.grh.dgid.raw, cmd.dest.dgid, 16);
1337219820Sjeff	attr->ah_attr.grh.flow_label        = cmd.dest.flow_label;
1338219820Sjeff	attr->ah_attr.grh.sgid_index        = cmd.dest.sgid_index;
1339219820Sjeff	attr->ah_attr.grh.hop_limit         = cmd.dest.hop_limit;
1340219820Sjeff	attr->ah_attr.grh.traffic_class     = cmd.dest.traffic_class;
1341219820Sjeff	attr->ah_attr.dlid 	    	    = cmd.dest.dlid;
1342219820Sjeff	attr->ah_attr.sl   	    	    = cmd.dest.sl;
1343219820Sjeff	attr->ah_attr.src_path_bits 	    = cmd.dest.src_path_bits;
1344219820Sjeff	attr->ah_attr.static_rate   	    = cmd.dest.static_rate;
1345219820Sjeff	attr->ah_attr.ah_flags 	    	    = cmd.dest.is_global ? IB_AH_GRH : 0;
1346219820Sjeff	attr->ah_attr.port_num 	    	    = cmd.dest.port_num;
1347219820Sjeff
1348219820Sjeff	memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd.alt_dest.dgid, 16);
1349219820Sjeff	attr->alt_ah_attr.grh.flow_label    = cmd.alt_dest.flow_label;
1350219820Sjeff	attr->alt_ah_attr.grh.sgid_index    = cmd.alt_dest.sgid_index;
1351219820Sjeff	attr->alt_ah_attr.grh.hop_limit     = cmd.alt_dest.hop_limit;
1352219820Sjeff	attr->alt_ah_attr.grh.traffic_class = cmd.alt_dest.traffic_class;
1353219820Sjeff	attr->alt_ah_attr.dlid 	    	    = cmd.alt_dest.dlid;
1354219820Sjeff	attr->alt_ah_attr.sl   	    	    = cmd.alt_dest.sl;
1355219820Sjeff	attr->alt_ah_attr.src_path_bits     = cmd.alt_dest.src_path_bits;
1356219820Sjeff	attr->alt_ah_attr.static_rate       = cmd.alt_dest.static_rate;
1357219820Sjeff	attr->alt_ah_attr.ah_flags 	    = cmd.alt_dest.is_global ? IB_AH_GRH : 0;
1358219820Sjeff	attr->alt_ah_attr.port_num 	    = cmd.alt_dest.port_num;
1359219820Sjeff
1360219820Sjeff	ret = qp->device->modify_qp(qp, attr, cmd.attr_mask, &udata);
1361219820Sjeff
1362219820Sjeff	put_qp_read(qp);
1363219820Sjeff
1364219820Sjeff	if (ret)
1365219820Sjeff		goto out;
1366219820Sjeff
1367219820Sjeff	ret = in_len;
1368219820Sjeff
1369219820Sjeffout:
1370219820Sjeff	kfree(attr);
1371219820Sjeff
1372219820Sjeff	return ret;
1373219820Sjeff}
1374219820Sjeff
1375219820Sjeffssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
1376219820Sjeff			     const char __user *buf, int in_len,
1377219820Sjeff			     int out_len)
1378219820Sjeff{
1379219820Sjeff	struct ib_uverbs_destroy_qp      cmd;
1380219820Sjeff	struct ib_uverbs_destroy_qp_resp resp;
1381219820Sjeff	struct ib_uobject		*uobj;
1382219820Sjeff	struct ib_qp               	*qp;
1383219820Sjeff	struct ib_uqp_object        	*obj;
1384219820Sjeff	int                        	 ret = -EINVAL;
1385219820Sjeff
1386219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
1387219820Sjeff		return -EFAULT;
1388219820Sjeff
1389219820Sjeff	memset(&resp, 0, sizeof resp);
1390219820Sjeff
1391219820Sjeff	uobj = idr_write_uobj(&ib_uverbs_qp_idr, cmd.qp_handle, file->ucontext);
1392219820Sjeff	if (!uobj)
1393219820Sjeff		return -EINVAL;
1394219820Sjeff	qp  = uobj->object;
1395219820Sjeff	obj = container_of(uobj, struct ib_uqp_object, uevent.uobject);
1396219820Sjeff
1397219820Sjeff	if (!list_empty(&obj->mcast_list)) {
1398219820Sjeff		put_uobj_write(uobj);
1399219820Sjeff		return -EBUSY;
1400219820Sjeff	}
1401219820Sjeff
1402219820Sjeff	ret = ib_destroy_qp(qp);
1403219820Sjeff	if (!ret)
1404219820Sjeff		uobj->live = 0;
1405219820Sjeff
1406219820Sjeff	put_uobj_write(uobj);
1407219820Sjeff
1408219820Sjeff	if (ret)
1409219820Sjeff		return ret;
1410219820Sjeff
1411219820Sjeff	idr_remove_uobj(&ib_uverbs_qp_idr, uobj);
1412219820Sjeff
1413219820Sjeff	mutex_lock(&file->mutex);
1414219820Sjeff	list_del(&uobj->list);
1415219820Sjeff	mutex_unlock(&file->mutex);
1416219820Sjeff
1417219820Sjeff	ib_uverbs_release_uevent(file, &obj->uevent);
1418219820Sjeff
1419219820Sjeff	resp.events_reported = obj->uevent.events_reported;
1420219820Sjeff
1421219820Sjeff	put_uobj(uobj);
1422219820Sjeff
1423219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
1424219820Sjeff			 &resp, sizeof resp))
1425219820Sjeff		return -EFAULT;
1426219820Sjeff
1427219820Sjeff	return in_len;
1428219820Sjeff}
1429219820Sjeff
1430219820Sjeffssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
1431219820Sjeff			    const char __user *buf, int in_len,
1432219820Sjeff			    int out_len)
1433219820Sjeff{
1434219820Sjeff	struct ib_uverbs_post_send      cmd;
1435219820Sjeff	struct ib_uverbs_post_send_resp resp;
1436219820Sjeff	struct ib_uverbs_send_wr       *user_wr;
1437219820Sjeff	struct ib_send_wr              *wr = NULL, *last, *next, *bad_wr;
1438219820Sjeff	struct ib_qp                   *qp;
1439219820Sjeff	int                             i, sg_ind;
1440219820Sjeff	int				is_ud;
1441219820Sjeff	ssize_t                         ret = -EINVAL;
1442219820Sjeff
1443219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
1444219820Sjeff		return -EFAULT;
1445219820Sjeff
1446219820Sjeff	if (in_len < sizeof cmd + cmd.wqe_size * cmd.wr_count +
1447219820Sjeff	    cmd.sge_count * sizeof (struct ib_uverbs_sge))
1448219820Sjeff		return -EINVAL;
1449219820Sjeff
1450219820Sjeff	if (cmd.wqe_size < sizeof (struct ib_uverbs_send_wr))
1451219820Sjeff		return -EINVAL;
1452219820Sjeff
1453219820Sjeff	user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL);
1454219820Sjeff	if (!user_wr)
1455219820Sjeff		return -ENOMEM;
1456219820Sjeff
1457219820Sjeff	qp = idr_read_qp(cmd.qp_handle, file->ucontext);
1458219820Sjeff	if (!qp)
1459219820Sjeff		goto out;
1460219820Sjeff
1461219820Sjeff	is_ud = qp->qp_type == IB_QPT_UD;
1462219820Sjeff	sg_ind = 0;
1463219820Sjeff	last = NULL;
1464219820Sjeff	for (i = 0; i < cmd.wr_count; ++i) {
1465219820Sjeff		if (copy_from_user(user_wr,
1466219820Sjeff				   buf + sizeof cmd + i * cmd.wqe_size,
1467219820Sjeff				   cmd.wqe_size)) {
1468219820Sjeff			ret = -EFAULT;
1469219820Sjeff			goto out_put;
1470219820Sjeff		}
1471219820Sjeff
1472219820Sjeff		if (user_wr->num_sge + sg_ind > cmd.sge_count) {
1473219820Sjeff			ret = -EINVAL;
1474219820Sjeff			goto out_put;
1475219820Sjeff		}
1476219820Sjeff
1477219820Sjeff		next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) +
1478219820Sjeff			       user_wr->num_sge * sizeof (struct ib_sge),
1479219820Sjeff			       GFP_KERNEL);
1480219820Sjeff		if (!next) {
1481219820Sjeff			ret = -ENOMEM;
1482219820Sjeff			goto out_put;
1483219820Sjeff		}
1484219820Sjeff
1485219820Sjeff		if (!last)
1486219820Sjeff			wr = next;
1487219820Sjeff		else
1488219820Sjeff			last->next = next;
1489219820Sjeff		last = next;
1490219820Sjeff
1491219820Sjeff		next->next       = NULL;
1492219820Sjeff		next->wr_id      = user_wr->wr_id;
1493219820Sjeff		next->num_sge    = user_wr->num_sge;
1494219820Sjeff		next->opcode     = user_wr->opcode;
1495219820Sjeff		next->send_flags = user_wr->send_flags;
1496219820Sjeff
1497219820Sjeff		if (is_ud) {
1498219820Sjeff			next->wr.ud.ah = idr_read_ah(user_wr->wr.ud.ah,
1499219820Sjeff						     file->ucontext);
1500219820Sjeff			if (!next->wr.ud.ah) {
1501219820Sjeff				ret = -EINVAL;
1502219820Sjeff				goto out_put;
1503219820Sjeff			}
1504219820Sjeff			next->wr.ud.remote_qpn  = user_wr->wr.ud.remote_qpn;
1505219820Sjeff			next->wr.ud.remote_qkey = user_wr->wr.ud.remote_qkey;
1506219820Sjeff		} else {
1507219820Sjeff			switch (next->opcode) {
1508219820Sjeff			case IB_WR_RDMA_WRITE_WITH_IMM:
1509219820Sjeff				next->ex.imm_data =
1510219820Sjeff					(__be32 __force) user_wr->ex.imm_data;
1511219820Sjeff			case IB_WR_RDMA_WRITE:
1512219820Sjeff			case IB_WR_RDMA_READ:
1513219820Sjeff				next->wr.rdma.remote_addr =
1514219820Sjeff					user_wr->wr.rdma.remote_addr;
1515219820Sjeff				next->wr.rdma.rkey        =
1516219820Sjeff					user_wr->wr.rdma.rkey;
1517219820Sjeff				break;
1518219820Sjeff			case IB_WR_SEND_WITH_IMM:
1519219820Sjeff				next->ex.imm_data =
1520219820Sjeff					(__be32 __force) user_wr->ex.imm_data;
1521219820Sjeff				break;
1522219820Sjeff			case IB_WR_SEND_WITH_INV:
1523219820Sjeff				next->ex.invalidate_rkey =
1524219820Sjeff					user_wr->ex.invalidate_rkey;
1525219820Sjeff				break;
1526219820Sjeff			case IB_WR_ATOMIC_CMP_AND_SWP:
1527219820Sjeff			case IB_WR_ATOMIC_FETCH_AND_ADD:
1528219820Sjeff				next->wr.atomic.remote_addr =
1529219820Sjeff					user_wr->wr.atomic.remote_addr;
1530219820Sjeff				next->wr.atomic.compare_add =
1531219820Sjeff					user_wr->wr.atomic.compare_add;
1532219820Sjeff				next->wr.atomic.swap = user_wr->wr.atomic.swap;
1533219820Sjeff				next->wr.atomic.rkey = user_wr->wr.atomic.rkey;
1534219820Sjeff				break;
1535219820Sjeff			default:
1536219820Sjeff				break;
1537219820Sjeff			}
1538219820Sjeff		}
1539219820Sjeff
1540219820Sjeff		if (next->num_sge) {
1541219820Sjeff			next->sg_list = (void *) next +
1542219820Sjeff				ALIGN(sizeof *next, sizeof (struct ib_sge));
1543219820Sjeff			if (copy_from_user(next->sg_list,
1544219820Sjeff					   buf + sizeof cmd +
1545219820Sjeff					   cmd.wr_count * cmd.wqe_size +
1546219820Sjeff					   sg_ind * sizeof (struct ib_sge),
1547219820Sjeff					   next->num_sge * sizeof (struct ib_sge))) {
1548219820Sjeff				ret = -EFAULT;
1549219820Sjeff				goto out_put;
1550219820Sjeff			}
1551219820Sjeff			sg_ind += next->num_sge;
1552219820Sjeff		} else
1553219820Sjeff			next->sg_list = NULL;
1554219820Sjeff	}
1555219820Sjeff
1556219820Sjeff	resp.bad_wr = 0;
1557219820Sjeff	ret = qp->device->post_send(qp, wr, &bad_wr);
1558219820Sjeff	if (ret)
1559219820Sjeff		for (next = wr; next; next = next->next) {
1560219820Sjeff			++resp.bad_wr;
1561219820Sjeff			if (next == bad_wr)
1562219820Sjeff				break;
1563219820Sjeff		}
1564219820Sjeff
1565219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
1566219820Sjeff			 &resp, sizeof resp))
1567219820Sjeff		ret = -EFAULT;
1568219820Sjeff
1569219820Sjeffout_put:
1570219820Sjeff	put_qp_read(qp);
1571219820Sjeff
1572219820Sjeff	while (wr) {
1573219820Sjeff		if (is_ud && wr->wr.ud.ah)
1574219820Sjeff			put_ah_read(wr->wr.ud.ah);
1575219820Sjeff		next = wr->next;
1576219820Sjeff		kfree(wr);
1577219820Sjeff		wr = next;
1578219820Sjeff	}
1579219820Sjeff
1580219820Sjeffout:
1581219820Sjeff	kfree(user_wr);
1582219820Sjeff
1583219820Sjeff	return ret ? ret : in_len;
1584219820Sjeff}
1585219820Sjeff
1586219820Sjeffstatic struct ib_recv_wr *ib_uverbs_unmarshall_recv(const char __user *buf,
1587219820Sjeff						    int in_len,
1588219820Sjeff						    u32 wr_count,
1589219820Sjeff						    u32 sge_count,
1590219820Sjeff						    u32 wqe_size)
1591219820Sjeff{
1592219820Sjeff	struct ib_uverbs_recv_wr *user_wr;
1593219820Sjeff	struct ib_recv_wr        *wr = NULL, *last, *next;
1594219820Sjeff	int                       sg_ind;
1595219820Sjeff	int                       i;
1596219820Sjeff	int                       ret;
1597219820Sjeff
1598219820Sjeff	if (in_len < wqe_size * wr_count +
1599219820Sjeff	    sge_count * sizeof (struct ib_uverbs_sge))
1600219820Sjeff		return ERR_PTR(-EINVAL);
1601219820Sjeff
1602219820Sjeff	if (wqe_size < sizeof (struct ib_uverbs_recv_wr))
1603219820Sjeff		return ERR_PTR(-EINVAL);
1604219820Sjeff
1605219820Sjeff	user_wr = kmalloc(wqe_size, GFP_KERNEL);
1606219820Sjeff	if (!user_wr)
1607219820Sjeff		return ERR_PTR(-ENOMEM);
1608219820Sjeff
1609219820Sjeff	sg_ind = 0;
1610219820Sjeff	last = NULL;
1611219820Sjeff	for (i = 0; i < wr_count; ++i) {
1612219820Sjeff		if (copy_from_user(user_wr, buf + i * wqe_size,
1613219820Sjeff				   wqe_size)) {
1614219820Sjeff			ret = -EFAULT;
1615219820Sjeff			goto err;
1616219820Sjeff		}
1617219820Sjeff
1618219820Sjeff		if (user_wr->num_sge + sg_ind > sge_count) {
1619219820Sjeff			ret = -EINVAL;
1620219820Sjeff			goto err;
1621219820Sjeff		}
1622219820Sjeff
1623219820Sjeff		next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) +
1624219820Sjeff			       user_wr->num_sge * sizeof (struct ib_sge),
1625219820Sjeff			       GFP_KERNEL);
1626219820Sjeff		if (!next) {
1627219820Sjeff			ret = -ENOMEM;
1628219820Sjeff			goto err;
1629219820Sjeff		}
1630219820Sjeff
1631219820Sjeff		if (!last)
1632219820Sjeff			wr = next;
1633219820Sjeff		else
1634219820Sjeff			last->next = next;
1635219820Sjeff		last = next;
1636219820Sjeff
1637219820Sjeff		next->next       = NULL;
1638219820Sjeff		next->wr_id      = user_wr->wr_id;
1639219820Sjeff		next->num_sge    = user_wr->num_sge;
1640219820Sjeff
1641219820Sjeff		if (next->num_sge) {
1642219820Sjeff			next->sg_list = (void *) next +
1643219820Sjeff				ALIGN(sizeof *next, sizeof (struct ib_sge));
1644219820Sjeff			if (copy_from_user(next->sg_list,
1645219820Sjeff					   buf + wr_count * wqe_size +
1646219820Sjeff					   sg_ind * sizeof (struct ib_sge),
1647219820Sjeff					   next->num_sge * sizeof (struct ib_sge))) {
1648219820Sjeff				ret = -EFAULT;
1649219820Sjeff				goto err;
1650219820Sjeff			}
1651219820Sjeff			sg_ind += next->num_sge;
1652219820Sjeff		} else
1653219820Sjeff			next->sg_list = NULL;
1654219820Sjeff	}
1655219820Sjeff
1656219820Sjeff	kfree(user_wr);
1657219820Sjeff	return wr;
1658219820Sjeff
1659219820Sjefferr:
1660219820Sjeff	kfree(user_wr);
1661219820Sjeff
1662219820Sjeff	while (wr) {
1663219820Sjeff		next = wr->next;
1664219820Sjeff		kfree(wr);
1665219820Sjeff		wr = next;
1666219820Sjeff	}
1667219820Sjeff
1668219820Sjeff	return ERR_PTR(ret);
1669219820Sjeff}
1670219820Sjeff
1671219820Sjeffssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
1672219820Sjeff			    const char __user *buf, int in_len,
1673219820Sjeff			    int out_len)
1674219820Sjeff{
1675219820Sjeff	struct ib_uverbs_post_recv      cmd;
1676219820Sjeff	struct ib_uverbs_post_recv_resp resp;
1677219820Sjeff	struct ib_recv_wr              *wr, *next, *bad_wr;
1678219820Sjeff	struct ib_qp                   *qp;
1679219820Sjeff	ssize_t                         ret = -EINVAL;
1680219820Sjeff
1681219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
1682219820Sjeff		return -EFAULT;
1683219820Sjeff
1684219820Sjeff	wr = ib_uverbs_unmarshall_recv(buf + sizeof cmd,
1685219820Sjeff				       in_len - sizeof cmd, cmd.wr_count,
1686219820Sjeff				       cmd.sge_count, cmd.wqe_size);
1687219820Sjeff	if (IS_ERR(wr))
1688219820Sjeff		return PTR_ERR(wr);
1689219820Sjeff
1690219820Sjeff	qp = idr_read_qp(cmd.qp_handle, file->ucontext);
1691219820Sjeff	if (!qp)
1692219820Sjeff		goto out;
1693219820Sjeff
1694219820Sjeff	resp.bad_wr = 0;
1695219820Sjeff	ret = qp->device->post_recv(qp, wr, &bad_wr);
1696219820Sjeff
1697219820Sjeff	put_qp_read(qp);
1698219820Sjeff
1699219820Sjeff	if (ret)
1700219820Sjeff		for (next = wr; next; next = next->next) {
1701219820Sjeff			++resp.bad_wr;
1702219820Sjeff			if (next == bad_wr)
1703219820Sjeff				break;
1704219820Sjeff		}
1705219820Sjeff
1706219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
1707219820Sjeff			 &resp, sizeof resp))
1708219820Sjeff		ret = -EFAULT;
1709219820Sjeff
1710219820Sjeffout:
1711219820Sjeff	while (wr) {
1712219820Sjeff		next = wr->next;
1713219820Sjeff		kfree(wr);
1714219820Sjeff		wr = next;
1715219820Sjeff	}
1716219820Sjeff
1717219820Sjeff	return ret ? ret : in_len;
1718219820Sjeff}
1719219820Sjeff
1720219820Sjeffssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
1721219820Sjeff				const char __user *buf, int in_len,
1722219820Sjeff				int out_len)
1723219820Sjeff{
1724219820Sjeff	struct ib_uverbs_post_srq_recv      cmd;
1725219820Sjeff	struct ib_uverbs_post_srq_recv_resp resp;
1726219820Sjeff	struct ib_recv_wr                  *wr, *next, *bad_wr;
1727219820Sjeff	struct ib_srq                      *srq;
1728219820Sjeff	ssize_t                             ret = -EINVAL;
1729219820Sjeff
1730219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
1731219820Sjeff		return -EFAULT;
1732219820Sjeff
1733219820Sjeff	wr = ib_uverbs_unmarshall_recv(buf + sizeof cmd,
1734219820Sjeff				       in_len - sizeof cmd, cmd.wr_count,
1735219820Sjeff				       cmd.sge_count, cmd.wqe_size);
1736219820Sjeff	if (IS_ERR(wr))
1737219820Sjeff		return PTR_ERR(wr);
1738219820Sjeff
1739219820Sjeff	srq = idr_read_srq(cmd.srq_handle, file->ucontext);
1740219820Sjeff	if (!srq)
1741219820Sjeff		goto out;
1742219820Sjeff
1743219820Sjeff	resp.bad_wr = 0;
1744219820Sjeff	ret = srq->device->post_srq_recv(srq, wr, &bad_wr);
1745219820Sjeff
1746219820Sjeff	put_srq_read(srq);
1747219820Sjeff
1748219820Sjeff	if (ret)
1749219820Sjeff		for (next = wr; next; next = next->next) {
1750219820Sjeff			++resp.bad_wr;
1751219820Sjeff			if (next == bad_wr)
1752219820Sjeff				break;
1753219820Sjeff		}
1754219820Sjeff
1755219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
1756219820Sjeff			 &resp, sizeof resp))
1757219820Sjeff		ret = -EFAULT;
1758219820Sjeff
1759219820Sjeffout:
1760219820Sjeff	while (wr) {
1761219820Sjeff		next = wr->next;
1762219820Sjeff		kfree(wr);
1763219820Sjeff		wr = next;
1764219820Sjeff	}
1765219820Sjeff
1766219820Sjeff	return ret ? ret : in_len;
1767219820Sjeff}
1768219820Sjeff
1769219820Sjeffssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
1770219820Sjeff			    const char __user *buf, int in_len,
1771219820Sjeff			    int out_len)
1772219820Sjeff{
1773219820Sjeff	struct ib_uverbs_create_ah	 cmd;
1774219820Sjeff	struct ib_uverbs_create_ah_resp	 resp;
1775219820Sjeff	struct ib_uobject		*uobj;
1776219820Sjeff	struct ib_pd			*pd;
1777219820Sjeff	struct ib_ah			*ah;
1778219820Sjeff	struct ib_ah_attr		attr;
1779219820Sjeff	int ret;
1780219820Sjeff
1781219820Sjeff	if (out_len < sizeof resp)
1782219820Sjeff		return -ENOSPC;
1783219820Sjeff
1784219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
1785219820Sjeff		return -EFAULT;
1786219820Sjeff
1787219820Sjeff	uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
1788219820Sjeff	if (!uobj)
1789219820Sjeff		return -ENOMEM;
1790219820Sjeff
1791219820Sjeff	init_uobj(uobj, cmd.user_handle, file->ucontext, &ah_lock_key);
1792219820Sjeff	down_write(&uobj->mutex);
1793219820Sjeff
1794219820Sjeff	pd = idr_read_pd(cmd.pd_handle, file->ucontext);
1795219820Sjeff	if (!pd) {
1796219820Sjeff		ret = -EINVAL;
1797219820Sjeff		goto err;
1798219820Sjeff	}
1799219820Sjeff
1800219820Sjeff	attr.dlid 	       = cmd.attr.dlid;
1801219820Sjeff	attr.sl 	       = cmd.attr.sl;
1802219820Sjeff	attr.src_path_bits     = cmd.attr.src_path_bits;
1803219820Sjeff	attr.static_rate       = cmd.attr.static_rate;
1804219820Sjeff	attr.ah_flags          = cmd.attr.is_global ? IB_AH_GRH : 0;
1805219820Sjeff	attr.port_num 	       = cmd.attr.port_num;
1806219820Sjeff	attr.grh.flow_label    = cmd.attr.grh.flow_label;
1807219820Sjeff	attr.grh.sgid_index    = cmd.attr.grh.sgid_index;
1808219820Sjeff	attr.grh.hop_limit     = cmd.attr.grh.hop_limit;
1809219820Sjeff	attr.grh.traffic_class = cmd.attr.grh.traffic_class;
1810219820Sjeff	memcpy(attr.grh.dgid.raw, cmd.attr.grh.dgid, 16);
1811219820Sjeff
1812219820Sjeff	ah = ib_create_ah(pd, &attr);
1813219820Sjeff	if (IS_ERR(ah)) {
1814219820Sjeff		ret = PTR_ERR(ah);
1815219820Sjeff		goto err_put;
1816219820Sjeff	}
1817219820Sjeff
1818219820Sjeff	ah->uobject  = uobj;
1819219820Sjeff	uobj->object = ah;
1820219820Sjeff
1821219820Sjeff	ret = idr_add_uobj(&ib_uverbs_ah_idr, uobj);
1822219820Sjeff	if (ret)
1823219820Sjeff		goto err_destroy;
1824219820Sjeff
1825219820Sjeff	resp.ah_handle = uobj->id;
1826219820Sjeff
1827219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
1828219820Sjeff			 &resp, sizeof resp)) {
1829219820Sjeff		ret = -EFAULT;
1830219820Sjeff		goto err_copy;
1831219820Sjeff	}
1832219820Sjeff
1833219820Sjeff	put_pd_read(pd);
1834219820Sjeff
1835219820Sjeff	mutex_lock(&file->mutex);
1836219820Sjeff	list_add_tail(&uobj->list, &file->ucontext->ah_list);
1837219820Sjeff	mutex_unlock(&file->mutex);
1838219820Sjeff
1839219820Sjeff	uobj->live = 1;
1840219820Sjeff
1841219820Sjeff	up_write(&uobj->mutex);
1842219820Sjeff
1843219820Sjeff	return in_len;
1844219820Sjeff
1845219820Sjefferr_copy:
1846219820Sjeff	idr_remove_uobj(&ib_uverbs_ah_idr, uobj);
1847219820Sjeff
1848219820Sjefferr_destroy:
1849219820Sjeff	ib_destroy_ah(ah);
1850219820Sjeff
1851219820Sjefferr_put:
1852219820Sjeff	put_pd_read(pd);
1853219820Sjeff
1854219820Sjefferr:
1855219820Sjeff	put_uobj_write(uobj);
1856219820Sjeff	return ret;
1857219820Sjeff}
1858219820Sjeff
1859219820Sjeffssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file,
1860219820Sjeff			     const char __user *buf, int in_len, int out_len)
1861219820Sjeff{
1862219820Sjeff	struct ib_uverbs_destroy_ah cmd;
1863219820Sjeff	struct ib_ah		   *ah;
1864219820Sjeff	struct ib_uobject	   *uobj;
1865219820Sjeff	int			    ret;
1866219820Sjeff
1867219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
1868219820Sjeff		return -EFAULT;
1869219820Sjeff
1870219820Sjeff	uobj = idr_write_uobj(&ib_uverbs_ah_idr, cmd.ah_handle, file->ucontext);
1871219820Sjeff	if (!uobj)
1872219820Sjeff		return -EINVAL;
1873219820Sjeff	ah = uobj->object;
1874219820Sjeff
1875219820Sjeff	ret = ib_destroy_ah(ah);
1876219820Sjeff	if (!ret)
1877219820Sjeff		uobj->live = 0;
1878219820Sjeff
1879219820Sjeff	put_uobj_write(uobj);
1880219820Sjeff
1881219820Sjeff	if (ret)
1882219820Sjeff		return ret;
1883219820Sjeff
1884219820Sjeff	idr_remove_uobj(&ib_uverbs_ah_idr, uobj);
1885219820Sjeff
1886219820Sjeff	mutex_lock(&file->mutex);
1887219820Sjeff	list_del(&uobj->list);
1888219820Sjeff	mutex_unlock(&file->mutex);
1889219820Sjeff
1890219820Sjeff	put_uobj(uobj);
1891219820Sjeff
1892219820Sjeff	return in_len;
1893219820Sjeff}
1894219820Sjeff
1895219820Sjeffssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
1896219820Sjeff			       const char __user *buf, int in_len,
1897219820Sjeff			       int out_len)
1898219820Sjeff{
1899219820Sjeff	struct ib_uverbs_attach_mcast cmd;
1900219820Sjeff	struct ib_qp                 *qp;
1901219820Sjeff	struct ib_uqp_object         *obj;
1902219820Sjeff	struct ib_uverbs_mcast_entry *mcast;
1903219820Sjeff	int                           ret;
1904219820Sjeff
1905219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
1906219820Sjeff		return -EFAULT;
1907219820Sjeff
1908219820Sjeff	qp = idr_read_qp(cmd.qp_handle, file->ucontext);
1909219820Sjeff	if (!qp)
1910219820Sjeff		return -EINVAL;
1911219820Sjeff
1912219820Sjeff	obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
1913219820Sjeff
1914219820Sjeff	list_for_each_entry(mcast, &obj->mcast_list, list)
1915219820Sjeff		if (cmd.mlid == mcast->lid &&
1916219820Sjeff		    !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) {
1917219820Sjeff			ret = 0;
1918219820Sjeff			goto out_put;
1919219820Sjeff		}
1920219820Sjeff
1921219820Sjeff	mcast = kmalloc(sizeof *mcast, GFP_KERNEL);
1922219820Sjeff	if (!mcast) {
1923219820Sjeff		ret = -ENOMEM;
1924219820Sjeff		goto out_put;
1925219820Sjeff	}
1926219820Sjeff
1927219820Sjeff	mcast->lid = cmd.mlid;
1928219820Sjeff	memcpy(mcast->gid.raw, cmd.gid, sizeof mcast->gid.raw);
1929219820Sjeff
1930219820Sjeff	ret = ib_attach_mcast(qp, &mcast->gid, cmd.mlid);
1931219820Sjeff	if (!ret)
1932219820Sjeff		list_add_tail(&mcast->list, &obj->mcast_list);
1933219820Sjeff	else
1934219820Sjeff		kfree(mcast);
1935219820Sjeff
1936219820Sjeffout_put:
1937219820Sjeff	put_qp_read(qp);
1938219820Sjeff
1939219820Sjeff	return ret ? ret : in_len;
1940219820Sjeff}
1941219820Sjeff
1942219820Sjeffssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
1943219820Sjeff			       const char __user *buf, int in_len,
1944219820Sjeff			       int out_len)
1945219820Sjeff{
1946219820Sjeff	struct ib_uverbs_detach_mcast cmd;
1947219820Sjeff	struct ib_uqp_object         *obj;
1948219820Sjeff	struct ib_qp                 *qp;
1949219820Sjeff	struct ib_uverbs_mcast_entry *mcast;
1950219820Sjeff	int                           ret = -EINVAL;
1951219820Sjeff
1952219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
1953219820Sjeff		return -EFAULT;
1954219820Sjeff
1955219820Sjeff	qp = idr_read_qp(cmd.qp_handle, file->ucontext);
1956219820Sjeff	if (!qp)
1957219820Sjeff		return -EINVAL;
1958219820Sjeff
1959219820Sjeff	ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid);
1960219820Sjeff	if (ret)
1961219820Sjeff		goto out_put;
1962219820Sjeff
1963219820Sjeff	obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
1964219820Sjeff
1965219820Sjeff	list_for_each_entry(mcast, &obj->mcast_list, list)
1966219820Sjeff		if (cmd.mlid == mcast->lid &&
1967219820Sjeff		    !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) {
1968219820Sjeff			list_del(&mcast->list);
1969219820Sjeff			kfree(mcast);
1970219820Sjeff			break;
1971219820Sjeff		}
1972219820Sjeff
1973219820Sjeffout_put:
1974219820Sjeff	put_qp_read(qp);
1975219820Sjeff
1976219820Sjeff	return ret ? ret : in_len;
1977219820Sjeff}
1978219820Sjeff
1979219820Sjeffssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
1980219820Sjeff			     const char __user *buf, int in_len,
1981219820Sjeff			     int out_len)
1982219820Sjeff{
1983219820Sjeff	struct ib_uverbs_create_srq      cmd;
1984219820Sjeff	struct ib_uverbs_create_srq_resp resp;
1985219820Sjeff	struct ib_udata                  udata;
1986219820Sjeff	struct ib_uevent_object         *obj;
1987219820Sjeff	struct ib_pd                    *pd;
1988219820Sjeff	struct ib_srq                   *srq;
1989219820Sjeff	struct ib_srq_init_attr          attr;
1990219820Sjeff	int ret;
1991219820Sjeff
1992219820Sjeff	if (out_len < sizeof resp)
1993219820Sjeff		return -ENOSPC;
1994219820Sjeff
1995219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
1996219820Sjeff		return -EFAULT;
1997219820Sjeff
1998219820Sjeff	INIT_UDATA(&udata, buf + sizeof cmd,
1999219820Sjeff		   (unsigned long) cmd.response + sizeof resp,
2000219820Sjeff		   in_len - sizeof cmd, out_len - sizeof resp);
2001219820Sjeff
2002219820Sjeff	obj = kmalloc(sizeof *obj, GFP_KERNEL);
2003219820Sjeff	if (!obj)
2004219820Sjeff		return -ENOMEM;
2005219820Sjeff
2006219820Sjeff	init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, &srq_lock_key);
2007219820Sjeff	down_write(&obj->uobject.mutex);
2008219820Sjeff
2009219820Sjeff	pd  = idr_read_pd(cmd.pd_handle, file->ucontext);
2010219820Sjeff	if (!pd) {
2011219820Sjeff		ret = -EINVAL;
2012219820Sjeff		goto err;
2013219820Sjeff	}
2014219820Sjeff
2015219820Sjeff	attr.event_handler  = ib_uverbs_srq_event_handler;
2016219820Sjeff	attr.srq_context    = file;
2017219820Sjeff	attr.attr.max_wr    = cmd.max_wr;
2018219820Sjeff	attr.attr.max_sge   = cmd.max_sge;
2019219820Sjeff	attr.attr.srq_limit = cmd.srq_limit;
2020219820Sjeff
2021219820Sjeff	obj->events_reported     = 0;
2022219820Sjeff	INIT_LIST_HEAD(&obj->event_list);
2023219820Sjeff
2024219820Sjeff	srq = pd->device->create_srq(pd, &attr, &udata);
2025219820Sjeff	if (IS_ERR(srq)) {
2026219820Sjeff		ret = PTR_ERR(srq);
2027219820Sjeff		goto err_put;
2028219820Sjeff	}
2029219820Sjeff
2030219820Sjeff	srq->device    	   = pd->device;
2031219820Sjeff	srq->pd        	   = pd;
2032219820Sjeff	srq->uobject       = &obj->uobject;
2033219820Sjeff	srq->event_handler = attr.event_handler;
2034219820Sjeff	srq->srq_context   = attr.srq_context;
2035255932Salfred	srq->ext.xrc.cq = NULL;
2036255932Salfred	srq->ext.xrc.xrcd = NULL;
2037219820Sjeff	atomic_inc(&pd->usecnt);
2038219820Sjeff	atomic_set(&srq->usecnt, 0);
2039219820Sjeff
2040219820Sjeff	obj->uobject.object = srq;
2041219820Sjeff	ret = idr_add_uobj(&ib_uverbs_srq_idr, &obj->uobject);
2042219820Sjeff	if (ret)
2043219820Sjeff		goto err_destroy;
2044219820Sjeff
2045219820Sjeff	memset(&resp, 0, sizeof resp);
2046219820Sjeff	resp.srq_handle = obj->uobject.id;
2047219820Sjeff	resp.max_wr     = attr.attr.max_wr;
2048219820Sjeff	resp.max_sge    = attr.attr.max_sge;
2049219820Sjeff
2050219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
2051219820Sjeff			 &resp, sizeof resp)) {
2052219820Sjeff		ret = -EFAULT;
2053219820Sjeff		goto err_copy;
2054219820Sjeff	}
2055219820Sjeff
2056219820Sjeff	put_pd_read(pd);
2057219820Sjeff
2058219820Sjeff	mutex_lock(&file->mutex);
2059219820Sjeff	list_add_tail(&obj->uobject.list, &file->ucontext->srq_list);
2060219820Sjeff	mutex_unlock(&file->mutex);
2061219820Sjeff
2062219820Sjeff	obj->uobject.live = 1;
2063219820Sjeff
2064219820Sjeff	up_write(&obj->uobject.mutex);
2065219820Sjeff
2066219820Sjeff	return in_len;
2067219820Sjeff
2068219820Sjefferr_copy:
2069219820Sjeff	idr_remove_uobj(&ib_uverbs_srq_idr, &obj->uobject);
2070219820Sjeff
2071219820Sjefferr_destroy:
2072219820Sjeff	ib_destroy_srq(srq);
2073219820Sjeff
2074219820Sjefferr_put:
2075219820Sjeff	put_pd_read(pd);
2076219820Sjeff
2077219820Sjefferr:
2078219820Sjeff	put_uobj_write(&obj->uobject);
2079219820Sjeff	return ret;
2080219820Sjeff}
2081219820Sjeff
2082219820Sjeffssize_t ib_uverbs_create_xrc_srq(struct ib_uverbs_file *file,
2083219820Sjeff			     const char __user *buf, int in_len,
2084219820Sjeff			     int out_len)
2085219820Sjeff{
2086255932Salfred	struct ib_uverbs_create_xsrq  cmd;
2087219820Sjeff	struct ib_uverbs_create_srq_resp resp;
2088219820Sjeff	struct ib_udata			 udata;
2089219820Sjeff	struct ib_uevent_object		*obj;
2090219820Sjeff	struct ib_pd			*pd;
2091219820Sjeff	struct ib_srq			*srq;
2092219820Sjeff	struct ib_cq			*xrc_cq;
2093219820Sjeff	struct ib_xrcd			*xrcd;
2094219820Sjeff	struct ib_srq_init_attr		 attr;
2095219820Sjeff	struct ib_uobject		*xrcd_uobj;
2096219820Sjeff	int ret;
2097219820Sjeff
2098219820Sjeff	if (out_len < sizeof resp)
2099219820Sjeff		return -ENOSPC;
2100219820Sjeff
2101219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
2102219820Sjeff		return -EFAULT;
2103219820Sjeff
2104219820Sjeff	INIT_UDATA(&udata, buf + sizeof cmd,
2105219820Sjeff		   (unsigned long) cmd.response + sizeof resp,
2106219820Sjeff		   in_len - sizeof cmd, out_len - sizeof resp);
2107219820Sjeff
2108219820Sjeff	obj = kmalloc(sizeof *obj, GFP_KERNEL);
2109219820Sjeff	if (!obj)
2110219820Sjeff		return -ENOMEM;
2111219820Sjeff
2112219820Sjeff	init_uobj(&obj->uobject, cmd.user_handle, file->ucontext,
2113219820Sjeff		  &srq_lock_key);
2114219820Sjeff	down_write(&obj->uobject.mutex);
2115219820Sjeff
2116219820Sjeff	pd  = idr_read_pd(cmd.pd_handle, file->ucontext);
2117219820Sjeff	if (!pd) {
2118219820Sjeff		ret = -EINVAL;
2119219820Sjeff		goto err;
2120219820Sjeff	}
2121219820Sjeff
2122255932Salfred	xrc_cq  = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
2123219820Sjeff	if (!xrc_cq) {
2124219820Sjeff		ret = -EINVAL;
2125219820Sjeff		goto err_put_pd;
2126219820Sjeff	}
2127219820Sjeff
2128219820Sjeff	xrcd  = idr_read_xrcd(cmd.xrcd_handle, file->ucontext, &xrcd_uobj);
2129219820Sjeff	if (!xrcd) {
2130219820Sjeff		ret = -EINVAL;
2131219820Sjeff		goto err_put_cq;
2132219820Sjeff	}
2133219820Sjeff
2134219820Sjeff
2135219820Sjeff	attr.event_handler  = ib_uverbs_srq_event_handler;
2136219820Sjeff	attr.srq_context    = file;
2137219820Sjeff	attr.attr.max_wr    = cmd.max_wr;
2138219820Sjeff	attr.attr.max_sge   = cmd.max_sge;
2139219820Sjeff	attr.attr.srq_limit = cmd.srq_limit;
2140219820Sjeff
2141219820Sjeff	obj->events_reported     = 0;
2142219820Sjeff	INIT_LIST_HEAD(&obj->event_list);
2143219820Sjeff
2144219820Sjeff	srq = pd->device->create_xrc_srq(pd, xrc_cq, xrcd, &attr, &udata);
2145219820Sjeff	if (IS_ERR(srq)) {
2146219820Sjeff		ret = PTR_ERR(srq);
2147219820Sjeff		goto err_put;
2148219820Sjeff	}
2149219820Sjeff
2150219820Sjeff	srq->device	   = pd->device;
2151219820Sjeff	srq->pd		   = pd;
2152219820Sjeff	srq->uobject	   = &obj->uobject;
2153219820Sjeff	srq->event_handler = attr.event_handler;
2154219820Sjeff	srq->srq_context   = attr.srq_context;
2155255932Salfred	srq->ext.xrc.cq	   = xrc_cq;
2156255932Salfred	srq->ext.xrc.xrcd	   = xrcd;
2157219820Sjeff	atomic_inc(&pd->usecnt);
2158219820Sjeff	atomic_inc(&xrc_cq->usecnt);
2159219820Sjeff	atomic_inc(&xrcd->usecnt);
2160219820Sjeff
2161219820Sjeff	atomic_set(&srq->usecnt, 0);
2162219820Sjeff
2163219820Sjeff	obj->uobject.object = srq;
2164219820Sjeff	ret = idr_add_uobj(&ib_uverbs_srq_idr, &obj->uobject);
2165219820Sjeff	if (ret)
2166219820Sjeff		goto err_destroy;
2167219820Sjeff
2168219820Sjeff	memset(&resp, 0, sizeof resp);
2169219820Sjeff	resp.srq_handle	= obj->uobject.id;
2170219820Sjeff	resp.max_wr	= attr.attr.max_wr;
2171219820Sjeff	resp.max_sge	= attr.attr.max_sge;
2172219820Sjeff
2173219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
2174219820Sjeff			 &resp, sizeof resp)) {
2175219820Sjeff		ret = -EFAULT;
2176219820Sjeff		goto err_copy;
2177219820Sjeff	}
2178219820Sjeff
2179219820Sjeff	put_xrcd_read(xrcd_uobj);
2180219820Sjeff	put_cq_read(xrc_cq);
2181219820Sjeff	put_pd_read(pd);
2182219820Sjeff
2183219820Sjeff	mutex_lock(&file->mutex);
2184219820Sjeff	list_add_tail(&obj->uobject.list, &file->ucontext->srq_list);
2185219820Sjeff	mutex_unlock(&file->mutex);
2186219820Sjeff
2187219820Sjeff	obj->uobject.live = 1;
2188219820Sjeff
2189219820Sjeff	up_write(&obj->uobject.mutex);
2190219820Sjeff
2191219820Sjeff	return in_len;
2192219820Sjeff
2193219820Sjefferr_copy:
2194219820Sjeff	idr_remove_uobj(&ib_uverbs_srq_idr, &obj->uobject);
2195219820Sjeff
2196219820Sjefferr_destroy:
2197219820Sjeff	ib_destroy_srq(srq);
2198219820Sjeff
2199219820Sjefferr_put:
2200219820Sjeff	put_xrcd_read(xrcd_uobj);
2201219820Sjeff
2202219820Sjefferr_put_cq:
2203219820Sjeff	put_cq_read(xrc_cq);
2204219820Sjeff
2205219820Sjefferr_put_pd:
2206219820Sjeff	put_pd_read(pd);
2207219820Sjeff
2208219820Sjefferr:
2209219820Sjeff	put_uobj_write(&obj->uobject);
2210219820Sjeff	return ret;
2211219820Sjeff}
2212219820Sjeff
2213219820Sjeffssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
2214219820Sjeff			     const char __user *buf, int in_len,
2215219820Sjeff			     int out_len)
2216219820Sjeff{
2217219820Sjeff	struct ib_uverbs_modify_srq cmd;
2218219820Sjeff	struct ib_udata             udata;
2219219820Sjeff	struct ib_srq              *srq;
2220219820Sjeff	struct ib_srq_attr          attr;
2221219820Sjeff	int                         ret;
2222219820Sjeff
2223219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
2224219820Sjeff		return -EFAULT;
2225219820Sjeff
2226219820Sjeff	INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd,
2227219820Sjeff		   out_len);
2228219820Sjeff
2229219820Sjeff	srq = idr_read_srq(cmd.srq_handle, file->ucontext);
2230219820Sjeff	if (!srq)
2231219820Sjeff		return -EINVAL;
2232219820Sjeff
2233219820Sjeff	attr.max_wr    = cmd.max_wr;
2234219820Sjeff	attr.srq_limit = cmd.srq_limit;
2235219820Sjeff
2236219820Sjeff	ret = srq->device->modify_srq(srq, &attr, cmd.attr_mask, &udata);
2237219820Sjeff
2238219820Sjeff	put_srq_read(srq);
2239219820Sjeff
2240219820Sjeff	return ret ? ret : in_len;
2241219820Sjeff}
2242219820Sjeff
2243219820Sjeffssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file,
2244219820Sjeff			    const char __user *buf,
2245219820Sjeff			    int in_len, int out_len)
2246219820Sjeff{
2247219820Sjeff	struct ib_uverbs_query_srq      cmd;
2248219820Sjeff	struct ib_uverbs_query_srq_resp resp;
2249219820Sjeff	struct ib_srq_attr              attr;
2250219820Sjeff	struct ib_srq                   *srq;
2251219820Sjeff	int                             ret;
2252219820Sjeff
2253219820Sjeff	if (out_len < sizeof resp)
2254219820Sjeff		return -ENOSPC;
2255219820Sjeff
2256219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
2257219820Sjeff		return -EFAULT;
2258219820Sjeff
2259219820Sjeff	srq = idr_read_srq(cmd.srq_handle, file->ucontext);
2260219820Sjeff	if (!srq)
2261219820Sjeff		return -EINVAL;
2262219820Sjeff
2263219820Sjeff	ret = ib_query_srq(srq, &attr);
2264219820Sjeff
2265219820Sjeff	put_srq_read(srq);
2266219820Sjeff
2267219820Sjeff	if (ret)
2268219820Sjeff		return ret;
2269219820Sjeff
2270219820Sjeff	memset(&resp, 0, sizeof resp);
2271219820Sjeff
2272219820Sjeff	resp.max_wr    = attr.max_wr;
2273219820Sjeff	resp.max_sge   = attr.max_sge;
2274219820Sjeff	resp.srq_limit = attr.srq_limit;
2275219820Sjeff
2276219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
2277219820Sjeff			 &resp, sizeof resp))
2278219820Sjeff		return -EFAULT;
2279219820Sjeff
2280219820Sjeff	return in_len;
2281219820Sjeff}
2282219820Sjeff
2283219820Sjeffssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
2284219820Sjeff			      const char __user *buf, int in_len,
2285219820Sjeff			      int out_len)
2286219820Sjeff{
2287219820Sjeff	struct ib_uverbs_destroy_srq      cmd;
2288219820Sjeff	struct ib_uverbs_destroy_srq_resp resp;
2289219820Sjeff	struct ib_uobject		 *uobj;
2290219820Sjeff	struct ib_srq               	 *srq;
2291219820Sjeff	struct ib_uevent_object        	 *obj;
2292219820Sjeff	int                         	  ret = -EINVAL;
2293219820Sjeff
2294219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
2295219820Sjeff		return -EFAULT;
2296219820Sjeff
2297219820Sjeff	uobj = idr_write_uobj(&ib_uverbs_srq_idr, cmd.srq_handle, file->ucontext);
2298219820Sjeff	if (!uobj)
2299219820Sjeff		return -EINVAL;
2300219820Sjeff	srq = uobj->object;
2301219820Sjeff	obj = container_of(uobj, struct ib_uevent_object, uobject);
2302219820Sjeff
2303219820Sjeff	ret = ib_destroy_srq(srq);
2304219820Sjeff	if (!ret)
2305219820Sjeff		uobj->live = 0;
2306219820Sjeff
2307219820Sjeff	put_uobj_write(uobj);
2308219820Sjeff
2309219820Sjeff	if (ret)
2310219820Sjeff		return ret;
2311219820Sjeff
2312219820Sjeff	idr_remove_uobj(&ib_uverbs_srq_idr, uobj);
2313219820Sjeff
2314219820Sjeff	mutex_lock(&file->mutex);
2315219820Sjeff	list_del(&uobj->list);
2316219820Sjeff	mutex_unlock(&file->mutex);
2317219820Sjeff
2318219820Sjeff	ib_uverbs_release_uevent(file, obj);
2319219820Sjeff
2320219820Sjeff	memset(&resp, 0, sizeof resp);
2321219820Sjeff	resp.events_reported = obj->events_reported;
2322219820Sjeff
2323219820Sjeff	put_uobj(uobj);
2324219820Sjeff
2325219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
2326219820Sjeff			 &resp, sizeof resp))
2327219820Sjeff		ret = -EFAULT;
2328219820Sjeff
2329219820Sjeff	return ret ? ret : in_len;
2330219820Sjeff}
2331219820Sjeff
2332219820Sjeffstatic struct inode *xrc_file2inode(struct file *f)
2333219820Sjeff{
2334219820Sjeff	return f->f_dentry->d_inode;
2335219820Sjeff}
2336219820Sjeff
2337219820Sjeffstruct xrcd_table_entry {
2338219820Sjeff	struct rb_node node;
2339219820Sjeff	struct inode *inode;
2340219820Sjeff	struct ib_xrcd *xrcd;
2341219820Sjeff};
2342219820Sjeff
2343219820Sjeffstatic int xrcd_table_insert(struct ib_device *dev,
2344219820Sjeff			     struct inode *i_n,
2345219820Sjeff			     struct ib_xrcd *xrcd)
2346219820Sjeff{
2347219820Sjeff	struct xrcd_table_entry *entry, *scan;
2348219820Sjeff	struct rb_node **p = &dev->ib_uverbs_xrcd_table.rb_node;
2349219820Sjeff	struct rb_node *parent = NULL;
2350219820Sjeff
2351219820Sjeff	entry = kmalloc(sizeof(struct xrcd_table_entry), GFP_KERNEL);
2352219820Sjeff	if (!entry)
2353219820Sjeff		return -ENOMEM;
2354219820Sjeff
2355219820Sjeff	entry->inode = i_n;
2356219820Sjeff	entry->xrcd = xrcd;
2357219820Sjeff
2358219820Sjeff	while (*p) {
2359219820Sjeff		parent = *p;
2360219820Sjeff		scan = rb_entry(parent, struct xrcd_table_entry, node);
2361219820Sjeff
2362219820Sjeff		if (i_n < scan->inode)
2363219820Sjeff			p = &(*p)->rb_left;
2364219820Sjeff		else if (i_n > scan->inode)
2365219820Sjeff			p = &(*p)->rb_right;
2366219820Sjeff		else {
2367219820Sjeff			kfree(entry);
2368219820Sjeff			return -EEXIST;
2369219820Sjeff		}
2370219820Sjeff	}
2371219820Sjeff
2372219820Sjeff	rb_link_node(&entry->node, parent, p);
2373219820Sjeff	rb_insert_color(&entry->node, &dev->ib_uverbs_xrcd_table);
2374219820Sjeff	igrab(i_n);
2375219820Sjeff	return 0;
2376219820Sjeff}
2377219820Sjeff
2378219820Sjeffstatic struct xrcd_table_entry *xrcd_table_search(struct ib_device *dev,
2379219820Sjeff						   struct inode *i_n)
2380219820Sjeff{
2381219820Sjeff	struct xrcd_table_entry *scan;
2382219820Sjeff	struct rb_node **p = &dev->ib_uverbs_xrcd_table.rb_node;
2383219820Sjeff	struct rb_node *parent = NULL;
2384219820Sjeff
2385219820Sjeff	while (*p) {
2386219820Sjeff		parent = *p;
2387219820Sjeff		scan = rb_entry(parent, struct xrcd_table_entry, node);
2388219820Sjeff
2389219820Sjeff		if (i_n < scan->inode)
2390219820Sjeff			p = &(*p)->rb_left;
2391219820Sjeff		else if (i_n > scan->inode)
2392219820Sjeff			p = &(*p)->rb_right;
2393219820Sjeff		else
2394219820Sjeff			return scan;
2395219820Sjeff	}
2396219820Sjeff	return NULL;
2397219820Sjeff}
2398219820Sjeff
2399219820Sjeffstatic int find_xrcd(struct ib_device *dev, struct inode *i_n,
2400219820Sjeff		     struct ib_xrcd **xrcd)
2401219820Sjeff{
2402219820Sjeff	struct xrcd_table_entry *entry;
2403219820Sjeff
2404219820Sjeff	entry = xrcd_table_search(dev, i_n);
2405219820Sjeff	if (!entry)
2406219820Sjeff		return -EINVAL;
2407219820Sjeff
2408219820Sjeff	*xrcd = entry->xrcd;
2409219820Sjeff	return 0;
2410219820Sjeff}
2411219820Sjeff
2412219820Sjeff
2413219820Sjeffstatic void xrcd_table_delete(struct ib_device *dev,
2414219820Sjeff			      struct inode *i_n)
2415219820Sjeff{
2416219820Sjeff	struct xrcd_table_entry *entry = xrcd_table_search(dev, i_n);
2417219820Sjeff
2418219820Sjeff	if (entry) {
2419219820Sjeff		iput(i_n);
2420219820Sjeff		rb_erase(&entry->node, &dev->ib_uverbs_xrcd_table);
2421219820Sjeff		kfree(entry);
2422219820Sjeff	}
2423219820Sjeff}
2424219820Sjeff
2425219820Sjeffssize_t ib_uverbs_open_xrc_domain(struct ib_uverbs_file *file,
2426219820Sjeff				  const char __user *buf, int in_len,
2427219820Sjeff				  int out_len)
2428219820Sjeff{
2429219820Sjeff	struct ib_uverbs_open_xrc_domain cmd;
2430219820Sjeff	struct ib_uverbs_open_xrc_domain_resp resp;
2431219820Sjeff	struct ib_udata	udata;
2432219820Sjeff	struct ib_uobject *uobj;
2433219820Sjeff	struct ib_uxrcd_object         	*xrcd_uobj;
2434219820Sjeff	struct ib_xrcd			*xrcd = NULL;
2435219820Sjeff	struct file			*f = NULL;
2436219820Sjeff	struct inode			*inode = NULL;
2437219820Sjeff	int				 ret = 0;
2438219820Sjeff	int				 new_xrcd = 0;
2439219820Sjeff
2440219820Sjeff	if (out_len < sizeof resp)
2441219820Sjeff		return -ENOSPC;
2442219820Sjeff
2443219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
2444219820Sjeff		return -EFAULT;
2445219820Sjeff
2446219820Sjeff	INIT_UDATA(&udata, buf + sizeof cmd,
2447219820Sjeff		   (unsigned long) cmd.response + sizeof resp,
2448219820Sjeff		   in_len - sizeof cmd, out_len - sizeof resp);
2449219820Sjeff
2450219820Sjeff	mutex_lock(&file->device->ib_dev->xrcd_table_mutex);
2451219820Sjeff	if (cmd.fd != (u32) (-1)) {
2452219820Sjeff		/* search for file descriptor */
2453219820Sjeff		f = fget(cmd.fd);
2454219820Sjeff		if (!f) {
2455219820Sjeff			ret = -EBADF;
2456219820Sjeff			goto err_table_mutex_unlock;
2457219820Sjeff		}
2458219820Sjeff
2459219820Sjeff		inode = xrc_file2inode(f);
2460219820Sjeff		if (!inode) {
2461219820Sjeff			ret = -EBADF;
2462219820Sjeff			goto err_table_mutex_unlock;
2463219820Sjeff		}
2464219820Sjeff
2465219820Sjeff		ret = find_xrcd(file->device->ib_dev, inode, &xrcd);
2466219820Sjeff		if (ret && !(cmd.oflags & O_CREAT)) {
2467219820Sjeff			/* no file descriptor. Need CREATE flag */
2468219820Sjeff			ret = -EAGAIN;
2469219820Sjeff			goto err_table_mutex_unlock;
2470219820Sjeff		}
2471219820Sjeff
2472219820Sjeff		if (xrcd && cmd.oflags & O_EXCL) {
2473219820Sjeff			ret = -EINVAL;
2474219820Sjeff			goto err_table_mutex_unlock;
2475219820Sjeff		}
2476219820Sjeff	}
2477219820Sjeff
2478219820Sjeff	xrcd_uobj = kmalloc(sizeof *xrcd_uobj, GFP_KERNEL);
2479219820Sjeff	if (!xrcd_uobj) {
2480219820Sjeff		ret = -ENOMEM;
2481219820Sjeff		goto err_table_mutex_unlock;
2482219820Sjeff	}
2483219820Sjeff
2484219820Sjeff	uobj = &xrcd_uobj->uobject;
2485219820Sjeff	init_uobj(uobj, 0, file->ucontext, &pd_lock_key);
2486219820Sjeff	down_write(&uobj->mutex);
2487219820Sjeff
2488219820Sjeff	if (!xrcd) {
2489219820Sjeff		xrcd = file->device->ib_dev->alloc_xrcd(file->device->ib_dev,
2490219820Sjeff							file->ucontext, &udata);
2491219820Sjeff		if (IS_ERR(xrcd)) {
2492219820Sjeff			ret = PTR_ERR(xrcd);
2493219820Sjeff			goto err;
2494219820Sjeff		}
2495219820Sjeff		xrcd->uobject = (cmd.fd == -1) ? uobj : NULL;
2496219820Sjeff		xrcd->inode = inode;
2497219820Sjeff		xrcd->device  = file->device->ib_dev;
2498219820Sjeff		atomic_set(&xrcd->usecnt, 0);
2499219820Sjeff		new_xrcd = 1;
2500219820Sjeff	}
2501219820Sjeff
2502219820Sjeff	uobj->object = xrcd;
2503219820Sjeff	ret = idr_add_uobj(&ib_uverbs_xrc_domain_idr, uobj);
2504219820Sjeff	if (ret)
2505219820Sjeff		goto err_idr;
2506219820Sjeff
2507219820Sjeff	memset(&resp, 0, sizeof resp);
2508219820Sjeff	resp.xrcd_handle = uobj->id;
2509219820Sjeff
2510219820Sjeff	if (inode) {
2511219820Sjeff		if (new_xrcd) {
2512219820Sjeff		/* create new inode/xrcd table entry */
2513219820Sjeff			ret = xrcd_table_insert(file->device->ib_dev, inode, xrcd);
2514219820Sjeff			if (ret)
2515219820Sjeff				goto err_insert_xrcd;
2516219820Sjeff		}
2517219820Sjeff		atomic_inc(&xrcd->usecnt);
2518219820Sjeff	}
2519219820Sjeff	if (f)
2520219820Sjeff		fput(f);
2521219820Sjeff
2522219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
2523219820Sjeff			 &resp, sizeof resp)) {
2524219820Sjeff		ret = -EFAULT;
2525219820Sjeff		goto err_copy;
2526219820Sjeff	}
2527219820Sjeff
2528219820Sjeff	INIT_LIST_HEAD(&xrcd_uobj->xrc_reg_qp_list);
2529219820Sjeff
2530219820Sjeff	mutex_lock(&file->mutex);
2531255932Salfred	list_add_tail(&uobj->list, &file->ucontext->xrcd_list);
2532219820Sjeff	mutex_unlock(&file->mutex);
2533219820Sjeff
2534219820Sjeff	uobj->live = 1;
2535219820Sjeff
2536219820Sjeff	up_write(&uobj->mutex);
2537219820Sjeff
2538219820Sjeff	mutex_unlock(&file->device->ib_dev->xrcd_table_mutex);
2539219820Sjeff	return in_len;
2540219820Sjeff
2541219820Sjefferr_copy:
2542219820Sjeff
2543219820Sjeff	if (inode) {
2544219820Sjeff		if (new_xrcd)
2545219820Sjeff			xrcd_table_delete(file->device->ib_dev, inode);
2546219820Sjeff		atomic_dec(&xrcd->usecnt);
2547219820Sjeff	}
2548219820Sjeff
2549219820Sjefferr_insert_xrcd:
2550219820Sjeff	idr_remove_uobj(&ib_uverbs_xrc_domain_idr, uobj);
2551219820Sjeff
2552219820Sjefferr_idr:
2553219820Sjeff	ib_dealloc_xrcd(xrcd);
2554219820Sjeff
2555219820Sjefferr:
2556219820Sjeff	put_uobj_write(uobj);
2557219820Sjeff
2558219820Sjefferr_table_mutex_unlock:
2559219820Sjeff
2560219820Sjeff	if (f)
2561219820Sjeff		fput(f);
2562219820Sjeff	mutex_unlock(&file->device->ib_dev->xrcd_table_mutex);
2563219820Sjeff	return ret;
2564219820Sjeff}
2565219820Sjeff
2566219820Sjeffssize_t ib_uverbs_close_xrc_domain(struct ib_uverbs_file *file,
2567219820Sjeff				   const char __user *buf, int in_len,
2568219820Sjeff				   int out_len)
2569219820Sjeff{
2570219820Sjeff	struct ib_uverbs_close_xrc_domain cmd;
2571219820Sjeff	struct ib_uobject *uobj, *t_uobj;
2572219820Sjeff	struct ib_uxrcd_object *xrcd_uobj;
2573219820Sjeff	struct ib_xrcd *xrcd = NULL;
2574219820Sjeff	struct inode *inode = NULL;
2575219820Sjeff	int ret = 0;
2576219820Sjeff
2577219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
2578219820Sjeff		return -EFAULT;
2579219820Sjeff
2580219820Sjeff	mutex_lock(&file->device->ib_dev->xrcd_table_mutex);
2581219820Sjeff	uobj = idr_write_uobj(&ib_uverbs_xrc_domain_idr, cmd.xrcd_handle,
2582219820Sjeff			      file->ucontext);
2583219820Sjeff	if (!uobj) {
2584219820Sjeff		ret = -EINVAL;
2585219820Sjeff		goto err_unlock_mutex;
2586219820Sjeff	}
2587219820Sjeff
2588219820Sjeff	mutex_lock(&file->mutex);
2589219820Sjeff	if (!ret) {
2590219820Sjeff		list_for_each_entry(t_uobj, &file->ucontext->qp_list, list) {
2591219820Sjeff			struct ib_qp *qp = t_uobj->object;
2592219820Sjeff			if (qp->xrcd && qp->xrcd == uobj->object) {
2593219820Sjeff				ret = -EBUSY;
2594219820Sjeff				break;
2595219820Sjeff			}
2596219820Sjeff		}
2597219820Sjeff	}
2598219820Sjeff	if (!ret) {
2599219820Sjeff		list_for_each_entry(t_uobj, &file->ucontext->srq_list, list) {
2600219820Sjeff			struct ib_srq *srq = t_uobj->object;
2601255932Salfred			if (srq->ext.xrc.xrcd && srq->ext.xrc.xrcd == uobj->object) {
2602219820Sjeff				ret = -EBUSY;
2603219820Sjeff				break;
2604219820Sjeff			}
2605219820Sjeff		}
2606219820Sjeff	}
2607219820Sjeff	mutex_unlock(&file->mutex);
2608219820Sjeff	if (ret) {
2609219820Sjeff		put_uobj_write(uobj);
2610219820Sjeff		goto err_unlock_mutex;
2611219820Sjeff	}
2612219820Sjeff
2613219820Sjeff	xrcd_uobj = container_of(uobj, struct ib_uxrcd_object, uobject);
2614219820Sjeff	if (!list_empty(&xrcd_uobj->xrc_reg_qp_list)) {
2615219820Sjeff		ret = -EBUSY;
2616219820Sjeff		put_uobj_write(uobj);
2617219820Sjeff		goto err_unlock_mutex;
2618219820Sjeff	}
2619219820Sjeff
2620219820Sjeff	xrcd = (struct ib_xrcd *) (uobj->object);
2621219820Sjeff	inode = xrcd->inode;
2622219820Sjeff
2623219820Sjeff	if (inode)
2624219820Sjeff		atomic_dec(&xrcd->usecnt);
2625219820Sjeff
2626219820Sjeff	ret = ib_dealloc_xrcd(uobj->object);
2627219820Sjeff	if (!ret)
2628219820Sjeff		uobj->live = 0;
2629219820Sjeff
2630219820Sjeff	put_uobj_write(uobj);
2631219820Sjeff
2632219820Sjeff	if (ret && !inode)
2633219820Sjeff		goto err_unlock_mutex;
2634219820Sjeff
2635219820Sjeff	if (!ret && inode)
2636219820Sjeff		xrcd_table_delete(file->device->ib_dev, inode);
2637219820Sjeff
2638219820Sjeff	idr_remove_uobj(&ib_uverbs_xrc_domain_idr, uobj);
2639219820Sjeff
2640219820Sjeff	mutex_lock(&file->mutex);
2641219820Sjeff	list_del(&uobj->list);
2642219820Sjeff	mutex_unlock(&file->mutex);
2643219820Sjeff
2644219820Sjeff	put_uobj(uobj);
2645219820Sjeff
2646219820Sjeff	mutex_unlock(&file->device->ib_dev->xrcd_table_mutex);
2647219820Sjeff	return in_len;
2648219820Sjeff
2649219820Sjefferr_unlock_mutex:
2650219820Sjeff	mutex_unlock(&file->device->ib_dev->xrcd_table_mutex);
2651219820Sjeff	return ret;
2652219820Sjeff}
2653219820Sjeff
2654219820Sjeffvoid ib_uverbs_dealloc_xrcd(struct ib_device *ib_dev,
2655219820Sjeff			    struct ib_xrcd *xrcd)
2656219820Sjeff{
2657219820Sjeff	struct inode *inode = NULL;
2658219820Sjeff	int ret = 0;
2659219820Sjeff
2660219820Sjeff	inode = xrcd->inode;
2661219820Sjeff	if (inode)
2662219820Sjeff		atomic_dec(&xrcd->usecnt);
2663219820Sjeff
2664219820Sjeff	ret = ib_dealloc_xrcd(xrcd);
2665219820Sjeff	if (!ret && inode)
2666219820Sjeff		xrcd_table_delete(ib_dev, inode);
2667219820Sjeff}
2668219820Sjeff
2669219820Sjeffssize_t ib_uverbs_create_xrc_rcv_qp(struct ib_uverbs_file *file,
2670219820Sjeff				    const char __user *buf, int in_len,
2671219820Sjeff				    int out_len)
2672219820Sjeff{
2673219820Sjeff	struct ib_uverbs_create_xrc_rcv_qp	cmd;
2674219820Sjeff	struct ib_uverbs_create_xrc_rcv_qp_resp resp;
2675219820Sjeff	struct ib_uxrc_rcv_object      *obj;
2676219820Sjeff	struct ib_qp_init_attr		init_attr;
2677219820Sjeff	struct ib_xrcd		       *xrcd;
2678219820Sjeff	struct ib_uobject	       *uobj;
2679219820Sjeff	struct ib_uxrcd_object	       *xrcd_uobj;
2680219820Sjeff	u32				qp_num;
2681219820Sjeff	int				err;
2682219820Sjeff
2683219820Sjeff	if (out_len < sizeof resp)
2684219820Sjeff		return -ENOSPC;
2685219820Sjeff
2686219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
2687219820Sjeff		return -EFAULT;
2688219820Sjeff
2689219820Sjeff	obj = kzalloc(sizeof *obj, GFP_KERNEL);
2690219820Sjeff	if (!obj)
2691219820Sjeff		return -ENOMEM;
2692219820Sjeff
2693219820Sjeff	xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj);
2694219820Sjeff	if (!xrcd) {
2695219820Sjeff		err = -EINVAL;
2696219820Sjeff		goto err_out;
2697219820Sjeff	}
2698219820Sjeff
2699219820Sjeff	init_attr.event_handler = ib_uverbs_xrc_rcv_qp_event_handler;
2700219820Sjeff	init_attr.qp_context	= file;
2701219820Sjeff	init_attr.srq		= NULL;
2702219820Sjeff	init_attr.sq_sig_type	=
2703219820Sjeff		cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
2704219820Sjeff	init_attr.qp_type	= IB_QPT_XRC;
2705255932Salfred	init_attr.xrcd	= xrcd;
2706219820Sjeff
2707219820Sjeff	init_attr.cap.max_send_wr	= 1;
2708219820Sjeff	init_attr.cap.max_recv_wr	= 0;
2709219820Sjeff	init_attr.cap.max_send_sge	= 1;
2710219820Sjeff	init_attr.cap.max_recv_sge	= 0;
2711219820Sjeff	init_attr.cap.max_inline_data	= 0;
2712219820Sjeff
2713219820Sjeff	err = xrcd->device->create_xrc_rcv_qp(&init_attr, &qp_num);
2714219820Sjeff	if (err)
2715219820Sjeff		goto err_put;
2716219820Sjeff
2717219820Sjeff	memset(&resp, 0, sizeof resp);
2718219820Sjeff	resp.qpn = qp_num;
2719219820Sjeff
2720219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
2721219820Sjeff			 &resp, sizeof resp)) {
2722219820Sjeff		err = -EFAULT;
2723219820Sjeff		goto err_destroy;
2724219820Sjeff	}
2725219820Sjeff
2726219820Sjeff	atomic_inc(&xrcd->usecnt);
2727219820Sjeff	put_xrcd_read(uobj);
2728219820Sjeff	obj->qp_num = qp_num;
2729219820Sjeff	obj->domain_handle = cmd.xrc_domain_handle;
2730219820Sjeff	xrcd_uobj = container_of(uobj, struct ib_uxrcd_object, uobject);
2731219820Sjeff	mutex_lock(&file->device->ib_dev->xrcd_table_mutex);
2732219820Sjeff	list_add_tail(&obj->list, &xrcd_uobj->xrc_reg_qp_list);
2733219820Sjeff	mutex_unlock(&file->device->ib_dev->xrcd_table_mutex);
2734219820Sjeff
2735219820Sjeff	return in_len;
2736219820Sjeff
2737219820Sjefferr_destroy:
2738219820Sjeff	xrcd->device->unreg_xrc_rcv_qp(xrcd, file, qp_num);
2739219820Sjefferr_put:
2740219820Sjeff	put_xrcd_read(uobj);
2741219820Sjefferr_out:
2742219820Sjeff	kfree(obj);
2743219820Sjeff	return err;
2744219820Sjeff}
2745219820Sjeff
2746219820Sjeffssize_t ib_uverbs_modify_xrc_rcv_qp(struct ib_uverbs_file *file,
2747219820Sjeff				    const char __user *buf, int in_len,
2748219820Sjeff				    int out_len)
2749219820Sjeff{
2750219820Sjeff	struct ib_uverbs_modify_xrc_rcv_qp      cmd;
2751219820Sjeff	struct ib_qp_attr	       *attr;
2752219820Sjeff	struct ib_xrcd		       *xrcd;
2753219820Sjeff	struct ib_uobject	       *uobj;
2754219820Sjeff	int				err;
2755219820Sjeff
2756219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
2757219820Sjeff		return -EFAULT;
2758219820Sjeff
2759219820Sjeff	attr = kzalloc(sizeof *attr, GFP_KERNEL);
2760219820Sjeff	if (!attr)
2761219820Sjeff		return -ENOMEM;
2762219820Sjeff
2763219820Sjeff	xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj);
2764219820Sjeff	if (!xrcd) {
2765219820Sjeff		kfree(attr);
2766219820Sjeff		return -EINVAL;
2767219820Sjeff	}
2768219820Sjeff
2769219820Sjeff	attr->qp_state		  = cmd.qp_state;
2770219820Sjeff	attr->cur_qp_state	  = cmd.cur_qp_state;
2771219820Sjeff	attr->qp_access_flags	  = cmd.qp_access_flags;
2772219820Sjeff	attr->pkey_index	  = cmd.pkey_index;
2773219820Sjeff	attr->port_num		  = cmd.port_num;
2774219820Sjeff	attr->path_mtu		  = cmd.path_mtu;
2775219820Sjeff	attr->path_mig_state	  = cmd.path_mig_state;
2776219820Sjeff	attr->qkey		  = cmd.qkey;
2777219820Sjeff	attr->rq_psn		  = cmd.rq_psn;
2778219820Sjeff	attr->sq_psn		  = cmd.sq_psn;
2779219820Sjeff	attr->dest_qp_num	  = cmd.dest_qp_num;
2780219820Sjeff	attr->alt_pkey_index	  = cmd.alt_pkey_index;
2781219820Sjeff	attr->en_sqd_async_notify = cmd.en_sqd_async_notify;
2782219820Sjeff	attr->max_rd_atomic	  = cmd.max_rd_atomic;
2783219820Sjeff	attr->max_dest_rd_atomic  = cmd.max_dest_rd_atomic;
2784219820Sjeff	attr->min_rnr_timer	  = cmd.min_rnr_timer;
2785219820Sjeff	attr->port_num		  = cmd.port_num;
2786219820Sjeff	attr->timeout		  = cmd.timeout;
2787219820Sjeff	attr->retry_cnt		  = cmd.retry_cnt;
2788219820Sjeff	attr->rnr_retry		  = cmd.rnr_retry;
2789219820Sjeff	attr->alt_port_num	  = cmd.alt_port_num;
2790219820Sjeff	attr->alt_timeout	  = cmd.alt_timeout;
2791219820Sjeff
2792219820Sjeff	memcpy(attr->ah_attr.grh.dgid.raw, cmd.dest.dgid, 16);
2793219820Sjeff	attr->ah_attr.grh.flow_label	    = cmd.dest.flow_label;
2794219820Sjeff	attr->ah_attr.grh.sgid_index	    = cmd.dest.sgid_index;
2795219820Sjeff	attr->ah_attr.grh.hop_limit	    = cmd.dest.hop_limit;
2796219820Sjeff	attr->ah_attr.grh.traffic_class	    = cmd.dest.traffic_class;
2797219820Sjeff	attr->ah_attr.dlid		    = cmd.dest.dlid;
2798219820Sjeff	attr->ah_attr.sl		    = cmd.dest.sl;
2799219820Sjeff	attr->ah_attr.src_path_bits	    = cmd.dest.src_path_bits;
2800219820Sjeff	attr->ah_attr.static_rate	    = cmd.dest.static_rate;
2801219820Sjeff	attr->ah_attr.ah_flags		    = cmd.dest.is_global ? IB_AH_GRH : 0;
2802219820Sjeff	attr->ah_attr.port_num		    = cmd.dest.port_num;
2803219820Sjeff
2804219820Sjeff	memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd.alt_dest.dgid, 16);
2805219820Sjeff	attr->alt_ah_attr.grh.flow_label    = cmd.alt_dest.flow_label;
2806219820Sjeff	attr->alt_ah_attr.grh.sgid_index    = cmd.alt_dest.sgid_index;
2807219820Sjeff	attr->alt_ah_attr.grh.hop_limit     = cmd.alt_dest.hop_limit;
2808219820Sjeff	attr->alt_ah_attr.grh.traffic_class = cmd.alt_dest.traffic_class;
2809219820Sjeff	attr->alt_ah_attr.dlid		    = cmd.alt_dest.dlid;
2810219820Sjeff	attr->alt_ah_attr.sl		    = cmd.alt_dest.sl;
2811219820Sjeff	attr->alt_ah_attr.src_path_bits	    = cmd.alt_dest.src_path_bits;
2812219820Sjeff	attr->alt_ah_attr.static_rate	    = cmd.alt_dest.static_rate;
2813219820Sjeff	attr->alt_ah_attr.ah_flags	    = cmd.alt_dest.is_global ? IB_AH_GRH : 0;
2814219820Sjeff	attr->alt_ah_attr.port_num	    = cmd.alt_dest.port_num;
2815219820Sjeff
2816219820Sjeff	err = xrcd->device->modify_xrc_rcv_qp(xrcd, cmd.qp_num, attr, cmd.attr_mask);
2817219820Sjeff	put_xrcd_read(uobj);
2818219820Sjeff	kfree(attr);
2819219820Sjeff	return err ? err : in_len;
2820219820Sjeff}
2821219820Sjeff
2822219820Sjeffssize_t ib_uverbs_query_xrc_rcv_qp(struct ib_uverbs_file *file,
2823219820Sjeff				   const char __user *buf, int in_len,
2824219820Sjeff				   int out_len)
2825219820Sjeff{
2826219820Sjeff	struct ib_uverbs_query_xrc_rcv_qp cmd;
2827219820Sjeff	struct ib_uverbs_query_qp_resp	 resp;
2828219820Sjeff	struct ib_qp_attr		*attr;
2829219820Sjeff	struct ib_qp_init_attr		*init_attr;
2830219820Sjeff	struct ib_xrcd			*xrcd;
2831219820Sjeff	struct ib_uobject		*uobj;
2832219820Sjeff	int				 ret;
2833219820Sjeff
2834219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
2835219820Sjeff		return -EFAULT;
2836219820Sjeff
2837219820Sjeff	attr      = kmalloc(sizeof *attr, GFP_KERNEL);
2838219820Sjeff	init_attr = kmalloc(sizeof *init_attr, GFP_KERNEL);
2839219820Sjeff	if (!attr || !init_attr) {
2840219820Sjeff		ret = -ENOMEM;
2841219820Sjeff		goto out;
2842219820Sjeff	}
2843219820Sjeff
2844219820Sjeff	xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj);
2845219820Sjeff	if (!xrcd) {
2846219820Sjeff		ret = -EINVAL;
2847219820Sjeff		goto out;
2848219820Sjeff	}
2849219820Sjeff
2850219820Sjeff	ret = xrcd->device->query_xrc_rcv_qp(xrcd, cmd.qp_num, attr,
2851219820Sjeff					     cmd.attr_mask, init_attr);
2852219820Sjeff
2853219820Sjeff	put_xrcd_read(uobj);
2854219820Sjeff
2855219820Sjeff	if (ret)
2856219820Sjeff		goto out;
2857219820Sjeff
2858219820Sjeff	memset(&resp, 0, sizeof resp);
2859219820Sjeff	resp.qp_state		    = attr->qp_state;
2860219820Sjeff	resp.cur_qp_state	    = attr->cur_qp_state;
2861219820Sjeff	resp.path_mtu		    = attr->path_mtu;
2862219820Sjeff	resp.path_mig_state	    = attr->path_mig_state;
2863219820Sjeff	resp.qkey		    = attr->qkey;
2864219820Sjeff	resp.rq_psn		    = attr->rq_psn;
2865219820Sjeff	resp.sq_psn		    = attr->sq_psn;
2866219820Sjeff	resp.dest_qp_num	    = attr->dest_qp_num;
2867219820Sjeff	resp.qp_access_flags	    = attr->qp_access_flags;
2868219820Sjeff	resp.pkey_index		    = attr->pkey_index;
2869219820Sjeff	resp.alt_pkey_index	    = attr->alt_pkey_index;
2870219820Sjeff	resp.sq_draining	    = attr->sq_draining;
2871219820Sjeff	resp.max_rd_atomic	    = attr->max_rd_atomic;
2872219820Sjeff	resp.max_dest_rd_atomic	    = attr->max_dest_rd_atomic;
2873219820Sjeff	resp.min_rnr_timer	    = attr->min_rnr_timer;
2874219820Sjeff	resp.port_num		    = attr->port_num;
2875219820Sjeff	resp.timeout		    = attr->timeout;
2876219820Sjeff	resp.retry_cnt		    = attr->retry_cnt;
2877219820Sjeff	resp.rnr_retry		    = attr->rnr_retry;
2878219820Sjeff	resp.alt_port_num	    = attr->alt_port_num;
2879219820Sjeff	resp.alt_timeout	    = attr->alt_timeout;
2880219820Sjeff
2881219820Sjeff	memcpy(resp.dest.dgid, attr->ah_attr.grh.dgid.raw, 16);
2882219820Sjeff	resp.dest.flow_label	    = attr->ah_attr.grh.flow_label;
2883219820Sjeff	resp.dest.sgid_index	    = attr->ah_attr.grh.sgid_index;
2884219820Sjeff	resp.dest.hop_limit	    = attr->ah_attr.grh.hop_limit;
2885219820Sjeff	resp.dest.traffic_class	    = attr->ah_attr.grh.traffic_class;
2886219820Sjeff	resp.dest.dlid		    = attr->ah_attr.dlid;
2887219820Sjeff	resp.dest.sl		    = attr->ah_attr.sl;
2888219820Sjeff	resp.dest.src_path_bits	    = attr->ah_attr.src_path_bits;
2889219820Sjeff	resp.dest.static_rate	    = attr->ah_attr.static_rate;
2890219820Sjeff	resp.dest.is_global	    = !!(attr->ah_attr.ah_flags & IB_AH_GRH);
2891219820Sjeff	resp.dest.port_num	    = attr->ah_attr.port_num;
2892219820Sjeff
2893219820Sjeff	memcpy(resp.alt_dest.dgid, attr->alt_ah_attr.grh.dgid.raw, 16);
2894219820Sjeff	resp.alt_dest.flow_label    = attr->alt_ah_attr.grh.flow_label;
2895219820Sjeff	resp.alt_dest.sgid_index    = attr->alt_ah_attr.grh.sgid_index;
2896219820Sjeff	resp.alt_dest.hop_limit     = attr->alt_ah_attr.grh.hop_limit;
2897219820Sjeff	resp.alt_dest.traffic_class = attr->alt_ah_attr.grh.traffic_class;
2898219820Sjeff	resp.alt_dest.dlid	    = attr->alt_ah_attr.dlid;
2899219820Sjeff	resp.alt_dest.sl	    = attr->alt_ah_attr.sl;
2900219820Sjeff	resp.alt_dest.src_path_bits = attr->alt_ah_attr.src_path_bits;
2901219820Sjeff	resp.alt_dest.static_rate   = attr->alt_ah_attr.static_rate;
2902219820Sjeff	resp.alt_dest.is_global	    = !!(attr->alt_ah_attr.ah_flags & IB_AH_GRH);
2903219820Sjeff	resp.alt_dest.port_num	    = attr->alt_ah_attr.port_num;
2904219820Sjeff
2905219820Sjeff	resp.max_send_wr	    = init_attr->cap.max_send_wr;
2906219820Sjeff	resp.max_recv_wr	    = init_attr->cap.max_recv_wr;
2907219820Sjeff	resp.max_send_sge	    = init_attr->cap.max_send_sge;
2908219820Sjeff	resp.max_recv_sge	    = init_attr->cap.max_recv_sge;
2909219820Sjeff	resp.max_inline_data	    = init_attr->cap.max_inline_data;
2910219820Sjeff	resp.sq_sig_all		    = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR;
2911219820Sjeff
2912219820Sjeff	if (copy_to_user((void __user *) (unsigned long) cmd.response,
2913219820Sjeff			 &resp, sizeof resp))
2914219820Sjeff		ret = -EFAULT;
2915219820Sjeff
2916219820Sjeffout:
2917219820Sjeff	kfree(attr);
2918219820Sjeff	kfree(init_attr);
2919219820Sjeff
2920219820Sjeff	return ret ? ret : in_len;
2921219820Sjeff}
2922219820Sjeff
2923219820Sjeffssize_t ib_uverbs_reg_xrc_rcv_qp(struct ib_uverbs_file *file,
2924219820Sjeff				 const char __user *buf, int in_len,
2925219820Sjeff				 int out_len)
2926219820Sjeff{
2927219820Sjeff	struct ib_uverbs_reg_xrc_rcv_qp  cmd;
2928219820Sjeff	struct ib_uxrc_rcv_object	*qp_obj, *tmp;
2929219820Sjeff	struct ib_xrcd			*xrcd;
2930219820Sjeff	struct ib_uobject		*uobj;
2931219820Sjeff	struct ib_uxrcd_object		*xrcd_uobj;
2932219820Sjeff	int				 ret;
2933219820Sjeff
2934219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
2935219820Sjeff		return -EFAULT;
2936219820Sjeff
2937219820Sjeff	qp_obj = kmalloc(sizeof *qp_obj, GFP_KERNEL);
2938219820Sjeff	if (!qp_obj)
2939219820Sjeff		return -ENOMEM;
2940219820Sjeff
2941219820Sjeff	xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj);
2942219820Sjeff	if (!xrcd) {
2943219820Sjeff		ret = -EINVAL;
2944219820Sjeff		goto err_out;
2945219820Sjeff	}
2946219820Sjeff
2947219820Sjeff	ret = xrcd->device->reg_xrc_rcv_qp(xrcd, file, cmd.qp_num);
2948219820Sjeff	if (ret)
2949219820Sjeff		goto err_put;
2950219820Sjeff
2951219820Sjeff	xrcd_uobj = container_of(uobj, struct ib_uxrcd_object, uobject);
2952219820Sjeff	mutex_lock(&file->device->ib_dev->xrcd_table_mutex);
2953219820Sjeff	list_for_each_entry(tmp, &xrcd_uobj->xrc_reg_qp_list, list)
2954219820Sjeff		if (cmd.qp_num == tmp->qp_num) {
2955219820Sjeff			kfree(qp_obj);
2956219820Sjeff			mutex_unlock(&file->device->ib_dev->xrcd_table_mutex);
2957219820Sjeff			put_xrcd_read(uobj);
2958219820Sjeff			return in_len;
2959219820Sjeff		}
2960219820Sjeff	qp_obj->qp_num = cmd.qp_num;
2961219820Sjeff	qp_obj->domain_handle = cmd.xrc_domain_handle;
2962219820Sjeff	list_add_tail(&qp_obj->list, &xrcd_uobj->xrc_reg_qp_list);
2963219820Sjeff	mutex_unlock(&file->device->ib_dev->xrcd_table_mutex);
2964219820Sjeff	atomic_inc(&xrcd->usecnt);
2965219820Sjeff	put_xrcd_read(uobj);
2966219820Sjeff	return in_len;
2967219820Sjeff
2968219820Sjefferr_put:
2969219820Sjeff	put_xrcd_read(uobj);
2970219820Sjefferr_out:
2971219820Sjeff
2972219820Sjeff	kfree(qp_obj);
2973219820Sjeff	return ret;
2974219820Sjeff}
2975219820Sjeff
2976219820Sjeffint ib_uverbs_cleanup_xrc_rcv_qp(struct ib_uverbs_file *file,
2977219820Sjeff				 struct ib_xrcd *xrcd, u32 qp_num)
2978219820Sjeff{
2979219820Sjeff	int err;
2980219820Sjeff	err = xrcd->device->unreg_xrc_rcv_qp(xrcd, file, qp_num);
2981219820Sjeff	if (!err)
2982219820Sjeff		atomic_dec(&xrcd->usecnt);
2983219820Sjeff	return err;
2984219820Sjeff}
2985219820Sjeff
2986219820Sjeffssize_t ib_uverbs_unreg_xrc_rcv_qp(struct ib_uverbs_file *file,
2987219820Sjeff				   const char __user *buf, int in_len,
2988219820Sjeff				   int out_len)
2989219820Sjeff{
2990219820Sjeff	struct ib_uverbs_unreg_xrc_rcv_qp cmd;
2991219820Sjeff	struct ib_uxrc_rcv_object *qp_obj, *tmp;
2992219820Sjeff	struct ib_xrcd *xrcd;
2993219820Sjeff	struct ib_uobject *uobj;
2994219820Sjeff	struct ib_uxrcd_object *xrcd_uobj;
2995219820Sjeff	int ret;
2996219820Sjeff
2997219820Sjeff	if (copy_from_user(&cmd, buf, sizeof cmd))
2998219820Sjeff		return -EFAULT;
2999219820Sjeff
3000219820Sjeff	xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj);
3001219820Sjeff	if (!xrcd)
3002219820Sjeff		return -EINVAL;
3003219820Sjeff
3004219820Sjeff	ret = xrcd->device->unreg_xrc_rcv_qp(xrcd, file, cmd.qp_num);
3005219820Sjeff	if (ret) {
3006219820Sjeff		put_xrcd_read(uobj);
3007219820Sjeff		return -EINVAL;
3008219820Sjeff	}
3009219820Sjeff	atomic_dec(&xrcd->usecnt);
3010219820Sjeff
3011219820Sjeff	xrcd_uobj = container_of(uobj, struct ib_uxrcd_object, uobject);
3012219820Sjeff	mutex_lock(&file->device->ib_dev->xrcd_table_mutex);
3013219820Sjeff	list_for_each_entry_safe(qp_obj, tmp, &xrcd_uobj->xrc_reg_qp_list, list)
3014219820Sjeff		if (cmd.qp_num == qp_obj->qp_num) {
3015219820Sjeff			list_del(&qp_obj->list);
3016219820Sjeff			kfree(qp_obj);
3017219820Sjeff			break;
3018219820Sjeff		}
3019219820Sjeff	mutex_unlock(&file->device->ib_dev->xrcd_table_mutex);
3020219820Sjeff	put_xrcd_read(uobj);
3021219820Sjeff	return in_len;
3022219820Sjeff}
3023