user_mad.c 33.9 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
#include "core_priv.h"

L
Linus Torvalds 已提交
60 61 62 63 64
MODULE_AUTHOR("Roland Dreier");
MODULE_DESCRIPTION("InfiniBand userspace MAD packet access");
MODULE_LICENSE("Dual BSD/GPL");

enum {
65
	IB_UMAD_MAX_PORTS  = RDMA_MAX_PORTS,
L
Linus Torvalds 已提交
66 67 68
	IB_UMAD_MAX_AGENTS = 32,

	IB_UMAD_MAJOR      = 231,
69 70 71 72
	IB_UMAD_MINOR_BASE = 0,
	IB_UMAD_NUM_FIXED_MINOR = 64,
	IB_UMAD_NUM_DYNAMIC_MINOR = IB_UMAD_MAX_PORTS - IB_UMAD_NUM_FIXED_MINOR,
	IB_ISSM_MINOR_BASE        = IB_UMAD_NUM_FIXED_MINOR,
L
Linus Torvalds 已提交
73 74
};

75
/*
A
Alexander Chiang 已提交
76 77 78
 * 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
79 80 81 82 83 84 85
 * 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 已提交
86
 * When destroying an ib_umad_device, we drop the module's reference.
87 88
 */

L
Linus Torvalds 已提交
89
struct ib_umad_port {
90
	struct cdev           cdev;
91
	struct device	      dev;
92
	struct cdev           sm_cdev;
93
	struct device	      sm_dev;
L
Linus Torvalds 已提交
94 95
	struct semaphore       sm_sem;

96
	struct mutex	       file_mutex;
97 98
	struct list_head       file_list;

L
Linus Torvalds 已提交
99 100
	struct ib_device      *ib_dev;
	struct ib_umad_device *umad_dev;
101
	int                    dev_num;
L
Linus Torvalds 已提交
102 103 104 105
	u8                     port_num;
};

struct ib_umad_device {
106 107
	struct kref kref;
	struct ib_umad_port ports[];
L
Linus Torvalds 已提交
108 109 110
};

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

struct ib_umad_packet {
125
	struct ib_mad_send_buf *msg;
126
	struct ib_mad_recv_wc  *recv_wc;
L
Linus Torvalds 已提交
127
	struct list_head   list;
128 129
	int		   length;
	struct ib_user_mad mad;
L
Linus Torvalds 已提交
130 131
};

132 133 134 135 136
static const dev_t base_umad_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE);
static const dev_t base_issm_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE) +
				   IB_UMAD_NUM_FIXED_MINOR;
static dev_t dynamic_umad_dev;
static dev_t dynamic_issm_dev;
137

138
static DEFINE_IDA(umad_ida);
L
Linus Torvalds 已提交
139 140

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

143
static void ib_umad_dev_free(struct kref *kref)
144 145
{
	struct ib_umad_device *dev =
146
		container_of(kref, struct ib_umad_device, kref);
147 148 149 150

	kfree(dev);
}

151 152 153 154 155 156 157 158 159
static void ib_umad_dev_get(struct ib_umad_device *dev)
{
	kref_get(&dev->kref);
}

static void ib_umad_dev_put(struct ib_umad_device *dev)
{
	kref_put(&dev->kref, ib_umad_dev_free);
}
160

R
Roland Dreier 已提交
161 162 163 164 165 166
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);
}

167
/* caller must hold file->mutex */
168 169 170 171 172
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 已提交
173 174 175 176 177 178
static int queue_packet(struct ib_umad_file *file,
			struct ib_mad_agent *agent,
			struct ib_umad_packet *packet)
{
	int ret = 1;

179
	mutex_lock(&file->mutex);
180

181 182 183
	for (packet->mad.hdr.id = 0;
	     packet->mad.hdr.id < IB_UMAD_MAX_AGENTS;
	     packet->mad.hdr.id++)
184
		if (agent == __get_agent(file, packet->mad.hdr.id)) {
L
Linus Torvalds 已提交
185 186 187 188 189 190
			list_add_tail(&packet->list, &file->recv_list);
			wake_up_interruptible(&file->recv_wait);
			ret = 0;
			break;
		}

191
	mutex_unlock(&file->mutex);
L
Linus Torvalds 已提交
192 193 194 195

	return ret;
}

196 197
static void dequeue_send(struct ib_umad_file *file,
			 struct ib_umad_packet *packet)
198
{
199 200 201
	spin_lock_irq(&file->send_lock);
	list_del(&packet->list);
	spin_unlock_irq(&file->send_lock);
202
}
203

L
Linus Torvalds 已提交
204 205 206 207
static void send_handler(struct ib_mad_agent *agent,
			 struct ib_mad_send_wc *send_wc)
{
	struct ib_umad_file *file = agent->context;
208
	struct ib_umad_packet *packet = send_wc->send_buf->context[0];
L
Linus Torvalds 已提交
209

210
	dequeue_send(file, packet);
211
	rdma_destroy_ah(packet->msg->ah, RDMA_DESTROY_AH_SLEEPABLE);
212
	ib_free_send_mad(packet->msg);
L
Linus Torvalds 已提交
213 214

	if (send_wc->status == IB_WC_RESP_TIMEOUT_ERR) {
215 216 217 218
		packet->length = IB_MGMT_MAD_HDR;
		packet->mad.hdr.status = ETIMEDOUT;
		if (!queue_packet(file, agent, packet))
			return;
219
	}
L
Linus Torvalds 已提交
220 221 222 223
	kfree(packet);
}

static void recv_handler(struct ib_mad_agent *agent,
224
			 struct ib_mad_send_buf *send_buf,
L
Linus Torvalds 已提交
225 226 227 228 229 230
			 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)
231
		goto err1;
L
Linus Torvalds 已提交
232

233
	packet = kzalloc(sizeof *packet, GFP_KERNEL);
L
Linus Torvalds 已提交
234
	if (!packet)
235
		goto err1;
L
Linus Torvalds 已提交
236

237 238
	packet->length = mad_recv_wc->mad_len;
	packet->recv_wc = mad_recv_wc;
L
Linus Torvalds 已提交
239

R
Roland Dreier 已提交
240 241 242
	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);
243 244 245 246
	/*
	 * 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.
	 */
247
	if (rdma_cap_opa_mad(agent->device, agent->port_num))
248 249 250 251
		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 已提交
252 253 254
	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;
255 256
	packet->mad.hdr.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH);
	if (packet->mad.hdr.grh_present) {
257
		struct rdma_ah_attr ah_attr;
258
		const struct ib_global_route *grh;
P
Parav Pandit 已提交
259
		int ret;
260

261 262 263 264
		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 已提交
265 266
		if (ret)
			goto err2;
267

268 269 270 271 272 273
		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);
274
		rdma_destroy_ah_attr(&ah_attr);
L
Linus Torvalds 已提交
275 276 277
	}

	if (queue_packet(file, agent, packet))
278 279
		goto err2;
	return;
L
Linus Torvalds 已提交
280

281 282 283
err2:
	kfree(packet);
err1:
L
Linus Torvalds 已提交
284 285 286
	ib_free_recv_mad(mad_recv_wc);
}

R
Roland Dreier 已提交
287 288
static ssize_t copy_recv_mad(struct ib_umad_file *file, char __user *buf,
			     struct ib_umad_packet *packet, size_t count)
289 290 291
{
	struct ib_mad_recv_buf *recv_buf;
	int left, seg_payload, offset, max_seg_payload;
I
Ira Weiny 已提交
292
	size_t seg_size;
293 294

	recv_buf = &packet->recv_wc->recv_buf;
I
Ira Weiny 已提交
295 296 297 298
	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 已提交
299
	     count < hdr_size(file) + packet->length) ||
I
Ira Weiny 已提交
300 301
	    (packet->length > seg_size &&
	     count < hdr_size(file) + seg_size))
302 303
		return -EINVAL;

R
Roland Dreier 已提交
304
	if (copy_to_user(buf, &packet->mad, hdr_size(file)))
305 306
		return -EFAULT;

R
Roland Dreier 已提交
307
	buf += hdr_size(file);
I
Ira Weiny 已提交
308
	seg_payload = min_t(int, packet->length, seg_size);
309 310 311 312 313 314 315 316
	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 已提交
317
		if (count < hdr_size(file) + packet->length) {
318 319 320 321 322 323
			/*
			 * The buffer is too small, return the first RMPP segment,
			 * which includes the RMPP message length.
			 */
			return -ENOSPC;
		}
324
		offset = ib_get_mad_data_offset(recv_buf->mad->mad_hdr.mgmt_class);
I
Ira Weiny 已提交
325
		max_seg_payload = seg_size - offset;
326 327 328 329 330 331 332 333 334 335 336

		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 已提交
337
	return hdr_size(file) + packet->length;
338 339
}

R
Roland Dreier 已提交
340 341
static ssize_t copy_send_mad(struct ib_umad_file *file, char __user *buf,
			     struct ib_umad_packet *packet, size_t count)
342
{
R
Roland Dreier 已提交
343
	ssize_t size = hdr_size(file) + packet->length;
344 345 346 347

	if (count < size)
		return -EINVAL;

R
Roland Dreier 已提交
348 349 350 351 352 353
	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))
354 355 356 357 358
		return -EFAULT;

	return size;
}

L
Linus Torvalds 已提交
359 360 361 362 363 364 365
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 已提交
366
	if (count < hdr_size(file))
L
Linus Torvalds 已提交
367 368
		return -EINVAL;

369
	mutex_lock(&file->mutex);
L
Linus Torvalds 已提交
370 371

	while (list_empty(&file->recv_list)) {
372
		mutex_unlock(&file->mutex);
L
Linus Torvalds 已提交
373 374 375 376 377 378 379 380

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

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

381
		mutex_lock(&file->mutex);
L
Linus Torvalds 已提交
382 383 384 385 386
	}

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

387
	mutex_unlock(&file->mutex);
L
Linus Torvalds 已提交
388

389
	if (packet->recv_wc)
R
Roland Dreier 已提交
390
		ret = copy_recv_mad(file, buf, packet, count);
L
Linus Torvalds 已提交
391
	else
R
Roland Dreier 已提交
392
		ret = copy_send_mad(file, buf, packet, count);
393

394 395
	if (ret < 0) {
		/* Requeue packet */
396
		mutex_lock(&file->mutex);
397
		list_add(&packet->list, &file->recv_list);
398
		mutex_unlock(&file->mutex);
399 400 401
	} else {
		if (packet->recv_wc)
			ib_free_recv_mad(packet->recv_wc);
402
		kfree(packet);
403
	}
L
Linus Torvalds 已提交
404 405 406
	return ret;
}

407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
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;
}

427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
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.
		 */
458 459
		if (!ib_response_mad(hdr)) {
			if (!ib_response_mad(sent_hdr))
460 461
				return 1;
			continue;
462
		} else if (!ib_response_mad(sent_hdr))
463 464 465 466 467 468 469 470 471
			continue;

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

	return 0;
}

L
Linus Torvalds 已提交
472 473 474 475 476 477
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;
478
	struct rdma_ah_attr ah_attr;
479
	struct ib_ah *ah;
480
	struct ib_rmpp_mad *rmpp_mad;
481
	__be64 *tid;
482
	int ret, data_len, hdr_len, copy_offset, rmpp_active;
I
Ira Weiny 已提交
483
	u8 base_version;
L
Linus Torvalds 已提交
484

R
Roland Dreier 已提交
485
	if (count < hdr_size(file) + IB_MGMT_RMPP_HDR)
L
Linus Torvalds 已提交
486 487
		return -EINVAL;

488
	packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);
L
Linus Torvalds 已提交
489 490 491
	if (!packet)
		return -ENOMEM;

R
Roland Dreier 已提交
492
	if (copy_from_user(&packet->mad, buf, hdr_size(file))) {
493 494
		ret = -EFAULT;
		goto err;
L
Linus Torvalds 已提交
495 496
	}

497
	if (packet->mad.hdr.id >= IB_UMAD_MAX_AGENTS) {
L
Linus Torvalds 已提交
498 499 500 501
		ret = -EINVAL;
		goto err;
	}

R
Roland Dreier 已提交
502 503 504 505 506 507 508
	buf += hdr_size(file);

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

509
	mutex_lock(&file->mutex);
L
Linus Torvalds 已提交
510

511
	agent = __get_agent(file, packet->mad.hdr.id);
L
Linus Torvalds 已提交
512 513 514 515 516 517
	if (!agent) {
		ret = -EINVAL;
		goto err_up;
	}

	memset(&ah_attr, 0, sizeof ah_attr);
518
	ah_attr.type = rdma_ah_find_type(agent->device,
519
					 file->port->port_num);
520 521 522 523
	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);
524
	if (packet->mad.hdr.grh_present) {
525 526 527 528 529 530
		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 已提交
531 532
	}

533
	ah = rdma_create_user_ah(agent->qp->pd, &ah_attr, NULL);
534 535
	if (IS_ERR(ah)) {
		ret = PTR_ERR(ah);
L
Linus Torvalds 已提交
536 537 538
		goto err_up;
	}

539
	rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data;
540
	hdr_len = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class);
I
Ira Weiny 已提交
541 542 543

	if (ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class)
	    && ib_mad_kernel_rmpp_agent(agent)) {
544 545
		copy_offset = IB_MGMT_RMPP_HDR;
		rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
I
Ira Weiny 已提交
546 547 548 549
						IB_MGMT_RMPP_FLAG_ACTIVE;
	} else {
		copy_offset = IB_MGMT_MAD_HDR;
		rmpp_active = 0;
550 551
	}

I
Ira Weiny 已提交
552
	base_version = ((struct ib_mad_hdr *)&packet->mad.data)->base_version;
R
Roland Dreier 已提交
553
	data_len = count - hdr_size(file) - hdr_len;
554 555
	packet->msg = ib_create_send_mad(agent,
					 be32_to_cpu(packet->mad.hdr.qpn),
R
Roland Dreier 已提交
556
					 packet->mad.hdr.pkey_index, rmpp_active,
557
					 hdr_len, data_len, GFP_KERNEL,
I
Ira Weiny 已提交
558
					 base_version);
559 560 561 562
	if (IS_ERR(packet->msg)) {
		ret = PTR_ERR(packet->msg);
		goto err_ah;
	}
L
Linus Torvalds 已提交
563

A
Alexander Chiang 已提交
564
	packet->msg->ah		= ah;
565
	packet->msg->timeout_ms = packet->mad.hdr.timeout_ms;
A
Alexander Chiang 已提交
566
	packet->msg->retries	= packet->mad.hdr.retries;
567
	packet->msg->context[0] = packet;
L
Linus Torvalds 已提交
568

569
	/* Copy MAD header.  Any RMPP header is already in place. */
S
Sean Hefty 已提交
570
	memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR);
571 572 573 574 575 576 577 578 579 580 581 582

	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;
583 584 585
	}

	/*
586 587 588
	 * 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.
589
	 */
590
	if (!ib_response_mad(packet->msg->mad)) {
591
		tid = &((struct ib_mad_hdr *) packet->msg->mad)->tid;
592 593
		*tid = cpu_to_be64(((u64) agent->hi_tid) << 32 |
				   (be64_to_cpup(tid) & 0xffffffff));
594 595 596
		rmpp_mad->mad_hdr.tid = *tid;
	}

I
Ira Weiny 已提交
597 598 599 600
	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);
601
		list_add_tail(&packet->list, &file->send_list);
I
Ira Weiny 已提交
602 603 604 605 606 607 608 609 610 611 612
		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 已提交
613 614
	}

615
	ret = ib_post_send_mad(packet->msg, NULL);
616
	if (ret)
617
		goto err_send;
618

619
	mutex_unlock(&file->mutex);
S
Sean Hefty 已提交
620
	return count;
621

622 623
err_send:
	dequeue_send(file, packet);
624 625 626
err_msg:
	ib_free_send_mad(packet->msg);
err_ah:
627
	rdma_destroy_ah(ah, RDMA_DESTROY_AH_SLEEPABLE);
L
Linus Torvalds 已提交
628
err_up:
629
	mutex_unlock(&file->mutex);
L
Linus Torvalds 已提交
630 631 632 633 634
err:
	kfree(packet);
	return ret;
}

635
static __poll_t ib_umad_poll(struct file *filp, struct poll_table_struct *wait)
L
Linus Torvalds 已提交
636 637 638 639
{
	struct ib_umad_file *file = filp->private_data;

	/* we will always be able to post a MAD send */
640
	__poll_t mask = EPOLLOUT | EPOLLWRNORM;
L
Linus Torvalds 已提交
641 642 643 644

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

	if (!list_empty(&file->recv_list))
645
		mask |= EPOLLIN | EPOLLRDNORM;
L
Linus Torvalds 已提交
646 647 648 649

	return mask;
}

650 651
static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
			     int compat_method_mask)
L
Linus Torvalds 已提交
652 653 654
{
	struct ib_user_mad_reg_req ureq;
	struct ib_mad_reg_req req;
655
	struct ib_mad_agent *agent = NULL;
L
Linus Torvalds 已提交
656 657 658
	int agent_id;
	int ret;

659 660
	mutex_lock(&file->port->file_mutex);
	mutex_lock(&file->mutex);
661 662

	if (!file->port->ib_dev) {
663
		dev_notice(&file->port->dev,
664
			   "ib_umad_reg_agent: invalid device\n");
665 666 667
		ret = -EPIPE;
		goto out;
	}
L
Linus Torvalds 已提交
668

669
	if (copy_from_user(&ureq, arg, sizeof ureq)) {
L
Linus Torvalds 已提交
670 671 672 673 674
		ret = -EFAULT;
		goto out;
	}

	if (ureq.qpn != 0 && ureq.qpn != 1) {
675
		dev_notice(&file->port->dev,
676 677
			   "ib_umad_reg_agent: invalid QPN %d specified\n",
			   ureq.qpn);
L
Linus Torvalds 已提交
678 679 680 681 682
		ret = -EINVAL;
		goto out;
	}

	for (agent_id = 0; agent_id < IB_UMAD_MAX_AGENTS; ++agent_id)
683
		if (!__get_agent(file, agent_id))
L
Linus Torvalds 已提交
684 685
			goto found;

686
	dev_notice(&file->port->dev,
687 688
		   "ib_umad_reg_agent: Max Agents (%u) reached\n",
		   IB_UMAD_MAX_AGENTS);
L
Linus Torvalds 已提交
689 690 691 692
	ret = -ENOMEM;
	goto out;

found:
693
	if (ureq.mgmt_class) {
694
		memset(&req, 0, sizeof(req));
695 696
		req.mgmt_class         = ureq.mgmt_class;
		req.mgmt_class_version = ureq.mgmt_class_version;
697 698 699 700 701 702 703 704 705 706 707 708
		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);
709
	}
L
Linus Torvalds 已提交
710 711 712

	agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num,
				      ureq.qpn ? IB_QPT_GSI : IB_QPT_SMI,
713
				      ureq.mgmt_class ? &req : NULL,
714
				      ureq.rmpp_version,
715
				      send_handler, recv_handler, file, 0);
L
Linus Torvalds 已提交
716 717
	if (IS_ERR(agent)) {
		ret = PTR_ERR(agent);
718
		agent = NULL;
L
Linus Torvalds 已提交
719 720 721 722 723 724
		goto out;
	}

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

R
Roland Dreier 已提交
728 729 730
	if (!file->already_used) {
		file->already_used = 1;
		if (!file->use_pkey_index) {
731
			dev_warn(&file->port->dev,
732 733
				"process %s did not enable P_Key index support.\n",
				current->comm);
734
			dev_warn(&file->port->dev,
735
				"   Documentation/infiniband/user_mad.txt has info on the new ABI.\n");
R
Roland Dreier 已提交
736 737 738
		}
	}

739
	file->agent[agent_id] = agent;
L
Linus Torvalds 已提交
740
	ret = 0;
741

L
Linus Torvalds 已提交
742
out:
743 744 745 746 747 748 749
	mutex_unlock(&file->mutex);

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

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

L
Linus Torvalds 已提交
750 751 752
	return ret;
}

753 754 755 756 757 758 759 760 761 762 763 764
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) {
765
		dev_notice(&file->port->dev,
766 767 768 769 770 771 772 773 774 775 776
			   "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) {
777
		dev_notice(&file->port->dev,
778 779 780 781 782 783 784
			   "ib_umad_reg_agent2: invalid QPN %d specified\n",
			   ureq.qpn);
		ret = -EINVAL;
		goto out;
	}

	if (ureq.flags & ~IB_USER_MAD_REG_FLAGS_CAP) {
785
		dev_notice(&file->port->dev,
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
			   "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;

802
	dev_notice(&file->port->dev,
803 804 805 806 807 808 809 810 811 812 813
		   "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) {
814
			dev_notice(&file->port->dev,
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 855 856 857 858 859 860 861 862 863 864 865
				   "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;
}


866
static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
L
Linus Torvalds 已提交
867
{
868
	struct ib_mad_agent *agent = NULL;
L
Linus Torvalds 已提交
869 870 871
	u32 id;
	int ret = 0;

872
	if (get_user(id, arg))
873
		return -EFAULT;
L
Linus Torvalds 已提交
874

875 876
	mutex_lock(&file->port->file_mutex);
	mutex_lock(&file->mutex);
L
Linus Torvalds 已提交
877

878
	if (id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {
L
Linus Torvalds 已提交
879 880 881 882
		ret = -EINVAL;
		goto out;
	}

883
	agent = file->agent[id];
L
Linus Torvalds 已提交
884 885 886
	file->agent[id] = NULL;

out:
887
	mutex_unlock(&file->mutex);
888

889
	if (agent)
890 891
		ib_unregister_mad_agent(agent);

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

L
Linus Torvalds 已提交
894 895 896
	return ret;
}

R
Roland Dreier 已提交
897 898 899 900
static long ib_umad_enable_pkey(struct ib_umad_file *file)
{
	int ret = 0;

901
	mutex_lock(&file->mutex);
R
Roland Dreier 已提交
902 903 904 905
	if (file->already_used)
		ret = -EINVAL;
	else
		file->use_pkey_index = 1;
906
	mutex_unlock(&file->mutex);
R
Roland Dreier 已提交
907 908 909 910

	return ret;
}

911 912
static long ib_umad_ioctl(struct file *filp, unsigned int cmd,
			  unsigned long arg)
L
Linus Torvalds 已提交
913 914 915
{
	switch (cmd) {
	case IB_USER_MAD_REGISTER_AGENT:
916
		return ib_umad_reg_agent(filp->private_data, (void __user *) arg, 0);
L
Linus Torvalds 已提交
917
	case IB_USER_MAD_UNREGISTER_AGENT:
918
		return ib_umad_unreg_agent(filp->private_data, (__u32 __user *) arg);
R
Roland Dreier 已提交
919 920
	case IB_USER_MAD_ENABLE_PKEY:
		return ib_umad_enable_pkey(filp->private_data);
921 922
	case IB_USER_MAD_REGISTER_AGENT2:
		return ib_umad_reg_agent2(filp->private_data, (void __user *) arg);
L
Linus Torvalds 已提交
923 924 925 926 927
	default:
		return -ENOIOCTLCMD;
	}
}

928 929 930 931 932 933 934 935 936 937 938
#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);
939 940
	case IB_USER_MAD_REGISTER_AGENT2:
		return ib_umad_reg_agent2(filp->private_data, compat_ptr(arg));
941 942 943 944 945 946
	default:
		return -ENOIOCTLCMD;
	}
}
#endif

947 948 949
/*
 * ib_umad_open() does not need the BKL:
 *
A
Alexander Chiang 已提交
950
 *  - the ib_umad_port structures are properly reference counted, and
951 952 953 954 955
 *    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 已提交
956 957
static int ib_umad_open(struct inode *inode, struct file *filp)
{
958
	struct ib_umad_port *port;
L
Linus Torvalds 已提交
959
	struct ib_umad_file *file;
960
	int ret = 0;
L
Linus Torvalds 已提交
961

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

964
	mutex_lock(&port->file_mutex);
965

966 967
	if (!port->ib_dev) {
		ret = -ENXIO;
968
		goto out;
969
	}
970

971 972 973
	file = kzalloc(sizeof(*file), GFP_KERNEL);
	if (!file) {
		ret = -ENOMEM;
974
		goto out;
975
	}
L
Linus Torvalds 已提交
976

977
	mutex_init(&file->mutex);
978
	spin_lock_init(&file->send_lock);
L
Linus Torvalds 已提交
979
	INIT_LIST_HEAD(&file->recv_list);
980
	INIT_LIST_HEAD(&file->send_list);
L
Linus Torvalds 已提交
981 982 983 984 985
	init_waitqueue_head(&file->recv_wait);

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

986 987
	list_add_tail(&file->port_list, &port->file_list);

988
	nonseekable_open(inode, filp);
989
out:
990
	mutex_unlock(&port->file_mutex);
991
	return ret;
L
Linus Torvalds 已提交
992 993 994 995 996
}

static int ib_umad_close(struct inode *inode, struct file *filp)
{
	struct ib_umad_file *file = filp->private_data;
997
	struct ib_umad_packet *packet, *tmp;
998
	int already_dead;
L
Linus Torvalds 已提交
999 1000
	int i;

1001 1002
	mutex_lock(&file->port->file_mutex);
	mutex_lock(&file->mutex);
1003 1004 1005

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

1007 1008 1009
	list_for_each_entry_safe(packet, tmp, &file->recv_list, list) {
		if (packet->recv_wc)
			ib_free_recv_mad(packet->recv_wc);
1010
		kfree(packet);
1011
	}
1012

1013 1014
	list_del(&file->port_list);

1015
	mutex_unlock(&file->mutex);
1016 1017 1018 1019 1020

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

1022
	mutex_unlock(&file->port->file_mutex);
1023 1024

	kfree(file);
L
Linus Torvalds 已提交
1025 1026 1027
	return 0;
}

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

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

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

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

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

	filp->private_data = port;

1070
	nonseekable_open(inode, filp);
B
Bart Van Assche 已提交
1071 1072 1073 1074
	return 0;

err_up_sem:
	up(&port->sm_sem);
1075 1076 1077

fail:
	return ret;
L
Linus Torvalds 已提交
1078 1079 1080 1081 1082 1083 1084 1085
}

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
	};
1086 1087
	int ret = 0;

1088
	mutex_lock(&port->file_mutex);
1089 1090
	if (port->ib_dev)
		ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
1091
	mutex_unlock(&port->file_mutex);
L
Linus Torvalds 已提交
1092 1093 1094 1095 1096 1097

	up(&port->sm_sem);

	return ret;
}

1098
static const struct file_operations umad_sm_fops = {
A
Alexander Chiang 已提交
1099 1100
	.owner	 = THIS_MODULE,
	.open	 = ib_umad_sm_open,
1101 1102
	.release = ib_umad_sm_close,
	.llseek	 = no_llseek,
L
Linus Torvalds 已提交
1103 1104 1105 1106 1107 1108 1109 1110
};

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

1111
static ssize_t ibdev_show(struct device *dev, struct device_attribute *attr,
1112
			  char *buf)
L
Linus Torvalds 已提交
1113
{
1114
	struct ib_umad_port *port = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1115

1116 1117 1118
	if (!port)
		return -ENODEV;

1119
	return sprintf(buf, "%s\n", dev_name(&port->ib_dev->dev));
L
Linus Torvalds 已提交
1120
}
1121
static DEVICE_ATTR_RO(ibdev);
L
Linus Torvalds 已提交
1122

1123
static ssize_t port_show(struct device *dev, struct device_attribute *attr,
1124
			 char *buf)
L
Linus Torvalds 已提交
1125
{
1126
	struct ib_umad_port *port = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1127

1128 1129 1130
	if (!port)
		return -ENODEV;

L
Linus Torvalds 已提交
1131 1132
	return sprintf(buf, "%d\n", port->port_num);
}
1133 1134 1135 1136 1137 1138 1139 1140
static DEVICE_ATTR_RO(port);

static struct attribute *umad_class_dev_attrs[] = {
	&dev_attr_ibdev.attr,
	&dev_attr_port.attr,
	NULL,
};
ATTRIBUTE_GROUPS(umad_class_dev);
L
Linus Torvalds 已提交
1141

1142 1143 1144 1145 1146
static char *umad_devnode(struct device *dev, umode_t *mode)
{
	return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
}

1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159
static ssize_t abi_version_show(struct class *class,
				struct class_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", IB_USER_MAD_ABI_VERSION);
}
static CLASS_ATTR_RO(abi_version);

static struct attribute *umad_class_attrs[] = {
	&class_attr_abi_version.attr,
	NULL,
};
ATTRIBUTE_GROUPS(umad_class);

1160 1161 1162
static struct class umad_class = {
	.name		= "infiniband_mad",
	.devnode	= umad_devnode,
1163
	.class_groups	= umad_class_groups,
1164
	.dev_groups	= umad_class_dev_groups,
1165 1166
};

1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
static void ib_umad_release_port(struct device *device)
{
	struct ib_umad_port *port = dev_get_drvdata(device);
	struct ib_umad_device *umad_dev = port->umad_dev;

	ib_umad_dev_put(umad_dev);
}

static void ib_umad_init_port_dev(struct device *dev,
				  struct ib_umad_port *port,
				  const struct ib_device *device)
{
	device_initialize(dev);
	ib_umad_dev_get(port->umad_dev);
	dev->class = &umad_class;
	dev->parent = device->dev.parent;
	dev_set_drvdata(dev, port);
	dev->release = ib_umad_release_port;
}

L
Linus Torvalds 已提交
1187
static int ib_umad_init_port(struct ib_device *device, int port_num,
1188
			     struct ib_umad_device *umad_dev,
L
Linus Torvalds 已提交
1189 1190
			     struct ib_umad_port *port)
{
1191
	int devnum;
1192 1193
	dev_t base_umad;
	dev_t base_issm;
1194
	int ret;
1195

1196 1197
	devnum = ida_alloc_max(&umad_ida, IB_UMAD_MAX_PORTS - 1, GFP_KERNEL);
	if (devnum < 0)
1198 1199 1200 1201 1202
		return -1;
	port->dev_num = devnum;
	if (devnum >= IB_UMAD_NUM_FIXED_MINOR) {
		base_umad = dynamic_umad_dev + devnum - IB_UMAD_NUM_FIXED_MINOR;
		base_issm = dynamic_issm_dev + devnum - IB_UMAD_NUM_FIXED_MINOR;
1203
	} else {
1204 1205
		base_umad = devnum + base_umad_dev;
		base_issm = devnum + base_issm_dev;
L
Linus Torvalds 已提交
1206 1207 1208
	}

	port->ib_dev   = device;
1209
	port->umad_dev = umad_dev;
L
Linus Torvalds 已提交
1210
	port->port_num = port_num;
1211
	sema_init(&port->sm_sem, 1);
1212
	mutex_init(&port->file_mutex);
1213
	INIT_LIST_HEAD(&port->file_list);
L
Linus Torvalds 已提交
1214

1215 1216 1217
	ib_umad_init_port_dev(&port->dev, port, device);
	port->dev.devt = base_umad;
	dev_set_name(&port->dev, "umad%d", port->dev_num);
1218 1219
	cdev_init(&port->cdev, &umad_fops);
	port->cdev.owner = THIS_MODULE;
L
Linus Torvalds 已提交
1220

1221 1222
	ret = cdev_device_add(&port->cdev, &port->dev);
	if (ret)
1223
		goto err_cdev;
L
Linus Torvalds 已提交
1224

1225 1226 1227
	ib_umad_init_port_dev(&port->sm_dev, port, device);
	port->sm_dev.devt = base_issm;
	dev_set_name(&port->sm_dev, "issm%d", port->dev_num);
1228 1229
	cdev_init(&port->sm_cdev, &umad_sm_fops);
	port->sm_cdev.owner = THIS_MODULE;
1230 1231 1232 1233 1234

	ret = cdev_device_add(&port->sm_cdev, &port->sm_dev);
	if (ret)
		goto err_dev;

L
Linus Torvalds 已提交
1235 1236
	return 0;

1237
err_dev:
1238 1239
	put_device(&port->sm_dev);
	cdev_device_del(&port->cdev, &port->dev);
L
Linus Torvalds 已提交
1240
err_cdev:
1241
	put_device(&port->dev);
1242
	ida_free(&umad_ida, devnum);
1243
	return ret;
L
Linus Torvalds 已提交
1244 1245
}

1246 1247
static void ib_umad_kill_port(struct ib_umad_port *port)
{
1248 1249 1250
	struct ib_umad_file *file;
	int id;

1251
	mutex_lock(&port->file_mutex);
1252

1253 1254 1255
	/* Mark ib_dev NULL and block ioctl or other file ops to progress
	 * further.
	 */
1256 1257
	port->ib_dev = NULL;

1258 1259
	list_for_each_entry(file, &port->file_list, port_list) {
		mutex_lock(&file->mutex);
1260
		file->agents_dead = 1;
1261
		mutex_unlock(&file->mutex);
1262 1263 1264 1265 1266

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

1268
	mutex_unlock(&port->file_mutex);
1269

1270 1271
	cdev_device_del(&port->sm_cdev, &port->sm_dev);
	cdev_device_del(&port->cdev, &port->dev);
1272 1273
	ida_free(&umad_ida, port->dev_num);

1274
	/* balances device_initialize() */
1275
	put_device(&port->sm_dev);
1276
	put_device(&port->dev);
1277 1278
}

L
Linus Torvalds 已提交
1279 1280 1281 1282
static void ib_umad_add_one(struct ib_device *device)
{
	struct ib_umad_device *umad_dev;
	int s, e, i;
1283
	int count = 0;
L
Linus Torvalds 已提交
1284

1285 1286
	s = rdma_start_port(device);
	e = rdma_end_port(device);
L
Linus Torvalds 已提交
1287

1288
	umad_dev = kzalloc(struct_size(umad_dev, ports, e - s + 1), GFP_KERNEL);
L
Linus Torvalds 已提交
1289 1290 1291
	if (!umad_dev)
		return;

1292
	kref_init(&umad_dev->kref);
L
Linus Torvalds 已提交
1293
	for (i = s; i <= e; ++i) {
1294
		if (!rdma_cap_ib_mad(device, i))
1295 1296
			continue;

1297
		if (ib_umad_init_port(device, i, umad_dev,
1298
				      &umad_dev->ports[i - s]))
L
Linus Torvalds 已提交
1299
			goto err;
1300 1301

		count++;
L
Linus Torvalds 已提交
1302 1303
	}

1304 1305 1306
	if (!count)
		goto free;

L
Linus Torvalds 已提交
1307 1308 1309 1310 1311
	ib_set_client_data(device, &umad_client, umad_dev);

	return;

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

1316
		ib_umad_kill_port(&umad_dev->ports[i - s]);
1317 1318
	}
free:
1319
	/* balances kref_init */
1320
	ib_umad_dev_put(umad_dev);
L
Linus Torvalds 已提交
1321 1322
}

1323
static void ib_umad_remove_one(struct ib_device *device, void *client_data)
L
Linus Torvalds 已提交
1324
{
1325
	struct ib_umad_device *umad_dev = client_data;
L
Linus Torvalds 已提交
1326 1327 1328 1329 1330
	int i;

	if (!umad_dev)
		return;

1331
	for (i = 0; i <= rdma_end_port(device) - rdma_start_port(device); ++i) {
1332
		if (rdma_cap_ib_mad(device, i + rdma_start_port(device)))
1333
			ib_umad_kill_port(&umad_dev->ports[i]);
1334
	}
1335
	/* balances kref_init() */
1336
	ib_umad_dev_put(umad_dev);
L
Linus Torvalds 已提交
1337 1338 1339 1340 1341 1342
}

static int __init ib_umad_init(void)
{
	int ret;

1343 1344
	ret = register_chrdev_region(base_umad_dev,
				     IB_UMAD_NUM_FIXED_MINOR * 2,
1345
				     umad_class.name);
L
Linus Torvalds 已提交
1346
	if (ret) {
1347
		pr_err("couldn't register device number\n");
L
Linus Torvalds 已提交
1348 1349 1350
		goto out;
	}

1351 1352
	ret = alloc_chrdev_region(&dynamic_umad_dev, 0,
				  IB_UMAD_NUM_DYNAMIC_MINOR * 2,
1353
				  umad_class.name);
1354 1355 1356 1357 1358 1359
	if (ret) {
		pr_err("couldn't register dynamic device number\n");
		goto out_alloc;
	}
	dynamic_issm_dev = dynamic_umad_dev + IB_UMAD_NUM_DYNAMIC_MINOR;

1360 1361
	ret = class_register(&umad_class);
	if (ret) {
1362
		pr_err("couldn't create class infiniband_mad\n");
L
Linus Torvalds 已提交
1363 1364 1365 1366 1367
		goto out_chrdev;
	}

	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_unregister(&umad_class);
L
Linus Torvalds 已提交
1376 1377

out_chrdev:
1378 1379 1380 1381 1382 1383
	unregister_chrdev_region(dynamic_umad_dev,
				 IB_UMAD_NUM_DYNAMIC_MINOR * 2);

out_alloc:
	unregister_chrdev_region(base_umad_dev,
				 IB_UMAD_NUM_FIXED_MINOR * 2);
L
Linus Torvalds 已提交
1384 1385 1386 1387 1388 1389 1390 1391

out:
	return ret;
}

static void __exit ib_umad_cleanup(void)
{
	ib_unregister_client(&umad_client);
1392
	class_unregister(&umad_class);
1393 1394 1395 1396
	unregister_chrdev_region(base_umad_dev,
				 IB_UMAD_NUM_FIXED_MINOR * 2);
	unregister_chrdev_region(dynamic_umad_dev,
				 IB_UMAD_NUM_DYNAMIC_MINOR * 2);
L
Linus Torvalds 已提交
1397 1398 1399 1400
}

module_init(ib_umad_init);
module_exit(ib_umad_cleanup);