user_mad.c 33.5 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 54

#include <asm/uaccess.h>

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 136 137

static void ib_umad_add_one(struct ib_device *device);
static void ib_umad_remove_one(struct ib_device *device);

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
	ib_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 213 214 215 216 217 218
	kfree(packet);
}

static void recv_handler(struct ib_mad_agent *agent,
			 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)
219
		goto err1;
L
Linus Torvalds 已提交
220

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

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

R
Roland Dreier 已提交
228 229 230 231 232 233 234
	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);
	packet->mad.hdr.lid	   = cpu_to_be16(mad_recv_wc->wc->slid);
	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;
235 236
	packet->mad.hdr.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH);
	if (packet->mad.hdr.grh_present) {
237 238 239 240 241 242 243 244 245 246 247
		struct ib_ah_attr ah_attr;

		ib_init_ah_from_wc(agent->device, agent->port_num,
				   mad_recv_wc->wc, mad_recv_wc->recv_buf.grh,
				   &ah_attr);

		packet->mad.hdr.gid_index = ah_attr.grh.sgid_index;
		packet->mad.hdr.hop_limit = ah_attr.grh.hop_limit;
		packet->mad.hdr.traffic_class = ah_attr.grh.traffic_class;
		memcpy(packet->mad.hdr.gid, &ah_attr.grh.dgid, 16);
		packet->mad.hdr.flow_label = cpu_to_be32(ah_attr.grh.flow_label);
L
Linus Torvalds 已提交
248 249 250
	}

	if (queue_packet(file, agent, packet))
251 252
		goto err2;
	return;
L
Linus Torvalds 已提交
253

254 255 256
err2:
	kfree(packet);
err1:
L
Linus Torvalds 已提交
257 258 259
	ib_free_recv_mad(mad_recv_wc);
}

R
Roland Dreier 已提交
260 261
static ssize_t copy_recv_mad(struct ib_umad_file *file, char __user *buf,
			     struct ib_umad_packet *packet, size_t count)
262 263 264 265 266 267 268
{
	struct ib_mad_recv_buf *recv_buf;
	int left, seg_payload, offset, max_seg_payload;

	/* We need enough room to copy the first (or only) MAD segment. */
	recv_buf = &packet->recv_wc->recv_buf;
	if ((packet->length <= sizeof (*recv_buf->mad) &&
R
Roland Dreier 已提交
269
	     count < hdr_size(file) + packet->length) ||
270
	    (packet->length > sizeof (*recv_buf->mad) &&
R
Roland Dreier 已提交
271
	     count < hdr_size(file) + sizeof (*recv_buf->mad)))
272 273
		return -EINVAL;

R
Roland Dreier 已提交
274
	if (copy_to_user(buf, &packet->mad, hdr_size(file)))
275 276
		return -EFAULT;

R
Roland Dreier 已提交
277
	buf += hdr_size(file);
278 279 280 281 282 283 284 285 286
	seg_payload = min_t(int, packet->length, sizeof (*recv_buf->mad));
	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 已提交
287
		if (count < hdr_size(file) + packet->length) {
288 289 290 291 292 293
			/*
			 * The buffer is too small, return the first RMPP segment,
			 * which includes the RMPP message length.
			 */
			return -ENOSPC;
		}
294
		offset = ib_get_mad_data_offset(recv_buf->mad->mad_hdr.mgmt_class);
295 296 297 298 299 300 301 302 303 304 305 306
		max_seg_payload = sizeof (struct ib_mad) - offset;

		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 已提交
307
	return hdr_size(file) + packet->length;
308 309
}

R
Roland Dreier 已提交
310 311
static ssize_t copy_send_mad(struct ib_umad_file *file, char __user *buf,
			     struct ib_umad_packet *packet, size_t count)
312
{
R
Roland Dreier 已提交
313
	ssize_t size = hdr_size(file) + packet->length;
314 315 316 317

	if (count < size)
		return -EINVAL;

R
Roland Dreier 已提交
318 319 320 321 322 323
	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))
324 325 326 327 328
		return -EFAULT;

	return size;
}

L
Linus Torvalds 已提交
329 330 331 332 333 334 335
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 已提交
336
	if (count < hdr_size(file))
L
Linus Torvalds 已提交
337 338
		return -EINVAL;

339
	mutex_lock(&file->mutex);
L
Linus Torvalds 已提交
340 341

	while (list_empty(&file->recv_list)) {
342
		mutex_unlock(&file->mutex);
L
Linus Torvalds 已提交
343 344 345 346 347 348 349 350

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

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

351
		mutex_lock(&file->mutex);
L
Linus Torvalds 已提交
352 353 354 355 356
	}

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

357
	mutex_unlock(&file->mutex);
L
Linus Torvalds 已提交
358

359
	if (packet->recv_wc)
R
Roland Dreier 已提交
360
		ret = copy_recv_mad(file, buf, packet, count);
L
Linus Torvalds 已提交
361
	else
R
Roland Dreier 已提交
362
		ret = copy_send_mad(file, buf, packet, count);
363

364 365
	if (ret < 0) {
		/* Requeue packet */
366
		mutex_lock(&file->mutex);
367
		list_add(&packet->list, &file->recv_list);
368
		mutex_unlock(&file->mutex);
369 370 371
	} else {
		if (packet->recv_wc)
			ib_free_recv_mad(packet->recv_wc);
372
		kfree(packet);
373
	}
L
Linus Torvalds 已提交
374 375 376
	return ret;
}

377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
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;
}

397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 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
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.
		 */
		if (!ib_response_mad((struct ib_mad *) hdr)) {
			if (!ib_response_mad((struct ib_mad *) sent_hdr))
				return 1;
			continue;
		} else if (!ib_response_mad((struct ib_mad *) sent_hdr))
			continue;

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

	return 0;
}

L
Linus Torvalds 已提交
442 443 444 445 446 447 448
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;
	struct ib_ah_attr ah_attr;
449
	struct ib_ah *ah;
450
	struct ib_rmpp_mad *rmpp_mad;
451
	__be64 *tid;
452
	int ret, data_len, hdr_len, copy_offset, rmpp_active;
L
Linus Torvalds 已提交
453

R
Roland Dreier 已提交
454
	if (count < hdr_size(file) + IB_MGMT_RMPP_HDR)
L
Linus Torvalds 已提交
455 456
		return -EINVAL;

457
	packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);
L
Linus Torvalds 已提交
458 459 460
	if (!packet)
		return -ENOMEM;

R
Roland Dreier 已提交
461
	if (copy_from_user(&packet->mad, buf, hdr_size(file))) {
462 463
		ret = -EFAULT;
		goto err;
L
Linus Torvalds 已提交
464 465
	}

466
	if (packet->mad.hdr.id >= IB_UMAD_MAX_AGENTS) {
L
Linus Torvalds 已提交
467 468 469 470
		ret = -EINVAL;
		goto err;
	}

R
Roland Dreier 已提交
471 472 473 474 475 476 477
	buf += hdr_size(file);

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

478
	mutex_lock(&file->mutex);
L
Linus Torvalds 已提交
479

480
	agent = __get_agent(file, packet->mad.hdr.id);
L
Linus Torvalds 已提交
481 482 483 484 485 486
	if (!agent) {
		ret = -EINVAL;
		goto err_up;
	}

	memset(&ah_attr, 0, sizeof ah_attr);
487 488 489
	ah_attr.dlid          = be16_to_cpu(packet->mad.hdr.lid);
	ah_attr.sl            = packet->mad.hdr.sl;
	ah_attr.src_path_bits = packet->mad.hdr.path_bits;
L
Linus Torvalds 已提交
490
	ah_attr.port_num      = file->port->port_num;
491
	if (packet->mad.hdr.grh_present) {
L
Linus Torvalds 已提交
492
		ah_attr.ah_flags = IB_AH_GRH;
493
		memcpy(ah_attr.grh.dgid.raw, packet->mad.hdr.gid, 16);
494
		ah_attr.grh.sgid_index	   = packet->mad.hdr.gid_index;
A
Alexander Chiang 已提交
495 496
		ah_attr.grh.flow_label	   = be32_to_cpu(packet->mad.hdr.flow_label);
		ah_attr.grh.hop_limit	   = packet->mad.hdr.hop_limit;
497
		ah_attr.grh.traffic_class  = packet->mad.hdr.traffic_class;
L
Linus Torvalds 已提交
498 499
	}

500 501 502
	ah = ib_create_ah(agent->qp->pd, &ah_attr);
	if (IS_ERR(ah)) {
		ret = PTR_ERR(ah);
L
Linus Torvalds 已提交
503 504 505
		goto err_up;
	}

506
	rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data;
507
	hdr_len = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class);
I
Ira Weiny 已提交
508 509 510

	if (ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class)
	    && ib_mad_kernel_rmpp_agent(agent)) {
511 512
		copy_offset = IB_MGMT_RMPP_HDR;
		rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
I
Ira Weiny 已提交
513 514 515 516
						IB_MGMT_RMPP_FLAG_ACTIVE;
	} else {
		copy_offset = IB_MGMT_MAD_HDR;
		rmpp_active = 0;
517 518
	}

R
Roland Dreier 已提交
519
	data_len = count - hdr_size(file) - hdr_len;
520 521
	packet->msg = ib_create_send_mad(agent,
					 be32_to_cpu(packet->mad.hdr.qpn),
R
Roland Dreier 已提交
522 523
					 packet->mad.hdr.pkey_index, rmpp_active,
					 hdr_len, data_len, GFP_KERNEL);
524 525 526 527
	if (IS_ERR(packet->msg)) {
		ret = PTR_ERR(packet->msg);
		goto err_ah;
	}
L
Linus Torvalds 已提交
528

A
Alexander Chiang 已提交
529
	packet->msg->ah		= ah;
530
	packet->msg->timeout_ms = packet->mad.hdr.timeout_ms;
A
Alexander Chiang 已提交
531
	packet->msg->retries	= packet->mad.hdr.retries;
532
	packet->msg->context[0] = packet;
L
Linus Torvalds 已提交
533

534
	/* Copy MAD header.  Any RMPP header is already in place. */
S
Sean Hefty 已提交
535
	memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR);
536 537 538 539 540 541 542 543 544 545 546 547

	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;
548 549 550
	}

	/*
551 552 553
	 * 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.
554
	 */
555
	if (!ib_response_mad(packet->msg->mad)) {
556
		tid = &((struct ib_mad_hdr *) packet->msg->mad)->tid;
557 558
		*tid = cpu_to_be64(((u64) agent->hi_tid) << 32 |
				   (be64_to_cpup(tid) & 0xffffffff));
559 560 561
		rmpp_mad->mad_hdr.tid = *tid;
	}

I
Ira Weiny 已提交
562 563 564 565
	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);
566
		list_add_tail(&packet->list, &file->send_list);
I
Ira Weiny 已提交
567 568 569 570 571 572 573 574 575 576 577
		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 已提交
578 579
	}

580
	ret = ib_post_send_mad(packet->msg, NULL);
581
	if (ret)
582
		goto err_send;
583

584
	mutex_unlock(&file->mutex);
S
Sean Hefty 已提交
585
	return count;
586

587 588
err_send:
	dequeue_send(file, packet);
589 590 591
err_msg:
	ib_free_send_mad(packet->msg);
err_ah:
592
	ib_destroy_ah(ah);
L
Linus Torvalds 已提交
593
err_up:
594
	mutex_unlock(&file->mutex);
L
Linus Torvalds 已提交
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
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;
}

615 616
static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
			     int compat_method_mask)
L
Linus Torvalds 已提交
617 618 619
{
	struct ib_user_mad_reg_req ureq;
	struct ib_mad_reg_req req;
620
	struct ib_mad_agent *agent = NULL;
L
Linus Torvalds 已提交
621 622 623
	int agent_id;
	int ret;

624 625
	mutex_lock(&file->port->file_mutex);
	mutex_lock(&file->mutex);
626 627

	if (!file->port->ib_dev) {
628 629
		dev_notice(file->port->dev,
			   "ib_umad_reg_agent: invalid device\n");
630 631 632
		ret = -EPIPE;
		goto out;
	}
L
Linus Torvalds 已提交
633

634
	if (copy_from_user(&ureq, arg, sizeof ureq)) {
L
Linus Torvalds 已提交
635 636 637 638 639
		ret = -EFAULT;
		goto out;
	}

	if (ureq.qpn != 0 && ureq.qpn != 1) {
640 641 642
		dev_notice(file->port->dev,
			   "ib_umad_reg_agent: invalid QPN %d specified\n",
			   ureq.qpn);
L
Linus Torvalds 已提交
643 644 645 646 647
		ret = -EINVAL;
		goto out;
	}

	for (agent_id = 0; agent_id < IB_UMAD_MAX_AGENTS; ++agent_id)
648
		if (!__get_agent(file, agent_id))
L
Linus Torvalds 已提交
649 650
			goto found;

651 652 653
	dev_notice(file->port->dev,
		   "ib_umad_reg_agent: Max Agents (%u) reached\n",
		   IB_UMAD_MAX_AGENTS);
L
Linus Torvalds 已提交
654 655 656 657
	ret = -ENOMEM;
	goto out;

found:
658
	if (ureq.mgmt_class) {
659
		memset(&req, 0, sizeof(req));
660 661
		req.mgmt_class         = ureq.mgmt_class;
		req.mgmt_class_version = ureq.mgmt_class_version;
662 663 664 665 666 667 668 669 670 671 672 673
		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);
674
	}
L
Linus Torvalds 已提交
675 676 677

	agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num,
				      ureq.qpn ? IB_QPT_GSI : IB_QPT_SMI,
678
				      ureq.mgmt_class ? &req : NULL,
679
				      ureq.rmpp_version,
680
				      send_handler, recv_handler, file, 0);
L
Linus Torvalds 已提交
681 682
	if (IS_ERR(agent)) {
		ret = PTR_ERR(agent);
683
		agent = NULL;
L
Linus Torvalds 已提交
684 685 686 687 688 689
		goto out;
	}

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

R
Roland Dreier 已提交
693 694 695
	if (!file->already_used) {
		file->already_used = 1;
		if (!file->use_pkey_index) {
696 697 698 699 700
			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 已提交
701 702 703
		}
	}

704
	file->agent[agent_id] = agent;
L
Linus Torvalds 已提交
705
	ret = 0;
706

L
Linus Torvalds 已提交
707
out:
708 709 710 711 712 713 714
	mutex_unlock(&file->mutex);

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

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

L
Linus Torvalds 已提交
715 716 717
	return ret;
}

718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 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
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;
}


831
static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
L
Linus Torvalds 已提交
832
{
833
	struct ib_mad_agent *agent = NULL;
L
Linus Torvalds 已提交
834 835 836
	u32 id;
	int ret = 0;

837
	if (get_user(id, arg))
838
		return -EFAULT;
L
Linus Torvalds 已提交
839

840 841
	mutex_lock(&file->port->file_mutex);
	mutex_lock(&file->mutex);
L
Linus Torvalds 已提交
842

843
	if (id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {
L
Linus Torvalds 已提交
844 845 846 847
		ret = -EINVAL;
		goto out;
	}

848
	agent = file->agent[id];
L
Linus Torvalds 已提交
849 850 851
	file->agent[id] = NULL;

out:
852
	mutex_unlock(&file->mutex);
853

854
	if (agent)
855 856
		ib_unregister_mad_agent(agent);

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

L
Linus Torvalds 已提交
859 860 861
	return ret;
}

R
Roland Dreier 已提交
862 863 864 865
static long ib_umad_enable_pkey(struct ib_umad_file *file)
{
	int ret = 0;

866
	mutex_lock(&file->mutex);
R
Roland Dreier 已提交
867 868 869 870
	if (file->already_used)
		ret = -EINVAL;
	else
		file->use_pkey_index = 1;
871
	mutex_unlock(&file->mutex);
R
Roland Dreier 已提交
872 873 874 875

	return ret;
}

876 877
static long ib_umad_ioctl(struct file *filp, unsigned int cmd,
			  unsigned long arg)
L
Linus Torvalds 已提交
878 879 880
{
	switch (cmd) {
	case IB_USER_MAD_REGISTER_AGENT:
881
		return ib_umad_reg_agent(filp->private_data, (void __user *) arg, 0);
L
Linus Torvalds 已提交
882
	case IB_USER_MAD_UNREGISTER_AGENT:
883
		return ib_umad_unreg_agent(filp->private_data, (__u32 __user *) arg);
R
Roland Dreier 已提交
884 885
	case IB_USER_MAD_ENABLE_PKEY:
		return ib_umad_enable_pkey(filp->private_data);
886 887
	case IB_USER_MAD_REGISTER_AGENT2:
		return ib_umad_reg_agent2(filp->private_data, (void __user *) arg);
L
Linus Torvalds 已提交
888 889 890 891 892
	default:
		return -ENOIOCTLCMD;
	}
}

893 894 895 896 897 898 899 900 901 902 903
#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);
904 905
	case IB_USER_MAD_REGISTER_AGENT2:
		return ib_umad_reg_agent2(filp->private_data, compat_ptr(arg));
906 907 908 909 910 911
	default:
		return -ENOIOCTLCMD;
	}
}
#endif

912 913 914
/*
 * ib_umad_open() does not need the BKL:
 *
A
Alexander Chiang 已提交
915
 *  - the ib_umad_port structures are properly reference counted, and
916 917 918 919 920
 *    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 已提交
921 922
static int ib_umad_open(struct inode *inode, struct file *filp)
{
923
	struct ib_umad_port *port;
L
Linus Torvalds 已提交
924
	struct ib_umad_file *file;
B
Bart Van Assche 已提交
925
	int ret = -ENXIO;
L
Linus Torvalds 已提交
926

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

929
	mutex_lock(&port->file_mutex);
930

B
Bart Van Assche 已提交
931
	if (!port->ib_dev)
932 933
		goto out;

B
Bart Van Assche 已提交
934
	ret = -ENOMEM;
S
Sean Hefty 已提交
935
	file = kzalloc(sizeof *file, GFP_KERNEL);
B
Bart Van Assche 已提交
936
	if (!file)
937
		goto out;
L
Linus Torvalds 已提交
938

939
	mutex_init(&file->mutex);
940
	spin_lock_init(&file->send_lock);
L
Linus Torvalds 已提交
941
	INIT_LIST_HEAD(&file->recv_list);
942
	INIT_LIST_HEAD(&file->send_list);
L
Linus Torvalds 已提交
943 944 945 946 947
	init_waitqueue_head(&file->recv_wait);

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

948 949
	list_add_tail(&file->port_list, &port->file_list);

950
	ret = nonseekable_open(inode, filp);
B
Bart Van Assche 已提交
951 952 953 954 955 956
	if (ret) {
		list_del(&file->port_list);
		kfree(file);
		goto out;
	}

957
	kobject_get(&port->umad_dev->kobj);
958

959
out:
960
	mutex_unlock(&port->file_mutex);
961
	return ret;
L
Linus Torvalds 已提交
962 963 964 965 966
}

static int ib_umad_close(struct inode *inode, struct file *filp)
{
	struct ib_umad_file *file = filp->private_data;
967
	struct ib_umad_device *dev = file->port->umad_dev;
968
	struct ib_umad_packet *packet, *tmp;
969
	int already_dead;
L
Linus Torvalds 已提交
970 971
	int i;

972 973
	mutex_lock(&file->port->file_mutex);
	mutex_lock(&file->mutex);
974 975 976

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

978 979 980
	list_for_each_entry_safe(packet, tmp, &file->recv_list, list) {
		if (packet->recv_wc)
			ib_free_recv_mad(packet->recv_wc);
981
		kfree(packet);
982
	}
983

984 985
	list_del(&file->port_list);

986
	mutex_unlock(&file->mutex);
987 988 989 990 991

	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 已提交
992

993
	mutex_unlock(&file->port->file_mutex);
994 995

	kfree(file);
996
	kobject_put(&dev->kobj);
997

L
Linus Torvalds 已提交
998 999 1000
	return 0;
}

1001
static const struct file_operations umad_fops = {
A
Alexander Chiang 已提交
1002 1003 1004 1005
	.owner		= THIS_MODULE,
	.read		= ib_umad_read,
	.write		= ib_umad_write,
	.poll		= ib_umad_poll,
L
Linus Torvalds 已提交
1006
	.unlocked_ioctl = ib_umad_ioctl,
1007
#ifdef CONFIG_COMPAT
A
Alexander Chiang 已提交
1008
	.compat_ioctl	= ib_umad_compat_ioctl,
1009
#endif
A
Alexander Chiang 已提交
1010
	.open		= ib_umad_open,
1011 1012
	.release	= ib_umad_close,
	.llseek		= no_llseek,
L
Linus Torvalds 已提交
1013 1014 1015 1016
};

static int ib_umad_sm_open(struct inode *inode, struct file *filp)
{
1017
	struct ib_umad_port *port;
L
Linus Torvalds 已提交
1018 1019 1020 1021 1022
	struct ib_port_modify props = {
		.set_port_cap_mask = IB_PORT_SM
	};
	int ret;

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

L
Linus Torvalds 已提交
1025
	if (filp->f_flags & O_NONBLOCK) {
1026 1027 1028 1029
		if (down_trylock(&port->sm_sem)) {
			ret = -EAGAIN;
			goto fail;
		}
L
Linus Torvalds 已提交
1030
	} else {
1031 1032 1033 1034
		if (down_interruptible(&port->sm_sem)) {
			ret = -ERESTARTSYS;
			goto fail;
		}
L
Linus Torvalds 已提交
1035 1036 1037
	}

	ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
B
Bart Van Assche 已提交
1038 1039
	if (ret)
		goto err_up_sem;
L
Linus Torvalds 已提交
1040 1041 1042

	filp->private_data = port;

B
Bart Van Assche 已提交
1043 1044 1045 1046
	ret = nonseekable_open(inode, filp);
	if (ret)
		goto err_clr_sm_cap;

1047
	kobject_get(&port->umad_dev->kobj);
B
Bart Van Assche 已提交
1048 1049 1050 1051 1052 1053 1054 1055 1056

	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);
1057 1058 1059

fail:
	return ret;
L
Linus Torvalds 已提交
1060 1061 1062 1063 1064 1065 1066 1067
}

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
	};
1068 1069
	int ret = 0;

1070
	mutex_lock(&port->file_mutex);
1071 1072
	if (port->ib_dev)
		ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
1073
	mutex_unlock(&port->file_mutex);
L
Linus Torvalds 已提交
1074 1075 1076

	up(&port->sm_sem);

1077
	kobject_put(&port->umad_dev->kobj);
1078

L
Linus Torvalds 已提交
1079 1080 1081
	return ret;
}

1082
static const struct file_operations umad_sm_fops = {
A
Alexander Chiang 已提交
1083 1084
	.owner	 = THIS_MODULE,
	.open	 = ib_umad_sm_open,
1085 1086
	.release = ib_umad_sm_close,
	.llseek	 = no_llseek,
L
Linus Torvalds 已提交
1087 1088 1089 1090 1091 1092 1093 1094
};

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

1095 1096
static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr,
			  char *buf)
L
Linus Torvalds 已提交
1097
{
1098
	struct ib_umad_port *port = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1099

1100 1101 1102
	if (!port)
		return -ENODEV;

L
Linus Torvalds 已提交
1103 1104
	return sprintf(buf, "%s\n", port->ib_dev->name);
}
1105
static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
L
Linus Torvalds 已提交
1106

1107 1108
static ssize_t show_port(struct device *dev, struct device_attribute *attr,
			 char *buf)
L
Linus Torvalds 已提交
1109
{
1110
	struct ib_umad_port *port = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1111

1112 1113 1114
	if (!port)
		return -ENODEV;

L
Linus Torvalds 已提交
1115 1116
	return sprintf(buf, "%d\n", port->port_num);
}
1117
static DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
L
Linus Torvalds 已提交
1118

1119 1120
static CLASS_ATTR_STRING(abi_version, S_IRUGO,
			 __stringify(IB_USER_MAD_ABI_VERSION));
L
Linus Torvalds 已提交
1121

1122 1123
static dev_t overflow_maj;
static DECLARE_BITMAP(overflow_map, IB_UMAD_MAX_PORTS);
1124
static int find_overflow_devnum(struct ib_device *device)
1125 1126 1127 1128 1129 1130 1131
{
	int ret;

	if (!overflow_maj) {
		ret = alloc_chrdev_region(&overflow_maj, 0, IB_UMAD_MAX_PORTS * 2,
					  "infiniband_mad");
		if (ret) {
1132 1133
			dev_err(&device->dev,
				"couldn't register dynamic device number\n");
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
			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 已提交
1145
static int ib_umad_init_port(struct ib_device *device, int port_num,
1146
			     struct ib_umad_device *umad_dev,
L
Linus Torvalds 已提交
1147 1148
			     struct ib_umad_port *port)
{
1149
	int devnum;
1150
	dev_t base;
1151

1152
	spin_lock(&port_lock);
1153 1154
	devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS);
	if (devnum >= IB_UMAD_MAX_PORTS) {
1155
		spin_unlock(&port_lock);
1156
		devnum = find_overflow_devnum(device);
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
		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 已提交
1168
	}
1169
	spin_unlock(&port_lock);
L
Linus Torvalds 已提交
1170 1171 1172

	port->ib_dev   = device;
	port->port_num = port_num;
1173
	sema_init(&port->sm_sem, 1);
1174
	mutex_init(&port->file_mutex);
1175
	INIT_LIST_HEAD(&port->file_list);
L
Linus Torvalds 已提交
1176

1177 1178
	cdev_init(&port->cdev, &umad_fops);
	port->cdev.owner = THIS_MODULE;
1179
	port->cdev.kobj.parent = &umad_dev->kobj;
1180
	kobject_set_name(&port->cdev.kobj, "umad%d", port->dev_num);
1181
	if (cdev_add(&port->cdev, base, 1))
L
Linus Torvalds 已提交
1182 1183
		goto err_cdev;

1184
	port->dev = device_create(umad_class, device->dma_device,
1185
				  port->cdev.dev, port,
1186
				  "umad%d", port->dev_num);
1187
	if (IS_ERR(port->dev))
1188
		goto err_cdev;
L
Linus Torvalds 已提交
1189

1190 1191 1192 1193 1194
	if (device_create_file(port->dev, &dev_attr_ibdev))
		goto err_dev;
	if (device_create_file(port->dev, &dev_attr_port))
		goto err_dev;

1195
	base += IB_UMAD_MAX_PORTS;
1196 1197
	cdev_init(&port->sm_cdev, &umad_sm_fops);
	port->sm_cdev.owner = THIS_MODULE;
1198
	port->sm_cdev.kobj.parent = &umad_dev->kobj;
1199
	kobject_set_name(&port->sm_cdev.kobj, "issm%d", port->dev_num);
1200
	if (cdev_add(&port->sm_cdev, base, 1))
1201
		goto err_sm_cdev;
L
Linus Torvalds 已提交
1202

1203
	port->sm_dev = device_create(umad_class, device->dma_device,
1204
				     port->sm_cdev.dev, port,
1205
				     "issm%d", port->dev_num);
1206
	if (IS_ERR(port->sm_dev))
L
Linus Torvalds 已提交
1207 1208
		goto err_sm_cdev;

1209 1210 1211 1212
	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 已提交
1213 1214 1215

	return 0;

1216
err_sm_dev:
1217
	device_destroy(umad_class, port->sm_cdev.dev);
L
Linus Torvalds 已提交
1218 1219

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

1222
err_dev:
1223
	device_destroy(umad_class, port->cdev.dev);
L
Linus Torvalds 已提交
1224 1225

err_cdev:
1226
	cdev_del(&port->cdev);
1227 1228 1229 1230
	if (port->dev_num < IB_UMAD_MAX_PORTS)
		clear_bit(devnum, dev_map);
	else
		clear_bit(devnum, overflow_map);
L
Linus Torvalds 已提交
1231 1232 1233 1234

	return -1;
}

1235 1236
static void ib_umad_kill_port(struct ib_umad_port *port)
{
1237 1238 1239
	struct ib_umad_file *file;
	int id;

1240 1241
	dev_set_drvdata(port->dev,    NULL);
	dev_set_drvdata(port->sm_dev, NULL);
1242

1243 1244
	device_destroy(umad_class, port->cdev.dev);
	device_destroy(umad_class, port->sm_cdev.dev);
1245

1246 1247
	cdev_del(&port->cdev);
	cdev_del(&port->sm_cdev);
1248

1249
	mutex_lock(&port->file_mutex);
1250 1251 1252

	port->ib_dev = NULL;

1253 1254
	list_for_each_entry(file, &port->file_list, port_list) {
		mutex_lock(&file->mutex);
1255
		file->agents_dead = 1;
1256
		mutex_unlock(&file->mutex);
1257 1258 1259 1260 1261

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

1263
	mutex_unlock(&port->file_mutex);
1264

1265 1266 1267 1268
	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);
1269 1270
}

L
Linus Torvalds 已提交
1271 1272 1273 1274
static void ib_umad_add_one(struct ib_device *device)
{
	struct ib_umad_device *umad_dev;
	int s, e, i;
1275
	int count = 0;
T
Tom Tucker 已提交
1276

1277 1278
	s = rdma_start_port(device);
	e = rdma_end_port(device);
L
Linus Torvalds 已提交
1279

S
Sean Hefty 已提交
1280
	umad_dev = kzalloc(sizeof *umad_dev +
L
Linus Torvalds 已提交
1281 1282 1283 1284 1285
			   (e - s + 1) * sizeof (struct ib_umad_port),
			   GFP_KERNEL);
	if (!umad_dev)
		return;

1286
	kobject_init(&umad_dev->kobj, &ib_umad_dev_ktype);
L
Linus Torvalds 已提交
1287 1288

	for (i = s; i <= e; ++i) {
1289
		if (!rdma_cap_ib_mad(device, i))
1290 1291
			continue;

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

1294 1295
		if (ib_umad_init_port(device, i, umad_dev,
				      &umad_dev->port[i - s]))
L
Linus Torvalds 已提交
1296
			goto err;
1297 1298

		count++;
L
Linus Torvalds 已提交
1299 1300
	}

1301 1302 1303
	if (!count)
		goto free;

L
Linus Torvalds 已提交
1304 1305 1306 1307 1308
	ib_set_client_data(device, &umad_client, umad_dev);

	return;

err:
1309
	while (--i >= s) {
1310
		if (!rdma_cap_ib_mad(device, i))
1311
			continue;
L
Linus Torvalds 已提交
1312

1313 1314 1315
		ib_umad_kill_port(&umad_dev->port[i - s]);
	}
free:
1316
	kobject_put(&umad_dev->kobj);
L
Linus Torvalds 已提交
1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
}

static void ib_umad_remove_one(struct ib_device *device)
{
	struct ib_umad_device *umad_dev = ib_get_client_data(device, &umad_client);
	int i;

	if (!umad_dev)
		return;

1327
	for (i = 0; i <= rdma_end_port(device) - rdma_start_port(device); ++i) {
1328
		if (rdma_cap_ib_mad(device, i))
1329 1330
			ib_umad_kill_port(&umad_dev->port[i]);
	}
L
Linus Torvalds 已提交
1331

1332
	kobject_put(&umad_dev->kobj);
L
Linus Torvalds 已提交
1333 1334
}

1335
static char *umad_devnode(struct device *dev, umode_t *mode)
1336 1337 1338 1339
{
	return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
}

L
Linus Torvalds 已提交
1340 1341 1342 1343 1344 1345 1346
static int __init ib_umad_init(void)
{
	int ret;

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

1351 1352 1353
	umad_class = class_create(THIS_MODULE, "infiniband_mad");
	if (IS_ERR(umad_class)) {
		ret = PTR_ERR(umad_class);
1354
		pr_err("couldn't create class infiniband_mad\n");
L
Linus Torvalds 已提交
1355 1356 1357
		goto out_chrdev;
	}

1358 1359
	umad_class->devnode = umad_devnode;

1360
	ret = class_create_file(umad_class, &class_attr_abi_version.attr);
L
Linus Torvalds 已提交
1361
	if (ret) {
1362
		pr_err("couldn't create abi_version attribute\n");
L
Linus Torvalds 已提交
1363 1364 1365 1366 1367
		goto out_class;
	}

	ret = ib_register_client(&umad_client);
	if (ret) {
1368
		pr_err("couldn't register ib_umad client\n");
L
Linus Torvalds 已提交
1369 1370 1371 1372 1373 1374
		goto out_class;
	}

	return 0;

out_class:
1375
	class_destroy(umad_class);
L
Linus Torvalds 已提交
1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386

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);
1387
	class_destroy(umad_class);
L
Linus Torvalds 已提交
1388
	unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2);
1389 1390
	if (overflow_maj)
		unregister_chrdev_region(overflow_maj, IB_UMAD_MAX_PORTS * 2);
L
Linus Torvalds 已提交
1391 1392 1393 1394
}

module_init(ib_umad_init);
module_exit(ib_umad_cleanup);