diff options
author | Sean Hefty <sean.hefty@intel.com> | 2007-10-23 00:52:54 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2008-01-25 17:15:29 -0500 |
commit | 547af76521b3fd4b9ec5c9a9975a17eadb95e6f6 (patch) | |
tree | 99e9a0b9a3da4cb8f855601467aad11e7296d337 /drivers/infiniband/core | |
parent | 94545e8c51fbf01d1c1cda7e6d017598d41e840a (diff) |
IB/multicast: Report errors on multicast groups if P_key changes
P_key changes can invalidate multicast groups. Report errors on all
multicast groups affected by a pkey change.
Signed-off-by: Sean Hefty <sean.hefty@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/core')
-rw-r--r-- | drivers/infiniband/core/multicast.c | 55 |
1 files changed, 45 insertions, 10 deletions
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c index 1bc1fe60528..107f170c57c 100644 --- a/drivers/infiniband/core/multicast.c +++ b/drivers/infiniband/core/multicast.c | |||
@@ -73,11 +73,20 @@ struct mcast_device { | |||
73 | }; | 73 | }; |
74 | 74 | ||
75 | enum mcast_state { | 75 | enum mcast_state { |
76 | MCAST_IDLE, | ||
77 | MCAST_JOINING, | 76 | MCAST_JOINING, |
78 | MCAST_MEMBER, | 77 | MCAST_MEMBER, |
78 | MCAST_ERROR, | ||
79 | }; | ||
80 | |||
81 | enum mcast_group_state { | ||
82 | MCAST_IDLE, | ||
79 | MCAST_BUSY, | 83 | MCAST_BUSY, |
80 | MCAST_ERROR | 84 | MCAST_GROUP_ERROR, |
85 | MCAST_PKEY_EVENT | ||
86 | }; | ||
87 | |||
88 | enum { | ||
89 | MCAST_INVALID_PKEY_INDEX = 0xFFFF | ||
81 | }; | 90 | }; |
82 | 91 | ||
83 | struct mcast_member; | 92 | struct mcast_member; |
@@ -93,9 +102,10 @@ struct mcast_group { | |||
93 | struct mcast_member *last_join; | 102 | struct mcast_member *last_join; |
94 | int members[3]; | 103 | int members[3]; |
95 | atomic_t refcount; | 104 | atomic_t refcount; |
96 | enum mcast_state state; | 105 | enum mcast_group_state state; |
97 | struct ib_sa_query *query; | 106 | struct ib_sa_query *query; |
98 | int query_id; | 107 | int query_id; |
108 | u16 pkey_index; | ||
99 | }; | 109 | }; |
100 | 110 | ||
101 | struct mcast_member { | 111 | struct mcast_member { |
@@ -378,9 +388,19 @@ static int fail_join(struct mcast_group *group, struct mcast_member *member, | |||
378 | static void process_group_error(struct mcast_group *group) | 388 | static void process_group_error(struct mcast_group *group) |
379 | { | 389 | { |
380 | struct mcast_member *member; | 390 | struct mcast_member *member; |
381 | int ret; | 391 | int ret = 0; |
392 | u16 pkey_index; | ||
393 | |||
394 | if (group->state == MCAST_PKEY_EVENT) | ||
395 | ret = ib_find_pkey(group->port->dev->device, | ||
396 | group->port->port_num, | ||
397 | be16_to_cpu(group->rec.pkey), &pkey_index); | ||
382 | 398 | ||
383 | spin_lock_irq(&group->lock); | 399 | spin_lock_irq(&group->lock); |
400 | if (group->state == MCAST_PKEY_EVENT && !ret && | ||
401 | group->pkey_index == pkey_index) | ||
402 | goto out; | ||
403 | |||
384 | while (!list_empty(&group->active_list)) { | 404 | while (!list_empty(&group->active_list)) { |
385 | member = list_entry(group->active_list.next, | 405 | member = list_entry(group->active_list.next, |
386 | struct mcast_member, list); | 406 | struct mcast_member, list); |
@@ -399,6 +419,7 @@ static void process_group_error(struct mcast_group *group) | |||
399 | } | 419 | } |
400 | 420 | ||
401 | group->rec.join_state = 0; | 421 | group->rec.join_state = 0; |
422 | out: | ||
402 | group->state = MCAST_BUSY; | 423 | group->state = MCAST_BUSY; |
403 | spin_unlock_irq(&group->lock); | 424 | spin_unlock_irq(&group->lock); |
404 | } | 425 | } |
@@ -415,9 +436,9 @@ static void mcast_work_handler(struct work_struct *work) | |||
415 | retest: | 436 | retest: |
416 | spin_lock_irq(&group->lock); | 437 | spin_lock_irq(&group->lock); |
417 | while (!list_empty(&group->pending_list) || | 438 | while (!list_empty(&group->pending_list) || |
418 | (group->state == MCAST_ERROR)) { | 439 | (group->state != MCAST_BUSY)) { |
419 | 440 | ||
420 | if (group->state == MCAST_ERROR) { | 441 | if (group->state != MCAST_BUSY) { |
421 | spin_unlock_irq(&group->lock); | 442 | spin_unlock_irq(&group->lock); |
422 | process_group_error(group); | 443 | process_group_error(group); |
423 | goto retest; | 444 | goto retest; |
@@ -494,12 +515,19 @@ static void join_handler(int status, struct ib_sa_mcmember_rec *rec, | |||
494 | void *context) | 515 | void *context) |
495 | { | 516 | { |
496 | struct mcast_group *group = context; | 517 | struct mcast_group *group = context; |
518 | u16 pkey_index = MCAST_INVALID_PKEY_INDEX; | ||
497 | 519 | ||
498 | if (status) | 520 | if (status) |
499 | process_join_error(group, status); | 521 | process_join_error(group, status); |
500 | else { | 522 | else { |
523 | ib_find_pkey(group->port->dev->device, group->port->port_num, | ||
524 | be16_to_cpu(rec->pkey), &pkey_index); | ||
525 | |||
501 | spin_lock_irq(&group->port->lock); | 526 | spin_lock_irq(&group->port->lock); |
502 | group->rec = *rec; | 527 | group->rec = *rec; |
528 | if (group->state == MCAST_BUSY && | ||
529 | group->pkey_index == MCAST_INVALID_PKEY_INDEX) | ||
530 | group->pkey_index = pkey_index; | ||
503 | if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) { | 531 | if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) { |
504 | rb_erase(&group->node, &group->port->table); | 532 | rb_erase(&group->node, &group->port->table); |
505 | mcast_insert(group->port, group, 1); | 533 | mcast_insert(group->port, group, 1); |
@@ -539,6 +567,7 @@ static struct mcast_group *acquire_group(struct mcast_port *port, | |||
539 | 567 | ||
540 | group->port = port; | 568 | group->port = port; |
541 | group->rec.mgid = *mgid; | 569 | group->rec.mgid = *mgid; |
570 | group->pkey_index = MCAST_INVALID_PKEY_INDEX; | ||
542 | INIT_LIST_HEAD(&group->pending_list); | 571 | INIT_LIST_HEAD(&group->pending_list); |
543 | INIT_LIST_HEAD(&group->active_list); | 572 | INIT_LIST_HEAD(&group->active_list); |
544 | INIT_WORK(&group->work, mcast_work_handler); | 573 | INIT_WORK(&group->work, mcast_work_handler); |
@@ -707,7 +736,8 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num, | |||
707 | } | 736 | } |
708 | EXPORT_SYMBOL(ib_init_ah_from_mcmember); | 737 | EXPORT_SYMBOL(ib_init_ah_from_mcmember); |
709 | 738 | ||
710 | static void mcast_groups_lost(struct mcast_port *port) | 739 | static void mcast_groups_event(struct mcast_port *port, |
740 | enum mcast_group_state state) | ||
711 | { | 741 | { |
712 | struct mcast_group *group; | 742 | struct mcast_group *group; |
713 | struct rb_node *node; | 743 | struct rb_node *node; |
@@ -721,7 +751,8 @@ static void mcast_groups_lost(struct mcast_port *port) | |||
721 | atomic_inc(&group->refcount); | 751 | atomic_inc(&group->refcount); |
722 | queue_work(mcast_wq, &group->work); | 752 | queue_work(mcast_wq, &group->work); |
723 | } | 753 | } |
724 | group->state = MCAST_ERROR; | 754 | if (group->state != MCAST_GROUP_ERROR) |
755 | group->state = state; | ||
725 | spin_unlock(&group->lock); | 756 | spin_unlock(&group->lock); |
726 | } | 757 | } |
727 | spin_unlock_irqrestore(&port->lock, flags); | 758 | spin_unlock_irqrestore(&port->lock, flags); |
@@ -731,16 +762,20 @@ static void mcast_event_handler(struct ib_event_handler *handler, | |||
731 | struct ib_event *event) | 762 | struct ib_event *event) |
732 | { | 763 | { |
733 | struct mcast_device *dev; | 764 | struct mcast_device *dev; |
765 | int index; | ||
734 | 766 | ||
735 | dev = container_of(handler, struct mcast_device, event_handler); | 767 | dev = container_of(handler, struct mcast_device, event_handler); |
768 | index = event->element.port_num - dev->start_port; | ||
736 | 769 | ||
737 | switch (event->event) { | 770 | switch (event->event) { |
738 | case IB_EVENT_PORT_ERR: | 771 | case IB_EVENT_PORT_ERR: |
739 | case IB_EVENT_LID_CHANGE: | 772 | case IB_EVENT_LID_CHANGE: |
740 | case IB_EVENT_SM_CHANGE: | 773 | case IB_EVENT_SM_CHANGE: |
741 | case IB_EVENT_CLIENT_REREGISTER: | 774 | case IB_EVENT_CLIENT_REREGISTER: |
742 | mcast_groups_lost(&dev->port[event->element.port_num - | 775 | mcast_groups_event(&dev->port[index], MCAST_GROUP_ERROR); |
743 | dev->start_port]); | 776 | break; |
777 | case IB_EVENT_PKEY_CHANGE: | ||
778 | mcast_groups_event(&dev->port[index], MCAST_PKEY_EVENT); | ||
744 | break; | 779 | break; |
745 | default: | 780 | default: |
746 | break; | 781 | break; |