user_mad.c 34.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/*
 * Copyright (c) 2004 Topspin Communications.  All rights reserved.
R
Roland Dreier 已提交
3
 * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
4
 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
5
 * Copyright (c) 2008 Cisco. All rights reserved.
L
Linus Torvalds 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
 * General Public License (GPL) Version 2, available from the file
 * COPYING in the main directory of this source tree, or the
 * OpenIB.org BSD license below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

36 37
#define pr_fmt(fmt) "user_mad: " fmt

L
Linus Torvalds 已提交
38 39 40 41 42 43 44 45
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/dma-mapping.h>
#include <linux/poll.h>
46
#include <linux/mutex.h>
L
Linus Torvalds 已提交
47
#include <linux/kref.h>
48
#include <linux/compat.h>
49
#include <linux/sched.h>
50
#include <linux/semaphore.h>
51
#include <linux/slab.h>
L
Linus Torvalds 已提交
52

53
#include <linux/uaccess.h>
L
Linus Torvalds 已提交
54

55 56
#include <rdma/ib_mad.h>
#include <rdma/ib_user_mad.h>
L
Linus Torvalds 已提交
57 58 59 60 61 62 63 64 65 66 67 68 69

MODULE_AUTHOR("Roland Dreier");
MODULE_DESCRIPTION("InfiniBand userspace MAD packet access");
MODULE_LICENSE("Dual BSD/GPL");

enum {
	IB_UMAD_MAX_PORTS  = 64,
	IB_UMAD_MAX_AGENTS = 32,

	IB_UMAD_MAJOR      = 231,
	IB_UMAD_MINOR_BASE = 0
};

70
/*
A
Alexander Chiang 已提交
71 72 73
 * Our lifetime rules for these structs are the following:
 * device special file is opened, we take a reference on the
 * ib_umad_port's struct ib_umad_device. We drop these
74 75 76 77 78 79 80
 * references in the corresponding close().
 *
 * In addition to references coming from open character devices, there
 * is one more reference to each ib_umad_device representing the
 * module's reference taken when allocating the ib_umad_device in
 * ib_umad_add_one().
 *
A
Alexander Chiang 已提交
81
 * When destroying an ib_umad_device, we drop the module's reference.
82 83
 */

L
Linus Torvalds 已提交
84
struct ib_umad_port {
85
	struct cdev           cdev;
86
	struct device	      *dev;
L
Linus Torvalds 已提交
87

88
	struct cdev           sm_cdev;
89
	struct device	      *sm_dev;
L
Linus Torvalds 已提交
90 91
	struct semaphore       sm_sem;

92
	struct mutex	       file_mutex;
93 94
	struct list_head       file_list;

L
Linus Torvalds 已提交
95 96
	struct ib_device      *ib_dev;
	struct ib_umad_device *umad_dev;
97
	int                    dev_num;
L
Linus Torvalds 已提交
98 99 100 101
	u8                     port_num;
};

struct ib_umad_device {
102
	struct kobject       kobj;
L
Linus Torvalds 已提交
103 104 105 106
	struct ib_umad_port  port[0];
};

struct ib_umad_file {
107
	struct mutex		mutex;
108 109
	struct ib_umad_port    *port;
	struct list_head	recv_list;
110
	struct list_head	send_list;
111
	struct list_head	port_list;
112
	spinlock_t		send_lock;
113 114 115
	wait_queue_head_t	recv_wait;
	struct ib_mad_agent    *agent[IB_UMAD_MAX_AGENTS];
	int			agents_dead;
R
Roland Dreier 已提交
116 117
	u8			use_pkey_index;
	u8			already_used;
L
Linus Torvalds 已提交
118 119 120
};

struct ib_umad_packet {
121
	struct ib_mad_send_buf *msg;
122
	struct ib_mad_recv_wc  *recv_wc;
L
Linus Torvalds 已提交
123
	struct list_head   list;
124 125
	int		   length;
	struct ib_user_mad mad;
L
Linus Torvalds 已提交
126 127
};

128 129
static struct class *umad_class;

L
Linus Torvalds 已提交
130
static const dev_t base_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE);
131 132

static DEFINE_SPINLOCK(port_lock);
133
static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS);
L
Linus Torvalds 已提交
134 135

static void ib_umad_add_one(struct ib_device *device);
136
static void ib_umad_remove_one(struct ib_device *device, void *client_data);
L
Linus Torvalds 已提交
137

138
static void ib_umad_release_dev(struct kobject *kobj)
139 140
{
	struct ib_umad_device *dev =
141
		container_of(kobj, struct ib_umad_device, kobj);
142 143 144 145

	kfree(dev);
}

146 147 148 149
static struct kobj_type ib_umad_dev_ktype = {
	.release = ib_umad_release_dev,
};

R
Roland Dreier 已提交
150 151 152 153 154 155
static int hdr_size(struct ib_umad_file *file)
{
	return file->use_pkey_index ? sizeof (struct ib_user_mad_hdr) :
		sizeof (struct ib_user_mad_hdr_old);
}

156
/* caller must hold file->mutex */
157 158 159 160 161
static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id)
{
	return file->agents_dead ? NULL : file->agent[id];
}

L
Linus Torvalds 已提交
162 163 164 165 166 167
static int queue_packet(struct ib_umad_file *file,
			struct ib_mad_agent *agent,
			struct ib_umad_packet *packet)
{
	int ret = 1;

168
	mutex_lock(&file->mutex);
169

170 171 172
	for (packet->mad.hdr.id = 0;
	     packet->mad.hdr.id < IB_UMAD_MAX_AGENTS;
	     packet->mad.hdr.id++)
173
		if (agent == __get_agent(file, packet->mad.hdr.id)) {
L
Linus Torvalds 已提交
174 175 176 177 178 179
			list_add_tail(&packet->list, &file->recv_list);
			wake_up_interruptible(&file->recv_wait);
			ret = 0;
			break;
		}

180
	mutex_unlock(&file->mutex);
L
Linus Torvalds 已提交
181 182 183 184

	return ret;
}

185 186
static void dequeue_send(struct ib_umad_file *file,
			 struct ib_umad_packet *packet)
187
{
188 189 190
	spin_lock_irq(&file->send_lock);
	list_del(&packet->list);
	spin_unlock_irq(&file->send_lock);
191
}
192

L
Linus Torvalds 已提交
193 194 195 196
static void send_handler(struct ib_mad_agent *agent,
			 struct ib_mad_send_wc *send_wc)
{
	struct ib_umad_file *file = agent->context;
197
	struct ib_umad_packet *packet = send_wc->send_buf->context[0];
L
Linus Torvalds 已提交
198

199
	dequeue_send(file, packet);
200
	rdma_destroy_ah(packet->msg->ah);
201
	ib_free_send_mad(packet->msg);
L
Linus Torvalds 已提交
202 203

	if (send_wc->status == IB_WC_RESP_TIMEOUT_ERR) {
204 205 206 207
		packet->length = IB_MGMT_MAD_HDR;
		packet->mad.hdr.status = ETIMEDOUT;
		if (!queue_packet(file, agent, packet))
			return;
208
	}
L
Linus Torvalds 已提交
209 210 211 212
	kfree(packet);
}

static void recv_handler(struct ib_mad_agent *agent,
213
			 struct ib_mad_send_buf *send_buf,
L
Linus Torvalds 已提交
214 215 216 217 218 219
			 struct ib_mad_recv_wc *mad_recv_wc)
{
	struct ib_umad_file *file = agent->context;
	struct ib_umad_packet *packet;

	if (mad_recv_wc->wc->status != IB_WC_SUCCESS)
220
		goto err1;
L
Linus Torvalds 已提交
221

222
	packet = kzalloc(sizeof *packet, GFP_KERNEL);
L
Linus Torvalds 已提交
223
	if (!packet)
224
		goto err1;
L
Linus Torvalds 已提交
225

226 227
	packet->length = mad_recv_wc->mad_len;
	packet->recv_wc = mad_recv_wc;
L
Linus Torvalds 已提交
228

R
Roland Dreier 已提交
229 230 231
	packet->mad.hdr.status	   = 0;
	packet->mad.hdr.length	   = hdr_size(file) + mad_recv_wc->mad_len;
	packet->mad.hdr.qpn	   = cpu_to_be32(mad_recv_wc->wc->src_qp);
232 233 234 235 236 237 238 239 240 241
	/*
	 * On OPA devices it is okay to lose the upper 16 bits of LID as this
	 * information is obtained elsewhere. Mask off the upper 16 bits.
	 */
	if (agent->device->port_immutable[agent->port_num].core_cap_flags &
	    RDMA_CORE_PORT_INTEL_OPA)
		packet->mad.hdr.lid = ib_lid_be16(0xFFFF &
						  mad_recv_wc->wc->slid);
	else
		packet->mad.hdr.lid = ib_lid_be16(mad_recv_wc->wc->slid);
R
Roland Dreier 已提交
242 243 244
	packet->mad.hdr.sl	   = mad_recv_wc->wc->sl;
	packet->mad.hdr.path_bits  = mad_recv_wc->wc->dlid_path_bits;
	packet->mad.hdr.pkey_index = mad_recv_wc->wc->pkey_index;
245 246
	packet->mad.hdr.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH);
	if (packet->mad.hdr.grh_present) {
247
		struct rdma_ah_attr ah_attr;
248
		const struct ib_global_route *grh;
P
Parav Pandit 已提交
249 250
		int ret;

251 252 253 254
		ret = ib_init_ah_attr_from_wc(agent->device, agent->port_num,
					      mad_recv_wc->wc,
					      mad_recv_wc->recv_buf.grh,
					      &ah_attr);
P
Parav Pandit 已提交
255 256
		if (ret)
			goto err2;
257

258 259 260 261 262 263
		grh = rdma_ah_read_grh(&ah_attr);
		packet->mad.hdr.gid_index = grh->sgid_index;
		packet->mad.hdr.hop_limit = grh->hop_limit;
		packet->mad.hdr.traffic_class = grh->traffic_class;
		memcpy(packet->mad.hdr.gid, &grh->dgid, 16);
		packet->mad.hdr.flow_label = cpu_to_be32(grh->flow_label);
L
Linus Torvalds 已提交
264 265 266
	}

	if (queue_packet(file, agent, packet))
267 268
		goto err2;
	return;
L
Linus Torvalds 已提交
269

270 271 272
err2:
	kfree(packet);
err1:
L
Linus Torvalds 已提交
273 274 275
	ib_free_recv_mad(mad_recv_wc);
}

R
Roland Dreier 已提交
276 277
static ssize_t copy_recv_mad(struct ib_umad_file *file, char __user *buf,
			     struct ib_umad_packet *packet, size_t count)
278 279 280
{
	struct ib_mad_recv_buf *recv_buf;
	int left, seg_payload, offset, max_seg_payload;
I
Ira Weiny 已提交
281
	size_t seg_size;
282 283

	recv_buf = &packet->recv_wc->recv_buf;
I
Ira Weiny 已提交
284 285 286 287
	seg_size = packet->recv_wc->mad_seg_size;

	/* We need enough room to copy the first (or only) MAD segment. */
	if ((packet->length <= seg_size &&
R
Roland Dreier 已提交
288
	     count < hdr_size(file) + packet->length) ||
I
Ira Weiny 已提交
289 290
	    (packet->length > seg_size &&
	     count < hdr_size(file) + seg_size))
291 292
		return -EINVAL;

R
Roland Dreier 已提交
293
	if (copy_to_user(buf, &packet->mad, hdr_size(file)))
294 295
		return -EFAULT;

R
Roland Dreier 已提交
296
	buf += hdr_size(file);
I
Ira Weiny 已提交
297
	seg_payload = min_t(int, packet->length, seg_size);
298 299 300 301 302 303 304 305
	if (copy_to_user(buf, recv_buf->mad, seg_payload))
		return -EFAULT;

	if (seg_payload < packet->length) {
		/*
		 * Multipacket RMPP MAD message. Copy remainder of message.
		 * Note that last segment may have a shorter payload.
		 */
R
Roland Dreier 已提交
306
		if (count < hdr_size(file) + packet->length) {
307 308 309 310 311 312
			/*
			 * The buffer is too small, return the first RMPP segment,
			 * which includes the RMPP message length.
			 */
			return -ENOSPC;
		}
313
		offset = ib_get_mad_data_offset(recv_buf->mad->mad_hdr.mgmt_class);
I
Ira Weiny 已提交
314
		max_seg_payload = seg_size - offset;
315 316 317 318 319 320 321 322 323 324 325

		for (left = packet->length - seg_payload, buf += seg_payload;
		     left; left -= seg_payload, buf += seg_payload) {
			recv_buf = container_of(recv_buf->list.next,
						struct ib_mad_recv_buf, list);
			seg_payload = min(left, max_seg_payload);
			if (copy_to_user(buf, ((void *) recv_buf->mad) + offset,
					 seg_payload))
				return -EFAULT;
		}
	}
R
Roland Dreier 已提交
326
	return hdr_size(file) + packet->length;
327 328
}

R
Roland Dreier 已提交
329 330
static ssize_t copy_send_mad(struct ib_umad_file *file, char __user *buf,
			     struct ib_umad_packet *packet, size_t count)
331
{
R
Roland Dreier 已提交
332
	ssize_t size = hdr_size(file) + packet->length;
333 334 335 336

	if (count < size)
		return -EINVAL;

R
Roland Dreier 已提交
337 338 339 340 341 342
	if (copy_to_user(buf, &packet->mad, hdr_size(file)))
		return -EFAULT;

	buf += hdr_size(file);

	if (copy_to_user(buf, packet->mad.data, packet->length))
343 344 345 346 347
		return -EFAULT;

	return size;
}

L
Linus Torvalds 已提交
348 349 350 351 352 353 354
static ssize_t ib_umad_read(struct file *filp, char __user *buf,
			    size_t count, loff_t *pos)
{
	struct ib_umad_file *file = filp->private_data;
	struct ib_umad_packet *packet;
	ssize_t ret;

R
Roland Dreier 已提交
355
	if (count < hdr_size(file))
L
Linus Torvalds 已提交
356 357
		return -EINVAL;

358
	mutex_lock(&file->mutex);
L
Linus Torvalds 已提交
359 360

	while (list_empty(&file->recv_list)) {
361
		mutex_unlock(&file->mutex);
L
Linus Torvalds 已提交
362 363 364 365 366 367 368 369

		if (filp->f_flags & O_NONBLOCK)
			return -EAGAIN;

		if (wait_event_interruptible(file->recv_wait,
					     !list_empty(&file->recv_list)))
			return -ERESTARTSYS;

370
		mutex_lock(&file->mutex);
L
Linus Torvalds 已提交
371 372 373 374 375
	}

	packet = list_entry(file->recv_list.next, struct ib_umad_packet, list);
	list_del(&packet->list);

376
	mutex_unlock(&file->mutex);
L
Linus Torvalds 已提交
377

378
	if (packet->recv_wc)
R
Roland Dreier 已提交
379
		ret = copy_recv_mad(file, buf, packet, count);
L
Linus Torvalds 已提交
380
	else
R
Roland Dreier 已提交
381
		ret = copy_send_mad(file, buf, packet, count);
382

383 384
	if (ret < 0) {
		/* Requeue packet */
385
		mutex_lock(&file->mutex);
386
		list_add(&packet->list, &file->recv_list);
387
		mutex_unlock(&file->mutex);
388 389 390
	} else {
		if (packet->recv_wc)
			ib_free_recv_mad(packet->recv_wc);
391
		kfree(packet);
392
	}
L
Linus Torvalds 已提交
393 394 395
	return ret;
}

396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
static int copy_rmpp_mad(struct ib_mad_send_buf *msg, const char __user *buf)
{
	int left, seg;

	/* Copy class specific header */
	if ((msg->hdr_len > IB_MGMT_RMPP_HDR) &&
	    copy_from_user(msg->mad + IB_MGMT_RMPP_HDR, buf + IB_MGMT_RMPP_HDR,
			   msg->hdr_len - IB_MGMT_RMPP_HDR))
		return -EFAULT;

	/* All headers are in place.  Copy data segments. */
	for (seg = 1, left = msg->data_len, buf += msg->hdr_len; left > 0;
	     seg++, left -= msg->seg_size, buf += msg->seg_size) {
		if (copy_from_user(ib_get_rmpp_segment(msg, seg), buf,
				   min(left, msg->seg_size)))
			return -EFAULT;
	}
	return 0;
}

416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
static int same_destination(struct ib_user_mad_hdr *hdr1,
			    struct ib_user_mad_hdr *hdr2)
{
	if (!hdr1->grh_present && !hdr2->grh_present)
	   return (hdr1->lid == hdr2->lid);

	if (hdr1->grh_present && hdr2->grh_present)
	   return !memcmp(hdr1->gid, hdr2->gid, 16);

	return 0;
}

static int is_duplicate(struct ib_umad_file *file,
			struct ib_umad_packet *packet)
{
	struct ib_umad_packet *sent_packet;
	struct ib_mad_hdr *sent_hdr, *hdr;

	hdr = (struct ib_mad_hdr *) packet->mad.data;
	list_for_each_entry(sent_packet, &file->send_list, list) {
		sent_hdr = (struct ib_mad_hdr *) sent_packet->mad.data;

		if ((hdr->tid != sent_hdr->tid) ||
		    (hdr->mgmt_class != sent_hdr->mgmt_class))
			continue;

		/*
		 * No need to be overly clever here.  If two new operations have
		 * the same TID, reject the second as a duplicate.  This is more
		 * restrictive than required by the spec.
		 */
447 448
		if (!ib_response_mad(hdr)) {
			if (!ib_response_mad(sent_hdr))
449 450
				return 1;
			continue;
451
		} else if (!ib_response_mad(sent_hdr))
452 453 454 455 456 457 458 459 460
			continue;

		if (same_destination(&packet->mad.hdr, &sent_packet->mad.hdr))
			return 1;
	}

	return 0;
}

L
Linus Torvalds 已提交
461 462 463 464 465 466
static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
			     size_t count, loff_t *pos)
{
	struct ib_umad_file *file = filp->private_data;
	struct ib_umad_packet *packet;
	struct ib_mad_agent *agent;
467
	struct rdma_ah_attr ah_attr;
468
	struct ib_ah *ah;
469
	struct ib_rmpp_mad *rmpp_mad;
470
	__be64 *tid;
471
	int ret, data_len, hdr_len, copy_offset, rmpp_active;
I
Ira Weiny 已提交
472
	u8 base_version;
L
Linus Torvalds 已提交
473

R
Roland Dreier 已提交
474
	if (count < hdr_size(file) + IB_MGMT_RMPP_HDR)
L
Linus Torvalds 已提交
475 476
		return -EINVAL;

477
	packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);
L
Linus Torvalds 已提交
478 479 480
	if (!packet)
		return -ENOMEM;

R
Roland Dreier 已提交
481
	if (copy_from_user(&packet->mad, buf, hdr_size(file))) {
482 483
		ret = -EFAULT;
		goto err;
L
Linus Torvalds 已提交
484 485
	}

486
	if (packet->mad.hdr.id >= IB_UMAD_MAX_AGENTS) {
L
Linus Torvalds 已提交
487 488 489 490
		ret = -EINVAL;
		goto err;
	}

R
Roland Dreier 已提交
491 492 493 494 495 496 497
	buf += hdr_size(file);

	if (copy_from_user(packet->mad.data, buf, IB_MGMT_RMPP_HDR)) {
		ret = -EFAULT;
		goto err;
	}

498
	mutex_lock(&file->mutex);
L
Linus Torvalds 已提交
499

500
	agent = __get_agent(file, packet->mad.hdr.id);
L
Linus Torvalds 已提交
501 502 503 504 505 506
	if (!agent) {
		ret = -EINVAL;
		goto err_up;
	}

	memset(&ah_attr, 0, sizeof ah_attr);
507 508
	ah_attr.type = rdma_ah_find_type(file->port->ib_dev,
					 file->port->port_num);
509 510 511 512
	rdma_ah_set_dlid(&ah_attr, be16_to_cpu(packet->mad.hdr.lid));
	rdma_ah_set_sl(&ah_attr, packet->mad.hdr.sl);
	rdma_ah_set_path_bits(&ah_attr, packet->mad.hdr.path_bits);
	rdma_ah_set_port_num(&ah_attr, file->port->port_num);
513
	if (packet->mad.hdr.grh_present) {
514 515 516 517 518 519
		rdma_ah_set_grh(&ah_attr, NULL,
				be32_to_cpu(packet->mad.hdr.flow_label),
				packet->mad.hdr.gid_index,
				packet->mad.hdr.hop_limit,
				packet->mad.hdr.traffic_class);
		rdma_ah_set_dgid_raw(&ah_attr, packet->mad.hdr.gid);
L
Linus Torvalds 已提交
520 521
	}

522
	ah = rdma_create_user_ah(agent->qp->pd, &ah_attr, NULL);
523 524
	if (IS_ERR(ah)) {
		ret = PTR_ERR(ah);
L
Linus Torvalds 已提交
525 526 527
		goto err_up;
	}

528
	rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data;
529
	hdr_len = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class);
I
Ira Weiny 已提交
530 531 532

	if (ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class)
	    && ib_mad_kernel_rmpp_agent(agent)) {
533 534
		copy_offset = IB_MGMT_RMPP_HDR;
		rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
I
Ira Weiny 已提交
535 536 537 538
						IB_MGMT_RMPP_FLAG_ACTIVE;
	} else {
		copy_offset = IB_MGMT_MAD_HDR;
		rmpp_active = 0;
539 540
	}

I
Ira Weiny 已提交
541
	base_version = ((struct ib_mad_hdr *)&packet->mad.data)->base_version;
R
Roland Dreier 已提交
542
	data_len = count - hdr_size(file) - hdr_len;
543 544
	packet->msg = ib_create_send_mad(agent,
					 be32_to_cpu(packet->mad.hdr.qpn),
R
Roland Dreier 已提交
545
					 packet->mad.hdr.pkey_index, rmpp_active,
546
					 hdr_len, data_len, GFP_KERNEL,
I
Ira Weiny 已提交
547
					 base_version);
548 549 550 551
	if (IS_ERR(packet->msg)) {
		ret = PTR_ERR(packet->msg);
		goto err_ah;
	}
L
Linus Torvalds 已提交
552

A
Alexander Chiang 已提交
553
	packet->msg->ah		= ah;
554
	packet->msg->timeout_ms = packet->mad.hdr.timeout_ms;
A
Alexander Chiang 已提交
555
	packet->msg->retries	= packet->mad.hdr.retries;
556
	packet->msg->context[0] = packet;
L
Linus Torvalds 已提交
557

558
	/* Copy MAD header.  Any RMPP header is already in place. */
S
Sean Hefty 已提交
559
	memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR);
560 561 562 563 564 565 566 567 568 569 570 571

	if (!rmpp_active) {
		if (copy_from_user(packet->msg->mad + copy_offset,
				   buf + copy_offset,
				   hdr_len + data_len - copy_offset)) {
			ret = -EFAULT;
			goto err_msg;
		}
	} else {
		ret = copy_rmpp_mad(packet->msg, buf);
		if (ret)
			goto err_msg;
572 573 574
	}

	/*
575 576 577
	 * Set the high-order part of the transaction ID to make MADs from
	 * different agents unique, and allow routing responses back to the
	 * original requestor.
578
	 */
579
	if (!ib_response_mad(packet->msg->mad)) {
580
		tid = &((struct ib_mad_hdr *) packet->msg->mad)->tid;
581 582
		*tid = cpu_to_be64(((u64) agent->hi_tid) << 32 |
				   (be64_to_cpup(tid) & 0xffffffff));
583 584 585
		rmpp_mad->mad_hdr.tid = *tid;
	}

I
Ira Weiny 已提交
586 587 588 589
	if (!ib_mad_kernel_rmpp_agent(agent)
	   && ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class)
	   && (ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE)) {
		spin_lock_irq(&file->send_lock);
590
		list_add_tail(&packet->list, &file->send_list);
I
Ira Weiny 已提交
591 592 593 594 595 596 597 598 599 600 601
		spin_unlock_irq(&file->send_lock);
	} else {
		spin_lock_irq(&file->send_lock);
		ret = is_duplicate(file, packet);
		if (!ret)
			list_add_tail(&packet->list, &file->send_list);
		spin_unlock_irq(&file->send_lock);
		if (ret) {
			ret = -EINVAL;
			goto err_msg;
		}
L
Linus Torvalds 已提交
602 603
	}

604
	ret = ib_post_send_mad(packet->msg, NULL);
605
	if (ret)
606
		goto err_send;
607

608
	mutex_unlock(&file->mutex);
S
Sean Hefty 已提交
609
	return count;
610

611 612
err_send:
	dequeue_send(file, packet);
613 614 615
err_msg:
	ib_free_send_mad(packet->msg);
err_ah:
616
	rdma_destroy_ah(ah);
L
Linus Torvalds 已提交
617
err_up:
618
	mutex_unlock(&file->mutex);
L
Linus Torvalds 已提交
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
err:
	kfree(packet);
	return ret;
}

static unsigned int ib_umad_poll(struct file *filp, struct poll_table_struct *wait)
{
	struct ib_umad_file *file = filp->private_data;

	/* we will always be able to post a MAD send */
	unsigned int mask = POLLOUT | POLLWRNORM;

	poll_wait(filp, &file->recv_wait, wait);

	if (!list_empty(&file->recv_list))
		mask |= POLLIN | POLLRDNORM;

	return mask;
}

639 640
static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
			     int compat_method_mask)
L
Linus Torvalds 已提交
641 642 643
{
	struct ib_user_mad_reg_req ureq;
	struct ib_mad_reg_req req;
644
	struct ib_mad_agent *agent = NULL;
L
Linus Torvalds 已提交
645 646 647
	int agent_id;
	int ret;

648 649
	mutex_lock(&file->port->file_mutex);
	mutex_lock(&file->mutex);
650 651

	if (!file->port->ib_dev) {
652 653
		dev_notice(file->port->dev,
			   "ib_umad_reg_agent: invalid device\n");
654 655 656
		ret = -EPIPE;
		goto out;
	}
L
Linus Torvalds 已提交
657

658
	if (copy_from_user(&ureq, arg, sizeof ureq)) {
L
Linus Torvalds 已提交
659 660 661 662 663
		ret = -EFAULT;
		goto out;
	}

	if (ureq.qpn != 0 && ureq.qpn != 1) {
664 665 666
		dev_notice(file->port->dev,
			   "ib_umad_reg_agent: invalid QPN %d specified\n",
			   ureq.qpn);
L
Linus Torvalds 已提交
667 668 669 670 671
		ret = -EINVAL;
		goto out;
	}

	for (agent_id = 0; agent_id < IB_UMAD_MAX_AGENTS; ++agent_id)
672
		if (!__get_agent(file, agent_id))
L
Linus Torvalds 已提交
673 674
			goto found;

675 676 677
	dev_notice(file->port->dev,
		   "ib_umad_reg_agent: Max Agents (%u) reached\n",
		   IB_UMAD_MAX_AGENTS);
L
Linus Torvalds 已提交
678 679 680 681
	ret = -ENOMEM;
	goto out;

found:
682
	if (ureq.mgmt_class) {
683
		memset(&req, 0, sizeof(req));
684 685
		req.mgmt_class         = ureq.mgmt_class;
		req.mgmt_class_version = ureq.mgmt_class_version;
686 687 688 689 690 691 692 693 694 695 696 697
		memcpy(req.oui, ureq.oui, sizeof req.oui);

		if (compat_method_mask) {
			u32 *umm = (u32 *) ureq.method_mask;
			int i;

			for (i = 0; i < BITS_TO_LONGS(IB_MGMT_MAX_METHODS); ++i)
				req.method_mask[i] =
					umm[i * 2] | ((u64) umm[i * 2 + 1] << 32);
		} else
			memcpy(req.method_mask, ureq.method_mask,
			       sizeof req.method_mask);
698
	}
L
Linus Torvalds 已提交
699 700 701

	agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num,
				      ureq.qpn ? IB_QPT_GSI : IB_QPT_SMI,
702
				      ureq.mgmt_class ? &req : NULL,
703
				      ureq.rmpp_version,
704
				      send_handler, recv_handler, file, 0);
L
Linus Torvalds 已提交
705 706
	if (IS_ERR(agent)) {
		ret = PTR_ERR(agent);
707
		agent = NULL;
L
Linus Torvalds 已提交
708 709 710 711 712 713
		goto out;
	}

	if (put_user(agent_id,
		     (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) {
		ret = -EFAULT;
714
		goto out;
L
Linus Torvalds 已提交
715 716
	}

R
Roland Dreier 已提交
717 718 719
	if (!file->already_used) {
		file->already_used = 1;
		if (!file->use_pkey_index) {
720 721 722 723 724
			dev_warn(file->port->dev,
				"process %s did not enable P_Key index support.\n",
				current->comm);
			dev_warn(file->port->dev,
				"   Documentation/infiniband/user_mad.txt has info on the new ABI.\n");
R
Roland Dreier 已提交
725 726 727
		}
	}

728
	file->agent[agent_id] = agent;
L
Linus Torvalds 已提交
729
	ret = 0;
730

L
Linus Torvalds 已提交
731
out:
732 733 734 735 736 737 738
	mutex_unlock(&file->mutex);

	if (ret && agent)
		ib_unregister_mad_agent(agent);

	mutex_unlock(&file->port->file_mutex);

L
Linus Torvalds 已提交
739 740 741
	return ret;
}

742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
static int ib_umad_reg_agent2(struct ib_umad_file *file, void __user *arg)
{
	struct ib_user_mad_reg_req2 ureq;
	struct ib_mad_reg_req req;
	struct ib_mad_agent *agent = NULL;
	int agent_id;
	int ret;

	mutex_lock(&file->port->file_mutex);
	mutex_lock(&file->mutex);

	if (!file->port->ib_dev) {
		dev_notice(file->port->dev,
			   "ib_umad_reg_agent2: invalid device\n");
		ret = -EPIPE;
		goto out;
	}

	if (copy_from_user(&ureq, arg, sizeof(ureq))) {
		ret = -EFAULT;
		goto out;
	}

	if (ureq.qpn != 0 && ureq.qpn != 1) {
		dev_notice(file->port->dev,
			   "ib_umad_reg_agent2: invalid QPN %d specified\n",
			   ureq.qpn);
		ret = -EINVAL;
		goto out;
	}

	if (ureq.flags & ~IB_USER_MAD_REG_FLAGS_CAP) {
		dev_notice(file->port->dev,
			   "ib_umad_reg_agent2 failed: invalid registration flags specified 0x%x; supported 0x%x\n",
			   ureq.flags, IB_USER_MAD_REG_FLAGS_CAP);
		ret = -EINVAL;

		if (put_user((u32)IB_USER_MAD_REG_FLAGS_CAP,
				(u32 __user *) (arg + offsetof(struct
				ib_user_mad_reg_req2, flags))))
			ret = -EFAULT;

		goto out;
	}

	for (agent_id = 0; agent_id < IB_UMAD_MAX_AGENTS; ++agent_id)
		if (!__get_agent(file, agent_id))
			goto found;

	dev_notice(file->port->dev,
		   "ib_umad_reg_agent2: Max Agents (%u) reached\n",
		   IB_UMAD_MAX_AGENTS);
	ret = -ENOMEM;
	goto out;

found:
	if (ureq.mgmt_class) {
		memset(&req, 0, sizeof(req));
		req.mgmt_class         = ureq.mgmt_class;
		req.mgmt_class_version = ureq.mgmt_class_version;
		if (ureq.oui & 0xff000000) {
			dev_notice(file->port->dev,
				   "ib_umad_reg_agent2 failed: oui invalid 0x%08x\n",
				   ureq.oui);
			ret = -EINVAL;
			goto out;
		}
		req.oui[2] =  ureq.oui & 0x0000ff;
		req.oui[1] = (ureq.oui & 0x00ff00) >> 8;
		req.oui[0] = (ureq.oui & 0xff0000) >> 16;
		memcpy(req.method_mask, ureq.method_mask,
			sizeof(req.method_mask));
	}

	agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num,
				      ureq.qpn ? IB_QPT_GSI : IB_QPT_SMI,
				      ureq.mgmt_class ? &req : NULL,
				      ureq.rmpp_version,
				      send_handler, recv_handler, file,
				      ureq.flags);
	if (IS_ERR(agent)) {
		ret = PTR_ERR(agent);
		agent = NULL;
		goto out;
	}

	if (put_user(agent_id,
		     (u32 __user *)(arg +
				offsetof(struct ib_user_mad_reg_req2, id)))) {
		ret = -EFAULT;
		goto out;
	}

	if (!file->already_used) {
		file->already_used = 1;
		file->use_pkey_index = 1;
	}

	file->agent[agent_id] = agent;
	ret = 0;

out:
	mutex_unlock(&file->mutex);

	if (ret && agent)
		ib_unregister_mad_agent(agent);

	mutex_unlock(&file->port->file_mutex);

	return ret;
}


855
static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
L
Linus Torvalds 已提交
856
{
857
	struct ib_mad_agent *agent = NULL;
L
Linus Torvalds 已提交
858 859 860
	u32 id;
	int ret = 0;

861
	if (get_user(id, arg))
862
		return -EFAULT;
L
Linus Torvalds 已提交
863

864 865
	mutex_lock(&file->port->file_mutex);
	mutex_lock(&file->mutex);
L
Linus Torvalds 已提交
866

867
	if (id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {
L
Linus Torvalds 已提交
868 869 870 871
		ret = -EINVAL;
		goto out;
	}

872
	agent = file->agent[id];
L
Linus Torvalds 已提交
873 874 875
	file->agent[id] = NULL;

out:
876
	mutex_unlock(&file->mutex);
877

878
	if (agent)
879 880
		ib_unregister_mad_agent(agent);

881 882
	mutex_unlock(&file->port->file_mutex);

L
Linus Torvalds 已提交
883 884 885
	return ret;
}

R
Roland Dreier 已提交
886 887 888 889
static long ib_umad_enable_pkey(struct ib_umad_file *file)
{
	int ret = 0;

890
	mutex_lock(&file->mutex);
R
Roland Dreier 已提交
891 892 893 894
	if (file->already_used)
		ret = -EINVAL;
	else
		file->use_pkey_index = 1;
895
	mutex_unlock(&file->mutex);
R
Roland Dreier 已提交
896 897 898 899

	return ret;
}

900 901
static long ib_umad_ioctl(struct file *filp, unsigned int cmd,
			  unsigned long arg)
L
Linus Torvalds 已提交
902 903 904
{
	switch (cmd) {
	case IB_USER_MAD_REGISTER_AGENT:
905
		return ib_umad_reg_agent(filp->private_data, (void __user *) arg, 0);
L
Linus Torvalds 已提交
906
	case IB_USER_MAD_UNREGISTER_AGENT:
907
		return ib_umad_unreg_agent(filp->private_data, (__u32 __user *) arg);
R
Roland Dreier 已提交
908 909
	case IB_USER_MAD_ENABLE_PKEY:
		return ib_umad_enable_pkey(filp->private_data);
910 911
	case IB_USER_MAD_REGISTER_AGENT2:
		return ib_umad_reg_agent2(filp->private_data, (void __user *) arg);
L
Linus Torvalds 已提交
912 913 914 915 916
	default:
		return -ENOIOCTLCMD;
	}
}

917 918 919 920 921 922 923 924 925 926 927
#ifdef CONFIG_COMPAT
static long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd,
				 unsigned long arg)
{
	switch (cmd) {
	case IB_USER_MAD_REGISTER_AGENT:
		return ib_umad_reg_agent(filp->private_data, compat_ptr(arg), 1);
	case IB_USER_MAD_UNREGISTER_AGENT:
		return ib_umad_unreg_agent(filp->private_data, compat_ptr(arg));
	case IB_USER_MAD_ENABLE_PKEY:
		return ib_umad_enable_pkey(filp->private_data);
928 929
	case IB_USER_MAD_REGISTER_AGENT2:
		return ib_umad_reg_agent2(filp->private_data, compat_ptr(arg));
930 931 932 933 934 935
	default:
		return -ENOIOCTLCMD;
	}
}
#endif

936 937 938
/*
 * ib_umad_open() does not need the BKL:
 *
A
Alexander Chiang 已提交
939
 *  - the ib_umad_port structures are properly reference counted, and
940 941 942 943 944
 *    everything else is purely local to the file being created, so
 *    races against other open calls are not a problem;
 *  - the ioctl method does not affect any global state outside of the
 *    file structure being operated on;
 */
L
Linus Torvalds 已提交
945 946
static int ib_umad_open(struct inode *inode, struct file *filp)
{
947
	struct ib_umad_port *port;
L
Linus Torvalds 已提交
948
	struct ib_umad_file *file;
B
Bart Van Assche 已提交
949
	int ret = -ENXIO;
L
Linus Torvalds 已提交
950

A
Alexander Chiang 已提交
951
	port = container_of(inode->i_cdev, struct ib_umad_port, cdev);
952

953
	mutex_lock(&port->file_mutex);
954

B
Bart Van Assche 已提交
955
	if (!port->ib_dev)
956 957
		goto out;

B
Bart Van Assche 已提交
958
	ret = -ENOMEM;
S
Sean Hefty 已提交
959
	file = kzalloc(sizeof *file, GFP_KERNEL);
B
Bart Van Assche 已提交
960
	if (!file)
961
		goto out;
L
Linus Torvalds 已提交
962

963
	mutex_init(&file->mutex);
964
	spin_lock_init(&file->send_lock);
L
Linus Torvalds 已提交
965
	INIT_LIST_HEAD(&file->recv_list);
966
	INIT_LIST_HEAD(&file->send_list);
L
Linus Torvalds 已提交
967 968 969 970 971
	init_waitqueue_head(&file->recv_wait);

	file->port = port;
	filp->private_data = file;

972 973
	list_add_tail(&file->port_list, &port->file_list);

974
	ret = nonseekable_open(inode, filp);
B
Bart Van Assche 已提交
975 976 977 978 979 980
	if (ret) {
		list_del(&file->port_list);
		kfree(file);
		goto out;
	}

981
	kobject_get(&port->umad_dev->kobj);
982

983
out:
984
	mutex_unlock(&port->file_mutex);
985
	return ret;
L
Linus Torvalds 已提交
986 987 988 989 990
}

static int ib_umad_close(struct inode *inode, struct file *filp)
{
	struct ib_umad_file *file = filp->private_data;
991
	struct ib_umad_device *dev = file->port->umad_dev;
992
	struct ib_umad_packet *packet, *tmp;
993
	int already_dead;
L
Linus Torvalds 已提交
994 995
	int i;

996 997
	mutex_lock(&file->port->file_mutex);
	mutex_lock(&file->mutex);
998 999 1000

	already_dead = file->agents_dead;
	file->agents_dead = 1;
L
Linus Torvalds 已提交
1001

1002 1003 1004
	list_for_each_entry_safe(packet, tmp, &file->recv_list, list) {
		if (packet->recv_wc)
			ib_free_recv_mad(packet->recv_wc);
1005
		kfree(packet);
1006
	}
1007

1008 1009
	list_del(&file->port_list);

1010
	mutex_unlock(&file->mutex);
1011 1012 1013 1014 1015

	if (!already_dead)
		for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i)
			if (file->agent[i])
				ib_unregister_mad_agent(file->agent[i]);
L
Linus Torvalds 已提交
1016

1017
	mutex_unlock(&file->port->file_mutex);
1018 1019

	kfree(file);
1020
	kobject_put(&dev->kobj);
1021

L
Linus Torvalds 已提交
1022 1023 1024
	return 0;
}

1025
static const struct file_operations umad_fops = {
A
Alexander Chiang 已提交
1026 1027 1028 1029
	.owner		= THIS_MODULE,
	.read		= ib_umad_read,
	.write		= ib_umad_write,
	.poll		= ib_umad_poll,
L
Linus Torvalds 已提交
1030
	.unlocked_ioctl = ib_umad_ioctl,
1031
#ifdef CONFIG_COMPAT
A
Alexander Chiang 已提交
1032
	.compat_ioctl	= ib_umad_compat_ioctl,
1033
#endif
A
Alexander Chiang 已提交
1034
	.open		= ib_umad_open,
1035 1036
	.release	= ib_umad_close,
	.llseek		= no_llseek,
L
Linus Torvalds 已提交
1037 1038 1039 1040
};

static int ib_umad_sm_open(struct inode *inode, struct file *filp)
{
1041
	struct ib_umad_port *port;
L
Linus Torvalds 已提交
1042 1043 1044 1045 1046
	struct ib_port_modify props = {
		.set_port_cap_mask = IB_PORT_SM
	};
	int ret;

A
Alexander Chiang 已提交
1047
	port = container_of(inode->i_cdev, struct ib_umad_port, sm_cdev);
1048

L
Linus Torvalds 已提交
1049
	if (filp->f_flags & O_NONBLOCK) {
1050 1051 1052 1053
		if (down_trylock(&port->sm_sem)) {
			ret = -EAGAIN;
			goto fail;
		}
L
Linus Torvalds 已提交
1054
	} else {
1055 1056 1057 1058
		if (down_interruptible(&port->sm_sem)) {
			ret = -ERESTARTSYS;
			goto fail;
		}
L
Linus Torvalds 已提交
1059 1060 1061
	}

	ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
B
Bart Van Assche 已提交
1062 1063
	if (ret)
		goto err_up_sem;
L
Linus Torvalds 已提交
1064 1065 1066

	filp->private_data = port;

B
Bart Van Assche 已提交
1067 1068 1069 1070
	ret = nonseekable_open(inode, filp);
	if (ret)
		goto err_clr_sm_cap;

1071
	kobject_get(&port->umad_dev->kobj);
B
Bart Van Assche 已提交
1072 1073 1074 1075 1076 1077 1078 1079 1080

	return 0;

err_clr_sm_cap:
	swap(props.set_port_cap_mask, props.clr_port_cap_mask);
	ib_modify_port(port->ib_dev, port->port_num, 0, &props);

err_up_sem:
	up(&port->sm_sem);
1081 1082 1083

fail:
	return ret;
L
Linus Torvalds 已提交
1084 1085 1086 1087 1088 1089 1090 1091
}

static int ib_umad_sm_close(struct inode *inode, struct file *filp)
{
	struct ib_umad_port *port = filp->private_data;
	struct ib_port_modify props = {
		.clr_port_cap_mask = IB_PORT_SM
	};
1092 1093
	int ret = 0;

1094
	mutex_lock(&port->file_mutex);
1095 1096
	if (port->ib_dev)
		ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
1097
	mutex_unlock(&port->file_mutex);
L
Linus Torvalds 已提交
1098 1099 1100

	up(&port->sm_sem);

1101
	kobject_put(&port->umad_dev->kobj);
1102

L
Linus Torvalds 已提交
1103 1104 1105
	return ret;
}

1106
static const struct file_operations umad_sm_fops = {
A
Alexander Chiang 已提交
1107 1108
	.owner	 = THIS_MODULE,
	.open	 = ib_umad_sm_open,
1109 1110
	.release = ib_umad_sm_close,
	.llseek	 = no_llseek,
L
Linus Torvalds 已提交
1111 1112 1113 1114 1115 1116 1117 1118
};

static struct ib_client umad_client = {
	.name   = "umad",
	.add    = ib_umad_add_one,
	.remove = ib_umad_remove_one
};

1119 1120
static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr,
			  char *buf)
L
Linus Torvalds 已提交
1121
{
1122
	struct ib_umad_port *port = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1123

1124 1125 1126
	if (!port)
		return -ENODEV;

L
Linus Torvalds 已提交
1127 1128
	return sprintf(buf, "%s\n", port->ib_dev->name);
}
1129
static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
L
Linus Torvalds 已提交
1130

1131 1132
static ssize_t show_port(struct device *dev, struct device_attribute *attr,
			 char *buf)
L
Linus Torvalds 已提交
1133
{
1134
	struct ib_umad_port *port = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1135

1136 1137 1138
	if (!port)
		return -ENODEV;

L
Linus Torvalds 已提交
1139 1140
	return sprintf(buf, "%d\n", port->port_num);
}
1141
static DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
L
Linus Torvalds 已提交
1142

1143 1144
static CLASS_ATTR_STRING(abi_version, S_IRUGO,
			 __stringify(IB_USER_MAD_ABI_VERSION));
L
Linus Torvalds 已提交
1145

1146 1147
static dev_t overflow_maj;
static DECLARE_BITMAP(overflow_map, IB_UMAD_MAX_PORTS);
1148
static int find_overflow_devnum(struct ib_device *device)
1149 1150 1151 1152 1153 1154 1155
{
	int ret;

	if (!overflow_maj) {
		ret = alloc_chrdev_region(&overflow_maj, 0, IB_UMAD_MAX_PORTS * 2,
					  "infiniband_mad");
		if (ret) {
1156 1157
			dev_err(&device->dev,
				"couldn't register dynamic device number\n");
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168
			return ret;
		}
	}

	ret = find_first_zero_bit(overflow_map, IB_UMAD_MAX_PORTS);
	if (ret >= IB_UMAD_MAX_PORTS)
		return -1;

	return ret;
}

L
Linus Torvalds 已提交
1169
static int ib_umad_init_port(struct ib_device *device, int port_num,
1170
			     struct ib_umad_device *umad_dev,
L
Linus Torvalds 已提交
1171 1172
			     struct ib_umad_port *port)
{
1173
	int devnum;
1174
	dev_t base;
1175

1176
	spin_lock(&port_lock);
1177 1178
	devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS);
	if (devnum >= IB_UMAD_MAX_PORTS) {
1179
		spin_unlock(&port_lock);
1180
		devnum = find_overflow_devnum(device);
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191
		if (devnum < 0)
			return -1;

		spin_lock(&port_lock);
		port->dev_num = devnum + IB_UMAD_MAX_PORTS;
		base = devnum + overflow_maj;
		set_bit(devnum, overflow_map);
	} else {
		port->dev_num = devnum;
		base = devnum + base_dev;
		set_bit(devnum, dev_map);
L
Linus Torvalds 已提交
1192
	}
1193
	spin_unlock(&port_lock);
L
Linus Torvalds 已提交
1194 1195 1196

	port->ib_dev   = device;
	port->port_num = port_num;
1197
	sema_init(&port->sm_sem, 1);
1198
	mutex_init(&port->file_mutex);
1199
	INIT_LIST_HEAD(&port->file_list);
L
Linus Torvalds 已提交
1200

1201 1202
	cdev_init(&port->cdev, &umad_fops);
	port->cdev.owner = THIS_MODULE;
1203
	cdev_set_parent(&port->cdev, &umad_dev->kobj);
1204
	kobject_set_name(&port->cdev.kobj, "umad%d", port->dev_num);
1205
	if (cdev_add(&port->cdev, base, 1))
L
Linus Torvalds 已提交
1206 1207
		goto err_cdev;

1208
	port->dev = device_create(umad_class, device->dev.parent,
1209
				  port->cdev.dev, port,
1210
				  "umad%d", port->dev_num);
1211
	if (IS_ERR(port->dev))
1212
		goto err_cdev;
L
Linus Torvalds 已提交
1213

1214 1215 1216 1217 1218
	if (device_create_file(port->dev, &dev_attr_ibdev))
		goto err_dev;
	if (device_create_file(port->dev, &dev_attr_port))
		goto err_dev;

1219
	base += IB_UMAD_MAX_PORTS;
1220 1221
	cdev_init(&port->sm_cdev, &umad_sm_fops);
	port->sm_cdev.owner = THIS_MODULE;
1222
	cdev_set_parent(&port->sm_cdev, &umad_dev->kobj);
1223
	kobject_set_name(&port->sm_cdev.kobj, "issm%d", port->dev_num);
1224
	if (cdev_add(&port->sm_cdev, base, 1))
1225
		goto err_sm_cdev;
L
Linus Torvalds 已提交
1226

1227
	port->sm_dev = device_create(umad_class, device->dev.parent,
1228
				     port->sm_cdev.dev, port,
1229
				     "issm%d", port->dev_num);
1230
	if (IS_ERR(port->sm_dev))
L
Linus Torvalds 已提交
1231 1232
		goto err_sm_cdev;

1233 1234 1235 1236
	if (device_create_file(port->sm_dev, &dev_attr_ibdev))
		goto err_sm_dev;
	if (device_create_file(port->sm_dev, &dev_attr_port))
		goto err_sm_dev;
L
Linus Torvalds 已提交
1237 1238 1239

	return 0;

1240
err_sm_dev:
1241
	device_destroy(umad_class, port->sm_cdev.dev);
L
Linus Torvalds 已提交
1242 1243

err_sm_cdev:
1244
	cdev_del(&port->sm_cdev);
L
Linus Torvalds 已提交
1245

1246
err_dev:
1247
	device_destroy(umad_class, port->cdev.dev);
L
Linus Torvalds 已提交
1248 1249

err_cdev:
1250
	cdev_del(&port->cdev);
1251 1252 1253 1254
	if (port->dev_num < IB_UMAD_MAX_PORTS)
		clear_bit(devnum, dev_map);
	else
		clear_bit(devnum, overflow_map);
L
Linus Torvalds 已提交
1255 1256 1257 1258

	return -1;
}

1259 1260
static void ib_umad_kill_port(struct ib_umad_port *port)
{
1261 1262 1263
	struct ib_umad_file *file;
	int id;

1264 1265
	dev_set_drvdata(port->dev,    NULL);
	dev_set_drvdata(port->sm_dev, NULL);
1266

1267 1268
	device_destroy(umad_class, port->cdev.dev);
	device_destroy(umad_class, port->sm_cdev.dev);
1269

1270 1271
	cdev_del(&port->cdev);
	cdev_del(&port->sm_cdev);
1272

1273
	mutex_lock(&port->file_mutex);
1274 1275 1276

	port->ib_dev = NULL;

1277 1278
	list_for_each_entry(file, &port->file_list, port_list) {
		mutex_lock(&file->mutex);
1279
		file->agents_dead = 1;
1280
		mutex_unlock(&file->mutex);
1281 1282 1283 1284 1285

		for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id)
			if (file->agent[id])
				ib_unregister_mad_agent(file->agent[id]);
	}
1286

1287
	mutex_unlock(&port->file_mutex);
1288

1289 1290 1291 1292
	if (port->dev_num < IB_UMAD_MAX_PORTS)
		clear_bit(port->dev_num, dev_map);
	else
		clear_bit(port->dev_num - IB_UMAD_MAX_PORTS, overflow_map);
1293 1294
}

L
Linus Torvalds 已提交
1295 1296 1297 1298
static void ib_umad_add_one(struct ib_device *device)
{
	struct ib_umad_device *umad_dev;
	int s, e, i;
1299
	int count = 0;
L
Linus Torvalds 已提交
1300

1301 1302
	s = rdma_start_port(device);
	e = rdma_end_port(device);
L
Linus Torvalds 已提交
1303

S
Sean Hefty 已提交
1304
	umad_dev = kzalloc(sizeof *umad_dev +
L
Linus Torvalds 已提交
1305 1306 1307 1308 1309
			   (e - s + 1) * sizeof (struct ib_umad_port),
			   GFP_KERNEL);
	if (!umad_dev)
		return;

1310
	kobject_init(&umad_dev->kobj, &ib_umad_dev_ktype);
L
Linus Torvalds 已提交
1311 1312

	for (i = s; i <= e; ++i) {
1313
		if (!rdma_cap_ib_mad(device, i))
1314 1315
			continue;

L
Linus Torvalds 已提交
1316 1317
		umad_dev->port[i - s].umad_dev = umad_dev;

1318 1319
		if (ib_umad_init_port(device, i, umad_dev,
				      &umad_dev->port[i - s]))
L
Linus Torvalds 已提交
1320
			goto err;
1321 1322

		count++;
L
Linus Torvalds 已提交
1323 1324
	}

1325 1326 1327
	if (!count)
		goto free;

L
Linus Torvalds 已提交
1328 1329 1330 1331 1332
	ib_set_client_data(device, &umad_client, umad_dev);

	return;

err:
1333
	while (--i >= s) {
1334
		if (!rdma_cap_ib_mad(device, i))
1335
			continue;
L
Linus Torvalds 已提交
1336

1337 1338 1339
		ib_umad_kill_port(&umad_dev->port[i - s]);
	}
free:
1340
	kobject_put(&umad_dev->kobj);
L
Linus Torvalds 已提交
1341 1342
}

1343
static void ib_umad_remove_one(struct ib_device *device, void *client_data)
L
Linus Torvalds 已提交
1344
{
1345
	struct ib_umad_device *umad_dev = client_data;
L
Linus Torvalds 已提交
1346 1347 1348 1349 1350
	int i;

	if (!umad_dev)
		return;

1351
	for (i = 0; i <= rdma_end_port(device) - rdma_start_port(device); ++i) {
1352
		if (rdma_cap_ib_mad(device, i + rdma_start_port(device)))
1353 1354
			ib_umad_kill_port(&umad_dev->port[i]);
	}
L
Linus Torvalds 已提交
1355

1356
	kobject_put(&umad_dev->kobj);
L
Linus Torvalds 已提交
1357 1358
}

1359
static char *umad_devnode(struct device *dev, umode_t *mode)
1360 1361 1362 1363
{
	return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
}

L
Linus Torvalds 已提交
1364 1365 1366 1367 1368 1369 1370
static int __init ib_umad_init(void)
{
	int ret;

	ret = register_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2,
				     "infiniband_mad");
	if (ret) {
1371
		pr_err("couldn't register device number\n");
L
Linus Torvalds 已提交
1372 1373 1374
		goto out;
	}

1375 1376 1377
	umad_class = class_create(THIS_MODULE, "infiniband_mad");
	if (IS_ERR(umad_class)) {
		ret = PTR_ERR(umad_class);
1378
		pr_err("couldn't create class infiniband_mad\n");
L
Linus Torvalds 已提交
1379 1380 1381
		goto out_chrdev;
	}

1382 1383
	umad_class->devnode = umad_devnode;

1384
	ret = class_create_file(umad_class, &class_attr_abi_version.attr);
L
Linus Torvalds 已提交
1385
	if (ret) {
1386
		pr_err("couldn't create abi_version attribute\n");
L
Linus Torvalds 已提交
1387 1388 1389 1390 1391
		goto out_class;
	}

	ret = ib_register_client(&umad_client);
	if (ret) {
1392
		pr_err("couldn't register ib_umad client\n");
L
Linus Torvalds 已提交
1393 1394 1395 1396 1397 1398
		goto out_class;
	}

	return 0;

out_class:
1399
	class_destroy(umad_class);
L
Linus Torvalds 已提交
1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410

out_chrdev:
	unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2);

out:
	return ret;
}

static void __exit ib_umad_cleanup(void)
{
	ib_unregister_client(&umad_client);
1411
	class_destroy(umad_class);
L
Linus Torvalds 已提交
1412
	unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2);
1413 1414
	if (overflow_maj)
		unregister_chrdev_region(overflow_maj, IB_UMAD_MAX_PORTS * 2);
L
Linus Torvalds 已提交
1415 1416 1417 1418
}

module_init(ib_umad_init);
module_exit(ib_umad_cleanup);