aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/core/cm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband/core/cm.c')
-rw-r--r--drivers/infiniband/core/cm.c66
1 files changed, 45 insertions, 21 deletions
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 0de335b7bfc..f35fcc4c063 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. 2 * Copyright (c) 2004-2006 Intel Corporation. All rights reserved.
3 * Copyright (c) 2004 Topspin Corporation. All rights reserved. 3 * Copyright (c) 2004 Topspin Corporation. All rights reserved.
4 * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved. 4 * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved.
5 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 5 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
@@ -41,6 +41,7 @@
41#include <linux/idr.h> 41#include <linux/idr.h>
42#include <linux/interrupt.h> 42#include <linux/interrupt.h>
43#include <linux/pci.h> 43#include <linux/pci.h>
44#include <linux/random.h>
44#include <linux/rbtree.h> 45#include <linux/rbtree.h>
45#include <linux/spinlock.h> 46#include <linux/spinlock.h>
46#include <linux/workqueue.h> 47#include <linux/workqueue.h>
@@ -73,6 +74,7 @@ static struct ib_cm {
73 struct rb_root remote_id_table; 74 struct rb_root remote_id_table;
74 struct rb_root remote_sidr_table; 75 struct rb_root remote_sidr_table;
75 struct idr local_id_table; 76 struct idr local_id_table;
77 __be32 random_id_operand;
76 struct workqueue_struct *wq; 78 struct workqueue_struct *wq;
77} cm; 79} cm;
78 80
@@ -177,7 +179,7 @@ static int cm_alloc_msg(struct cm_id_private *cm_id_priv,
177 if (IS_ERR(ah)) 179 if (IS_ERR(ah))
178 return PTR_ERR(ah); 180 return PTR_ERR(ah);
179 181
180 m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn, 182 m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn,
181 cm_id_priv->av.pkey_index, 183 cm_id_priv->av.pkey_index,
182 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, 184 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
183 GFP_ATOMIC); 185 GFP_ATOMIC);
@@ -299,15 +301,17 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
299static int cm_alloc_id(struct cm_id_private *cm_id_priv) 301static int cm_alloc_id(struct cm_id_private *cm_id_priv)
300{ 302{
301 unsigned long flags; 303 unsigned long flags;
302 int ret; 304 int ret, id;
303 static int next_id; 305 static int next_id;
304 306
305 do { 307 do {
306 spin_lock_irqsave(&cm.lock, flags); 308 spin_lock_irqsave(&cm.lock, flags);
307 ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, next_id++, 309 ret = idr_get_new_above(&cm.local_id_table, cm_id_priv,
308 (__force int *) &cm_id_priv->id.local_id); 310 next_id++, &id);
309 spin_unlock_irqrestore(&cm.lock, flags); 311 spin_unlock_irqrestore(&cm.lock, flags);
310 } while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) ); 312 } while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) );
313
314 cm_id_priv->id.local_id = (__force __be32) (id ^ cm.random_id_operand);
311 return ret; 315 return ret;
312} 316}
313 317
@@ -316,7 +320,8 @@ static void cm_free_id(__be32 local_id)
316 unsigned long flags; 320 unsigned long flags;
317 321
318 spin_lock_irqsave(&cm.lock, flags); 322 spin_lock_irqsave(&cm.lock, flags);
319 idr_remove(&cm.local_id_table, (__force int) local_id); 323 idr_remove(&cm.local_id_table,
324 (__force int) (local_id ^ cm.random_id_operand));
320 spin_unlock_irqrestore(&cm.lock, flags); 325 spin_unlock_irqrestore(&cm.lock, flags);
321} 326}
322 327
@@ -324,7 +329,8 @@ static struct cm_id_private * cm_get_id(__be32 local_id, __be32 remote_id)
324{ 329{
325 struct cm_id_private *cm_id_priv; 330 struct cm_id_private *cm_id_priv;
326 331
327 cm_id_priv = idr_find(&cm.local_id_table, (__force int) local_id); 332 cm_id_priv = idr_find(&cm.local_id_table,
333 (__force int) (local_id ^ cm.random_id_operand));
328 if (cm_id_priv) { 334 if (cm_id_priv) {
329 if (cm_id_priv->id.remote_id == remote_id) 335 if (cm_id_priv->id.remote_id == remote_id)
330 atomic_inc(&cm_id_priv->refcount); 336 atomic_inc(&cm_id_priv->refcount);
@@ -679,6 +685,8 @@ static void cm_enter_timewait(struct cm_id_private *cm_id_priv)
679{ 685{
680 int wait_time; 686 int wait_time;
681 687
688 cm_cleanup_timewait(cm_id_priv->timewait_info);
689
682 /* 690 /*
683 * The cm_id could be destroyed by the user before we exit timewait. 691 * The cm_id could be destroyed by the user before we exit timewait.
684 * To protect against this, we search for the cm_id after exiting 692 * To protect against this, we search for the cm_id after exiting
@@ -1354,7 +1362,7 @@ static int cm_req_handler(struct cm_work *work)
1354 id.local_id); 1362 id.local_id);
1355 if (IS_ERR(cm_id_priv->timewait_info)) { 1363 if (IS_ERR(cm_id_priv->timewait_info)) {
1356 ret = PTR_ERR(cm_id_priv->timewait_info); 1364 ret = PTR_ERR(cm_id_priv->timewait_info);
1357 goto error1; 1365 goto destroy;
1358 } 1366 }
1359 cm_id_priv->timewait_info->work.remote_id = req_msg->local_comm_id; 1367 cm_id_priv->timewait_info->work.remote_id = req_msg->local_comm_id;
1360 cm_id_priv->timewait_info->remote_ca_guid = req_msg->local_ca_guid; 1368 cm_id_priv->timewait_info->remote_ca_guid = req_msg->local_ca_guid;
@@ -1363,7 +1371,8 @@ static int cm_req_handler(struct cm_work *work)
1363 listen_cm_id_priv = cm_match_req(work, cm_id_priv); 1371 listen_cm_id_priv = cm_match_req(work, cm_id_priv);
1364 if (!listen_cm_id_priv) { 1372 if (!listen_cm_id_priv) {
1365 ret = -EINVAL; 1373 ret = -EINVAL;
1366 goto error2; 1374 kfree(cm_id_priv->timewait_info);
1375 goto destroy;
1367 } 1376 }
1368 1377
1369 cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler; 1378 cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler;
@@ -1373,12 +1382,22 @@ static int cm_req_handler(struct cm_work *work)
1373 1382
1374 cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]); 1383 cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]);
1375 ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av); 1384 ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av);
1376 if (ret) 1385 if (ret) {
1377 goto error3; 1386 ib_get_cached_gid(work->port->cm_dev->device,
1387 work->port->port_num, 0, &work->path[0].sgid);
1388 ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_GID,
1389 &work->path[0].sgid, sizeof work->path[0].sgid,
1390 NULL, 0);
1391 goto rejected;
1392 }
1378 if (req_msg->alt_local_lid) { 1393 if (req_msg->alt_local_lid) {
1379 ret = cm_init_av_by_path(&work->path[1], &cm_id_priv->alt_av); 1394 ret = cm_init_av_by_path(&work->path[1], &cm_id_priv->alt_av);
1380 if (ret) 1395 if (ret) {
1381 goto error3; 1396 ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_ALT_GID,
1397 &work->path[0].sgid,
1398 sizeof work->path[0].sgid, NULL, 0);
1399 goto rejected;
1400 }
1382 } 1401 }
1383 cm_id_priv->tid = req_msg->hdr.tid; 1402 cm_id_priv->tid = req_msg->hdr.tid;
1384 cm_id_priv->timeout_ms = cm_convert_to_ms( 1403 cm_id_priv->timeout_ms = cm_convert_to_ms(
@@ -1400,12 +1419,11 @@ static int cm_req_handler(struct cm_work *work)
1400 cm_deref_id(listen_cm_id_priv); 1419 cm_deref_id(listen_cm_id_priv);
1401 return 0; 1420 return 0;
1402 1421
1403error3: atomic_dec(&cm_id_priv->refcount); 1422rejected:
1423 atomic_dec(&cm_id_priv->refcount);
1404 cm_deref_id(listen_cm_id_priv); 1424 cm_deref_id(listen_cm_id_priv);
1405 cm_cleanup_timewait(cm_id_priv->timewait_info); 1425destroy:
1406error2: kfree(cm_id_priv->timewait_info); 1426 ib_destroy_cm_id(cm_id);
1407 cm_id_priv->timewait_info = NULL;
1408error1: ib_destroy_cm_id(&cm_id_priv->id);
1409 return ret; 1427 return ret;
1410} 1428}
1411 1429
@@ -2072,8 +2090,9 @@ static struct cm_id_private * cm_acquire_rejected_id(struct cm_rej_msg *rej_msg)
2072 spin_unlock_irqrestore(&cm.lock, flags); 2090 spin_unlock_irqrestore(&cm.lock, flags);
2073 return NULL; 2091 return NULL;
2074 } 2092 }
2075 cm_id_priv = idr_find(&cm.local_id_table, 2093 cm_id_priv = idr_find(&cm.local_id_table, (__force int)
2076 (__force int) timewait_info->work.local_id); 2094 (timewait_info->work.local_id ^
2095 cm.random_id_operand));
2077 if (cm_id_priv) { 2096 if (cm_id_priv) {
2078 if (cm_id_priv->id.remote_id == remote_id) 2097 if (cm_id_priv->id.remote_id == remote_id)
2079 atomic_inc(&cm_id_priv->refcount); 2098 atomic_inc(&cm_id_priv->refcount);
@@ -3125,7 +3144,8 @@ static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv,
3125 qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE | 3144 qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE |
3126 IB_ACCESS_REMOTE_WRITE; 3145 IB_ACCESS_REMOTE_WRITE;
3127 if (cm_id_priv->responder_resources) 3146 if (cm_id_priv->responder_resources)
3128 qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ; 3147 qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ |
3148 IB_ACCESS_REMOTE_ATOMIC;
3129 qp_attr->pkey_index = cm_id_priv->av.pkey_index; 3149 qp_attr->pkey_index = cm_id_priv->av.pkey_index;
3130 qp_attr->port_num = cm_id_priv->av.port->port_num; 3150 qp_attr->port_num = cm_id_priv->av.port->port_num;
3131 ret = 0; 3151 ret = 0;
@@ -3262,6 +3282,9 @@ static void cm_add_one(struct ib_device *device)
3262 int ret; 3282 int ret;
3263 u8 i; 3283 u8 i;
3264 3284
3285 if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
3286 return;
3287
3265 cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) * 3288 cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) *
3266 device->phys_port_cnt, GFP_KERNEL); 3289 device->phys_port_cnt, GFP_KERNEL);
3267 if (!cm_dev) 3290 if (!cm_dev)
@@ -3349,6 +3372,7 @@ static int __init ib_cm_init(void)
3349 cm.remote_qp_table = RB_ROOT; 3372 cm.remote_qp_table = RB_ROOT;
3350 cm.remote_sidr_table = RB_ROOT; 3373 cm.remote_sidr_table = RB_ROOT;
3351 idr_init(&cm.local_id_table); 3374 idr_init(&cm.local_id_table);
3375 get_random_bytes(&cm.random_id_operand, sizeof cm.random_id_operand);
3352 idr_pre_get(&cm.local_id_table, GFP_KERNEL); 3376 idr_pre_get(&cm.local_id_table, GFP_KERNEL);
3353 3377
3354 cm.wq = create_workqueue("ib_cm"); 3378 cm.wq = create_workqueue("ib_cm");