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
#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;
B
Bart Van Assche 已提交
960
	int ret = -ENXIO;
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

B
Bart Van Assche 已提交
966
	if (!port->ib_dev)
967 968
		goto out;

B
Bart Van Assche 已提交
969
	ret = -ENOMEM;
S
Sean Hefty 已提交
970
	file = kzalloc(sizeof *file, GFP_KERNEL);
B
Bart Van Assche 已提交
971
	if (!file)
972
		goto out;
L
Linus Torvalds 已提交
973

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

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

983 984
	list_add_tail(&file->port_list, &port->file_list);

985
	ret = nonseekable_open(inode, filp);
B
Bart Van Assche 已提交
986 987 988 989 990 991
	if (ret) {
		list_del(&file->port_list);
		kfree(file);
		goto out;
	}

992
out:
993
	mutex_unlock(&port->file_mutex);
994
	return ret;
L
Linus Torvalds 已提交
995 996 997 998 999
}

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

1004 1005
	mutex_lock(&file->port->file_mutex);
	mutex_lock(&file->mutex);
1006 1007 1008

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

1010 1011 1012
	list_for_each_entry_safe(packet, tmp, &file->recv_list, list) {
		if (packet->recv_wc)
			ib_free_recv_mad(packet->recv_wc);
1013
		kfree(packet);
1014
	}
1015

1016 1017
	list_del(&file->port_list);

1018
	mutex_unlock(&file->mutex);
1019 1020 1021 1022 1023

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

1025
	mutex_unlock(&file->port->file_mutex);
1026 1027

	kfree(file);
L
Linus Torvalds 已提交
1028 1029 1030
	return 0;
}

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

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

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

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

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

	filp->private_data = port;

B
Bart Van Assche 已提交
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
	ret = nonseekable_open(inode, filp);
	if (ret)
		goto err_clr_sm_cap;

	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);
1085 1086 1087

fail:
	return ret;
L
Linus Torvalds 已提交
1088 1089 1090 1091 1092 1093 1094 1095
}

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
	};
1096 1097
	int ret = 0;

1098
	mutex_lock(&port->file_mutex);
1099 1100
	if (port->ib_dev)
		ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
1101
	mutex_unlock(&port->file_mutex);
L
Linus Torvalds 已提交
1102 1103 1104 1105 1106 1107

	up(&port->sm_sem);

	return ret;
}

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

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

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

1126 1127 1128
	if (!port)
		return -ENODEV;

1129
	return sprintf(buf, "%s\n", dev_name(&port->ib_dev->dev));
L
Linus Torvalds 已提交
1130
}
1131
static DEVICE_ATTR_RO(ibdev);
L
Linus Torvalds 已提交
1132

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

1138 1139 1140
	if (!port)
		return -ENODEV;

L
Linus Torvalds 已提交
1141 1142
	return sprintf(buf, "%d\n", port->port_num);
}
1143 1144 1145 1146 1147 1148 1149 1150
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 已提交
1151

1152 1153 1154 1155 1156
static char *umad_devnode(struct device *dev, umode_t *mode)
{
	return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
}

1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
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);

1170 1171 1172
static struct class umad_class = {
	.name		= "infiniband_mad",
	.devnode	= umad_devnode,
1173
	.class_groups	= umad_class_groups,
1174
	.dev_groups	= umad_class_dev_groups,
1175 1176
};

1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
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 已提交
1197
static int ib_umad_init_port(struct ib_device *device, int port_num,
1198
			     struct ib_umad_device *umad_dev,
L
Linus Torvalds 已提交
1199 1200
			     struct ib_umad_port *port)
{
1201
	int devnum;
1202 1203
	dev_t base_umad;
	dev_t base_issm;
1204
	int ret;
1205

1206 1207
	devnum = ida_alloc_max(&umad_ida, IB_UMAD_MAX_PORTS - 1, GFP_KERNEL);
	if (devnum < 0)
1208 1209 1210 1211 1212
		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;
1213
	} else {
1214 1215
		base_umad = devnum + base_umad_dev;
		base_issm = devnum + base_issm_dev;
L
Linus Torvalds 已提交
1216 1217 1218
	}

	port->ib_dev   = device;
1219
	port->umad_dev = umad_dev;
L
Linus Torvalds 已提交
1220
	port->port_num = port_num;
1221
	sema_init(&port->sm_sem, 1);
1222
	mutex_init(&port->file_mutex);
1223
	INIT_LIST_HEAD(&port->file_list);
L
Linus Torvalds 已提交
1224

1225 1226 1227
	ib_umad_init_port_dev(&port->dev, port, device);
	port->dev.devt = base_umad;
	dev_set_name(&port->dev, "umad%d", port->dev_num);
1228 1229
	cdev_init(&port->cdev, &umad_fops);
	port->cdev.owner = THIS_MODULE;
L
Linus Torvalds 已提交
1230

1231 1232
	ret = cdev_device_add(&port->cdev, &port->dev);
	if (ret)
1233
		goto err_cdev;
L
Linus Torvalds 已提交
1234

1235 1236 1237
	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);
1238 1239
	cdev_init(&port->sm_cdev, &umad_sm_fops);
	port->sm_cdev.owner = THIS_MODULE;
1240 1241 1242 1243 1244

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

L
Linus Torvalds 已提交
1245 1246
	return 0;

1247
err_dev:
1248 1249
	put_device(&port->sm_dev);
	cdev_device_del(&port->cdev, &port->dev);
L
Linus Torvalds 已提交
1250
err_cdev:
1251
	put_device(&port->dev);
1252
	ida_free(&umad_ida, devnum);
1253
	return ret;
L
Linus Torvalds 已提交
1254 1255
}

1256 1257
static void ib_umad_kill_port(struct ib_umad_port *port)
{
1258 1259 1260
	struct ib_umad_file *file;
	int id;

1261
	mutex_lock(&port->file_mutex);
1262

1263 1264 1265
	/* Mark ib_dev NULL and block ioctl or other file ops to progress
	 * further.
	 */
1266 1267
	port->ib_dev = NULL;

1268 1269
	list_for_each_entry(file, &port->file_list, port_list) {
		mutex_lock(&file->mutex);
1270
		file->agents_dead = 1;
1271
		mutex_unlock(&file->mutex);
1272 1273 1274 1275 1276

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

1278
	mutex_unlock(&port->file_mutex);
1279

1280
	cdev_device_del(&port->sm_cdev, &port->sm_dev);
1281
	/* balances device_initialize() */
1282 1283
	put_device(&port->sm_dev);
	cdev_device_del(&port->cdev, &port->dev);
1284
	/* balances device_initialize() */
1285
	put_device(&port->dev);
1286
	ida_free(&umad_ida, port->dev_num);
1287 1288
}

L
Linus Torvalds 已提交
1289 1290 1291 1292
static void ib_umad_add_one(struct ib_device *device)
{
	struct ib_umad_device *umad_dev;
	int s, e, i;
1293
	int count = 0;
L
Linus Torvalds 已提交
1294

1295 1296
	s = rdma_start_port(device);
	e = rdma_end_port(device);
L
Linus Torvalds 已提交
1297

1298
	umad_dev = kzalloc(struct_size(umad_dev, ports, e - s + 1), GFP_KERNEL);
L
Linus Torvalds 已提交
1299 1300 1301
	if (!umad_dev)
		return;

1302
	kref_init(&umad_dev->kref);
L
Linus Torvalds 已提交
1303
	for (i = s; i <= e; ++i) {
1304
		if (!rdma_cap_ib_mad(device, i))
1305 1306
			continue;

1307
		if (ib_umad_init_port(device, i, umad_dev,
1308
				      &umad_dev->ports[i - s]))
L
Linus Torvalds 已提交
1309
			goto err;
1310 1311

		count++;
L
Linus Torvalds 已提交
1312 1313
	}

1314 1315 1316
	if (!count)
		goto free;

L
Linus Torvalds 已提交
1317 1318 1319 1320 1321
	ib_set_client_data(device, &umad_client, umad_dev);

	return;

err:
1322
	while (--i >= s) {
1323
		if (!rdma_cap_ib_mad(device, i))
1324
			continue;
L
Linus Torvalds 已提交
1325

1326
		ib_umad_kill_port(&umad_dev->ports[i - s]);
1327 1328
	}
free:
1329
	/* balances kref_init */
1330
	ib_umad_dev_put(umad_dev);
L
Linus Torvalds 已提交
1331 1332
}

1333
static void ib_umad_remove_one(struct ib_device *device, void *client_data)
L
Linus Torvalds 已提交
1334
{
1335
	struct ib_umad_device *umad_dev = client_data;
L
Linus Torvalds 已提交
1336 1337 1338 1339 1340
	int i;

	if (!umad_dev)
		return;

1341
	for (i = 0; i <= rdma_end_port(device) - rdma_start_port(device); ++i) {
1342
		if (rdma_cap_ib_mad(device, i + rdma_start_port(device)))
1343
			ib_umad_kill_port(&umad_dev->ports[i]);
1344
	}
1345
	/* balances kref_init() */
1346
	ib_umad_dev_put(umad_dev);
L
Linus Torvalds 已提交
1347 1348 1349 1350 1351 1352
}

static int __init ib_umad_init(void)
{
	int ret;

1353 1354
	ret = register_chrdev_region(base_umad_dev,
				     IB_UMAD_NUM_FIXED_MINOR * 2,
1355
				     umad_class.name);
L
Linus Torvalds 已提交
1356
	if (ret) {
1357
		pr_err("couldn't register device number\n");
L
Linus Torvalds 已提交
1358 1359 1360
		goto out;
	}

1361 1362
	ret = alloc_chrdev_region(&dynamic_umad_dev, 0,
				  IB_UMAD_NUM_DYNAMIC_MINOR * 2,
1363
				  umad_class.name);
1364 1365 1366 1367 1368 1369
	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;

1370 1371
	ret = class_register(&umad_class);
	if (ret) {
1372
		pr_err("couldn't create class infiniband_mad\n");
L
Linus Torvalds 已提交
1373 1374 1375 1376 1377
		goto out_chrdev;
	}

	ret = ib_register_client(&umad_client);
	if (ret) {
1378
		pr_err("couldn't register ib_umad client\n");
L
Linus Torvalds 已提交
1379 1380 1381 1382 1383 1384
		goto out_class;
	}

	return 0;

out_class:
1385
	class_unregister(&umad_class);
L
Linus Torvalds 已提交
1386 1387

out_chrdev:
1388 1389 1390 1391 1392 1393
	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 已提交
1394 1395 1396 1397 1398 1399 1400 1401

out:
	return ret;
}

static void __exit ib_umad_cleanup(void)
{
	ib_unregister_client(&umad_client);
1402
	class_unregister(&umad_class);
1403 1404 1405 1406
	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 已提交
1407 1408 1409 1410
}

module_init(ib_umad_init);
module_exit(ib_umad_cleanup);