1faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty/* 243506d954e43933cd6fdcab679f6ab057e7607c6Roland Dreier * Copyright (c) 2006 Intel Corporation. All rights reserved. 3faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * 4faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * This software is available to you under a choice of one of two 5faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * licenses. You may choose to be licensed under the terms of the GNU 6faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * General Public License (GPL) Version 2, available from the file 7faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * COPYING in the main directory of this source tree, or the 8faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * OpenIB.org BSD license below: 9faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * 10faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * Redistribution and use in source and binary forms, with or 11faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * without modification, are permitted provided that the following 12faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * conditions are met: 13faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * 14faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * - Redistributions of source code must retain the above 15faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * copyright notice, this list of conditions and the following 16faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * disclaimer. 17faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * 18faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * - Redistributions in binary form must reproduce the above 19faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * copyright notice, this list of conditions and the following 20faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * disclaimer in the documentation and/or other materials 21faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * provided with the distribution. 22faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * 23faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * SOFTWARE. 31faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty */ 32faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 33faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty#include <linux/completion.h> 34faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty#include <linux/dma-mapping.h> 35faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty#include <linux/err.h> 36faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty#include <linux/interrupt.h> 37b108d9764cff25262bf764542ed1998d3e568962Paul Gortmaker#include <linux/export.h> 385a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 39faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty#include <linux/bitops.h> 40faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty#include <linux/random.h> 41faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 42faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty#include <rdma/ib_cache.h> 43faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty#include "sa.h" 44faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 45faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void mcast_add_one(struct ib_device *device); 46faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void mcast_remove_one(struct ib_device *device); 47faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 48faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic struct ib_client mcast_client = { 49faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty .name = "ib_multicast", 50faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty .add = mcast_add_one, 51faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty .remove = mcast_remove_one 52faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty}; 53faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 54faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic struct ib_sa_client sa_client; 55faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic struct workqueue_struct *mcast_wq; 56faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic union ib_gid mgid0; 57faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 58faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystruct mcast_device; 59faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 60faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystruct mcast_port { 61faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_device *dev; 62faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spinlock_t lock; 63faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct rb_root table; 64faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty atomic_t refcount; 65faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct completion comp; 66faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty u8 port_num; 67faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty}; 68faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 69faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystruct mcast_device { 70faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_device *device; 71faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_event_handler event_handler; 72faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int start_port; 73faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int end_port; 74faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_port port[0]; 75faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty}; 76faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 77faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftyenum mcast_state { 78faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty MCAST_JOINING, 79faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty MCAST_MEMBER, 80547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty MCAST_ERROR, 81547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty}; 82547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty 83547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Heftyenum mcast_group_state { 84547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty MCAST_IDLE, 85faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty MCAST_BUSY, 86547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty MCAST_GROUP_ERROR, 87547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty MCAST_PKEY_EVENT 88547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty}; 89547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty 90547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Heftyenum { 91547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty MCAST_INVALID_PKEY_INDEX = 0xFFFF 92faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty}; 93faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 94faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystruct mcast_member; 95faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 96faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystruct mcast_group { 97faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_sa_mcmember_rec rec; 98faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct rb_node node; 99faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_port *port; 100faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spinlock_t lock; 101faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct work_struct work; 102faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct list_head pending_list; 103faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct list_head active_list; 104faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_member *last_join; 105faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int members[3]; 106faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty atomic_t refcount; 107547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty enum mcast_group_state state; 108faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_sa_query *query; 109faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int query_id; 110547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty u16 pkey_index; 111e1d7806df32bd247af6a2fe52433ecdd34fee773Yossi Etigin u8 leave_state; 112e1d7806df32bd247af6a2fe52433ecdd34fee773Yossi Etigin int retries; 113faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty}; 114faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 115faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystruct mcast_member { 116faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_sa_multicast multicast; 117faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_sa_client *client; 118faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_group *group; 119faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct list_head list; 120faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty enum mcast_state state; 121faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty atomic_t refcount; 122faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct completion comp; 123faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty}; 124faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 125faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void join_handler(int status, struct ib_sa_mcmember_rec *rec, 126faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty void *context); 127faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void leave_handler(int status, struct ib_sa_mcmember_rec *rec, 128faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty void *context); 129faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 130faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic struct mcast_group *mcast_find(struct mcast_port *port, 131faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty union ib_gid *mgid) 132faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 133faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct rb_node *node = port->table.rb_node; 134faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_group *group; 135faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int ret; 136faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 137faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty while (node) { 138faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group = rb_entry(node, struct mcast_group, node); 139faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ret = memcmp(mgid->raw, group->rec.mgid.raw, sizeof *mgid); 140faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!ret) 141faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return group; 142faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 143faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (ret < 0) 144faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty node = node->rb_left; 145faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty else 146faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty node = node->rb_right; 147faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 148faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return NULL; 149faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 150faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 151faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic struct mcast_group *mcast_insert(struct mcast_port *port, 152faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_group *group, 153faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int allow_duplicates) 154faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 155faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct rb_node **link = &port->table.rb_node; 156faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct rb_node *parent = NULL; 157faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_group *cur_group; 158faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int ret; 159faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 160faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty while (*link) { 161faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty parent = *link; 162faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty cur_group = rb_entry(parent, struct mcast_group, node); 163faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 164faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ret = memcmp(group->rec.mgid.raw, cur_group->rec.mgid.raw, 165faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty sizeof group->rec.mgid); 166faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (ret < 0) 167faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty link = &(*link)->rb_left; 168faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty else if (ret > 0) 169faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty link = &(*link)->rb_right; 170faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty else if (allow_duplicates) 171faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty link = &(*link)->rb_left; 172faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty else 173faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return cur_group; 174faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 175faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty rb_link_node(&group->node, parent, link); 176faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty rb_insert_color(&group->node, &port->table); 177faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return NULL; 178faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 179faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 180faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void deref_port(struct mcast_port *port) 181faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 182faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (atomic_dec_and_test(&port->refcount)) 183faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty complete(&port->comp); 184faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 185faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 186faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void release_group(struct mcast_group *group) 187faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 188faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_port *port = group->port; 189faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty unsigned long flags; 190faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 191faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_irqsave(&port->lock, flags); 192faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (atomic_dec_and_test(&group->refcount)) { 193faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty rb_erase(&group->node, &port->table); 194faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irqrestore(&port->lock, flags); 195faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty kfree(group); 196faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty deref_port(port); 197faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } else 198faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irqrestore(&port->lock, flags); 199faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 200faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 201faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void deref_member(struct mcast_member *member) 202faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 203faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (atomic_dec_and_test(&member->refcount)) 204faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty complete(&member->comp); 205faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 206faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 207faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void queue_join(struct mcast_member *member) 208faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 209faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_group *group = member->group; 210faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty unsigned long flags; 211faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 212faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_irqsave(&group->lock, flags); 21357cb61d587e990d556385d367589ff61f6c2c0f2Ralph Campbell list_add_tail(&member->list, &group->pending_list); 214faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (group->state == MCAST_IDLE) { 215faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group->state = MCAST_BUSY; 216faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty atomic_inc(&group->refcount); 217faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty queue_work(mcast_wq, &group->work); 218faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 219faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irqrestore(&group->lock, flags); 220faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 221faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 222faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty/* 223faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * A multicast group has three types of members: full member, non member, and 224faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * send only member. We need to keep track of the number of members of each 225faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * type based on their join state. Adjust the number of members the belong to 226faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * the specified join states. 227faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty */ 228faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void adjust_membership(struct mcast_group *group, u8 join_state, int inc) 229faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 230faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int i; 231faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 232faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty for (i = 0; i < 3; i++, join_state >>= 1) 233faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (join_state & 0x1) 234faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group->members[i] += inc; 235faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 236faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 237faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty/* 238faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * If a multicast group has zero members left for a particular join state, but 239faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * the group is still a member with the SA, we need to leave that join state. 240faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * Determine which join states we still belong to, but that do not have any 241faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * active members. 242faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty */ 243faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic u8 get_leave_state(struct mcast_group *group) 244faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 245faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty u8 leave_state = 0; 246faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int i; 247faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 248faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty for (i = 0; i < 3; i++) 249faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!group->members[i]) 250faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty leave_state |= (0x1 << i); 251faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 252faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return leave_state & group->rec.join_state; 253faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 254faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 255faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic int check_selector(ib_sa_comp_mask comp_mask, 256faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_sa_comp_mask selector_mask, 257faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_sa_comp_mask value_mask, 258faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty u8 selector, u8 src_value, u8 dst_value) 259faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 260faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int err; 261faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 262faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!(comp_mask & selector_mask) || !(comp_mask & value_mask)) 263faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return 0; 264faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 265faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty switch (selector) { 266faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty case IB_SA_GT: 267faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty err = (src_value <= dst_value); 268faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty break; 269faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty case IB_SA_LT: 270faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty err = (src_value >= dst_value); 271faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty break; 272faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty case IB_SA_EQ: 273faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty err = (src_value != dst_value); 274faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty break; 275faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty default: 276faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty err = 0; 277faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty break; 278faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 279faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 280faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return err; 281faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 282faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 283faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic int cmp_rec(struct ib_sa_mcmember_rec *src, 284faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_sa_mcmember_rec *dst, ib_sa_comp_mask comp_mask) 285faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 286faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty /* MGID must already match */ 287faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 288faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (comp_mask & IB_SA_MCMEMBER_REC_PORT_GID && 289faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty memcmp(&src->port_gid, &dst->port_gid, sizeof src->port_gid)) 290faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return -EINVAL; 291faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (comp_mask & IB_SA_MCMEMBER_REC_QKEY && src->qkey != dst->qkey) 292faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return -EINVAL; 293faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (comp_mask & IB_SA_MCMEMBER_REC_MLID && src->mlid != dst->mlid) 294faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return -EINVAL; 295faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (check_selector(comp_mask, IB_SA_MCMEMBER_REC_MTU_SELECTOR, 296faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty IB_SA_MCMEMBER_REC_MTU, dst->mtu_selector, 297faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty src->mtu, dst->mtu)) 298faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return -EINVAL; 299faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (comp_mask & IB_SA_MCMEMBER_REC_TRAFFIC_CLASS && 300faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty src->traffic_class != dst->traffic_class) 301faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return -EINVAL; 302faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (comp_mask & IB_SA_MCMEMBER_REC_PKEY && src->pkey != dst->pkey) 303faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return -EINVAL; 304faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (check_selector(comp_mask, IB_SA_MCMEMBER_REC_RATE_SELECTOR, 305faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty IB_SA_MCMEMBER_REC_RATE, dst->rate_selector, 306faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty src->rate, dst->rate)) 307faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return -EINVAL; 308faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (check_selector(comp_mask, 309faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR, 310faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME, 311faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty dst->packet_life_time_selector, 312faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty src->packet_life_time, dst->packet_life_time)) 313faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return -EINVAL; 314faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (comp_mask & IB_SA_MCMEMBER_REC_SL && src->sl != dst->sl) 315faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return -EINVAL; 316faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (comp_mask & IB_SA_MCMEMBER_REC_FLOW_LABEL && 317faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty src->flow_label != dst->flow_label) 318faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return -EINVAL; 319faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (comp_mask & IB_SA_MCMEMBER_REC_HOP_LIMIT && 320faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty src->hop_limit != dst->hop_limit) 321faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return -EINVAL; 322faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (comp_mask & IB_SA_MCMEMBER_REC_SCOPE && src->scope != dst->scope) 323faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return -EINVAL; 324faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 325faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty /* join_state checked separately, proxy_join ignored */ 326faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 327faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return 0; 328faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 329faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 330faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic int send_join(struct mcast_group *group, struct mcast_member *member) 331faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 332faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_port *port = group->port; 333faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int ret; 334faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 335faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group->last_join = member; 336faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ret = ib_sa_mcmember_rec_query(&sa_client, port->dev->device, 337faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty port->port_num, IB_MGMT_METHOD_SET, 338faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty &member->multicast.rec, 339faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member->multicast.comp_mask, 340faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 3000, GFP_KERNEL, join_handler, group, 341faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty &group->query); 342faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (ret >= 0) { 343faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group->query_id = ret; 344faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ret = 0; 345faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 346faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return ret; 347faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 348faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 349faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic int send_leave(struct mcast_group *group, u8 leave_state) 350faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 351faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_port *port = group->port; 352faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_sa_mcmember_rec rec; 353faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int ret; 354faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 355faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty rec = group->rec; 356faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty rec.join_state = leave_state; 357e1d7806df32bd247af6a2fe52433ecdd34fee773Yossi Etigin group->leave_state = leave_state; 358faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 359faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ret = ib_sa_mcmember_rec_query(&sa_client, port->dev->device, 360faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty port->port_num, IB_SA_METHOD_DELETE, &rec, 361faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty IB_SA_MCMEMBER_REC_MGID | 362faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty IB_SA_MCMEMBER_REC_PORT_GID | 363faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty IB_SA_MCMEMBER_REC_JOIN_STATE, 364faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 3000, GFP_KERNEL, leave_handler, 365faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group, &group->query); 366faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (ret >= 0) { 367faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group->query_id = ret; 368faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ret = 0; 369faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 370faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return ret; 371faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 372faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 373faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void join_group(struct mcast_group *group, struct mcast_member *member, 374faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty u8 join_state) 375faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 376faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member->state = MCAST_MEMBER; 377faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty adjust_membership(group, join_state, 1); 378faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group->rec.join_state |= join_state; 379faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member->multicast.rec = group->rec; 380faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member->multicast.rec.join_state = join_state; 381faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty list_move(&member->list, &group->active_list); 382faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 383faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 384faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic int fail_join(struct mcast_group *group, struct mcast_member *member, 385faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int status) 386faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 387faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_irq(&group->lock); 388faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty list_del_init(&member->list); 389faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irq(&group->lock); 390faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return member->multicast.callback(status, &member->multicast); 391faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 392faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 393faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void process_group_error(struct mcast_group *group) 394faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 395faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_member *member; 396547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty int ret = 0; 397547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty u16 pkey_index; 398547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty 399547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty if (group->state == MCAST_PKEY_EVENT) 400547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty ret = ib_find_pkey(group->port->dev->device, 401547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty group->port->port_num, 402547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty be16_to_cpu(group->rec.pkey), &pkey_index); 403faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 404faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_irq(&group->lock); 405547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty if (group->state == MCAST_PKEY_EVENT && !ret && 406547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty group->pkey_index == pkey_index) 407547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty goto out; 408547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty 409faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty while (!list_empty(&group->active_list)) { 410faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member = list_entry(group->active_list.next, 411faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_member, list); 412faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty atomic_inc(&member->refcount); 413faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty list_del_init(&member->list); 414faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty adjust_membership(group, member->multicast.rec.join_state, -1); 415faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member->state = MCAST_ERROR; 416faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irq(&group->lock); 417faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 418faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ret = member->multicast.callback(-ENETRESET, 419faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty &member->multicast); 420faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty deref_member(member); 421faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (ret) 422faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_sa_free_multicast(&member->multicast); 423faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_irq(&group->lock); 424faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 425faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 426faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group->rec.join_state = 0; 427547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Heftyout: 428faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group->state = MCAST_BUSY; 429faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irq(&group->lock); 430faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 431faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 432faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void mcast_work_handler(struct work_struct *work) 433faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 434faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_group *group; 435faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_member *member; 436faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_sa_multicast *multicast; 437faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int status, ret; 438faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty u8 join_state; 439faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 440faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group = container_of(work, typeof(*group), work); 441faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftyretest: 442faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_irq(&group->lock); 443faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty while (!list_empty(&group->pending_list) || 444547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty (group->state != MCAST_BUSY)) { 445faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 446547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty if (group->state != MCAST_BUSY) { 447faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irq(&group->lock); 448faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty process_group_error(group); 449faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty goto retest; 450faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 451faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 452faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member = list_entry(group->pending_list.next, 453faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_member, list); 454faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty multicast = &member->multicast; 455faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty join_state = multicast->rec.join_state; 456faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty atomic_inc(&member->refcount); 457faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 458faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (join_state == (group->rec.join_state & join_state)) { 459faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty status = cmp_rec(&group->rec, &multicast->rec, 460faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty multicast->comp_mask); 461faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!status) 462faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty join_group(group, member, join_state); 463faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty else 464faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty list_del_init(&member->list); 465faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irq(&group->lock); 466faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ret = multicast->callback(status, multicast); 467faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } else { 468faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irq(&group->lock); 469faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty status = send_join(group, member); 470faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!status) { 471faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty deref_member(member); 472faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return; 473faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 474faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ret = fail_join(group, member, status); 475faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 476faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 477faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty deref_member(member); 478faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (ret) 479faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_sa_free_multicast(&member->multicast); 480faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_irq(&group->lock); 481faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 482faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 483faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty join_state = get_leave_state(group); 484faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (join_state) { 485faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group->rec.join_state &= ~join_state; 486faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irq(&group->lock); 487faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (send_leave(group, join_state)) 488faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty goto retest; 489faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } else { 490faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group->state = MCAST_IDLE; 491faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irq(&group->lock); 492faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty release_group(group); 493faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 494faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 495faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 496faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty/* 497faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * Fail a join request if it is still active - at the head of the pending queue. 498faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty */ 499faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void process_join_error(struct mcast_group *group, int status) 500faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 501faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_member *member; 502faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int ret; 503faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 504faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_irq(&group->lock); 505faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member = list_entry(group->pending_list.next, 506faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_member, list); 507faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (group->last_join == member) { 508faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty atomic_inc(&member->refcount); 509faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty list_del_init(&member->list); 510faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irq(&group->lock); 511faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ret = member->multicast.callback(status, &member->multicast); 512faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty deref_member(member); 513faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (ret) 514faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_sa_free_multicast(&member->multicast); 515faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } else 516faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irq(&group->lock); 517faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 518faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 519faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void join_handler(int status, struct ib_sa_mcmember_rec *rec, 520faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty void *context) 521faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 522faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_group *group = context; 523547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty u16 pkey_index = MCAST_INVALID_PKEY_INDEX; 524faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 525faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (status) 526faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty process_join_error(group, status); 527faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty else { 528547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty ib_find_pkey(group->port->dev->device, group->port->port_num, 529547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty be16_to_cpu(rec->pkey), &pkey_index); 530547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty 531faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_irq(&group->port->lock); 532faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group->rec = *rec; 533547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty if (group->state == MCAST_BUSY && 534547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty group->pkey_index == MCAST_INVALID_PKEY_INDEX) 535547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty group->pkey_index = pkey_index; 536faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) { 537faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty rb_erase(&group->node, &group->port->table); 538faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty mcast_insert(group->port, group, 1); 539faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 540faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irq(&group->port->lock); 541faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 542faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty mcast_work_handler(&group->work); 543faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 544faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 545faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void leave_handler(int status, struct ib_sa_mcmember_rec *rec, 546faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty void *context) 547faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 548faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_group *group = context; 549faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 550e1d7806df32bd247af6a2fe52433ecdd34fee773Yossi Etigin if (status && group->retries > 0 && 551e1d7806df32bd247af6a2fe52433ecdd34fee773Yossi Etigin !send_leave(group, group->leave_state)) 552e1d7806df32bd247af6a2fe52433ecdd34fee773Yossi Etigin group->retries--; 553e1d7806df32bd247af6a2fe52433ecdd34fee773Yossi Etigin else 554e1d7806df32bd247af6a2fe52433ecdd34fee773Yossi Etigin mcast_work_handler(&group->work); 555faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 556faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 557faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic struct mcast_group *acquire_group(struct mcast_port *port, 558faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty union ib_gid *mgid, gfp_t gfp_mask) 559faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 560faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_group *group, *cur_group; 561faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty unsigned long flags; 562faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int is_mgid0; 563faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 564faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty is_mgid0 = !memcmp(&mgid0, mgid, sizeof mgid0); 565faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!is_mgid0) { 566faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_irqsave(&port->lock, flags); 567faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group = mcast_find(port, mgid); 568faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (group) 569faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty goto found; 570faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irqrestore(&port->lock, flags); 571faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 572faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 573faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group = kzalloc(sizeof *group, gfp_mask); 574faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!group) 575faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return NULL; 576faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 577e1d7806df32bd247af6a2fe52433ecdd34fee773Yossi Etigin group->retries = 3; 578faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group->port = port; 579faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group->rec.mgid = *mgid; 580547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty group->pkey_index = MCAST_INVALID_PKEY_INDEX; 581faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty INIT_LIST_HEAD(&group->pending_list); 582faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty INIT_LIST_HEAD(&group->active_list); 583faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty INIT_WORK(&group->work, mcast_work_handler); 584faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_init(&group->lock); 585faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 586faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_irqsave(&port->lock, flags); 587faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty cur_group = mcast_insert(port, group, is_mgid0); 588faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (cur_group) { 589faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty kfree(group); 590faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group = cur_group; 591faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } else 592faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty atomic_inc(&port->refcount); 593faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftyfound: 594faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty atomic_inc(&group->refcount); 595faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irqrestore(&port->lock, flags); 596faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return group; 597faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 598faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 599faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty/* 600faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * We serialize all join requests to a single group to make our lives much 601faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * easier. Otherwise, two users could try to join the same group 602faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * simultaneously, with different configurations, one could leave while the 603faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * join is in progress, etc., which makes locking around error recovery 604faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * difficult. 605faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty */ 606faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystruct ib_sa_multicast * 607faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftyib_sa_join_multicast(struct ib_sa_client *client, 608faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_device *device, u8 port_num, 609faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_sa_mcmember_rec *rec, 610faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_sa_comp_mask comp_mask, gfp_t gfp_mask, 611faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int (*callback)(int status, 612faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_sa_multicast *multicast), 613faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty void *context) 614faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 615faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_device *dev; 616faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_member *member; 617faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_sa_multicast *multicast; 618faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int ret; 619faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 620faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty dev = ib_get_client_data(device, &mcast_client); 621faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!dev) 622faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return ERR_PTR(-ENODEV); 623faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 624faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member = kmalloc(sizeof *member, gfp_mask); 625faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!member) 626faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return ERR_PTR(-ENOMEM); 627faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 628faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_sa_client_get(client); 629faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member->client = client; 630faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member->multicast.rec = *rec; 631faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member->multicast.comp_mask = comp_mask; 632faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member->multicast.callback = callback; 633faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member->multicast.context = context; 634faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty init_completion(&member->comp); 635faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty atomic_set(&member->refcount, 1); 636faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member->state = MCAST_JOINING; 637faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 638faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member->group = acquire_group(&dev->port[port_num - dev->start_port], 639faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty &rec->mgid, gfp_mask); 640faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!member->group) { 641faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ret = -ENOMEM; 642faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty goto err; 643faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 644faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 645faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty /* 646faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * The user will get the multicast structure in their callback. They 647faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * could then free the multicast structure before we can return from 648faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * this routine. So we save the pointer to return before queuing 649faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty * any callback. 650faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty */ 651faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty multicast = &member->multicast; 652faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty queue_join(member); 653faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return multicast; 654faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 655faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftyerr: 656faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_sa_client_put(client); 657faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty kfree(member); 658faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return ERR_PTR(ret); 659faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 660faec2f7b96b555055d0aa6cc6b83a537270bed52Sean HeftyEXPORT_SYMBOL(ib_sa_join_multicast); 661faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 662faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftyvoid ib_sa_free_multicast(struct ib_sa_multicast *multicast) 663faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 664faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_member *member; 665faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_group *group; 666faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 667faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty member = container_of(multicast, struct mcast_member, multicast); 668faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group = member->group; 669faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 670faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_irq(&group->lock); 671faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (member->state == MCAST_MEMBER) 672faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty adjust_membership(group, multicast->rec.join_state, -1); 673faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 674faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty list_del_init(&member->list); 675faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 676faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (group->state == MCAST_IDLE) { 677faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group->state = MCAST_BUSY; 678faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irq(&group->lock); 679faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty /* Continue to hold reference on group until callback */ 680faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty queue_work(mcast_wq, &group->work); 681faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } else { 682faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irq(&group->lock); 683faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty release_group(group); 684faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 685faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 686faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty deref_member(member); 687faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty wait_for_completion(&member->comp); 688faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_sa_client_put(member->client); 689faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty kfree(member); 690faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 691faec2f7b96b555055d0aa6cc6b83a537270bed52Sean HeftyEXPORT_SYMBOL(ib_sa_free_multicast); 692faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 693faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftyint ib_sa_get_mcmember_rec(struct ib_device *device, u8 port_num, 694faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty union ib_gid *mgid, struct ib_sa_mcmember_rec *rec) 695faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 696faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_device *dev; 697faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_port *port; 698faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_group *group; 699faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty unsigned long flags; 700faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int ret = 0; 701faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 702faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty dev = ib_get_client_data(device, &mcast_client); 703faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!dev) 704faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return -ENODEV; 705faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 706faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty port = &dev->port[port_num - dev->start_port]; 707faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_irqsave(&port->lock, flags); 708faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group = mcast_find(port, mgid); 709faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (group) 710faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty *rec = group->rec; 711faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty else 712faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ret = -EADDRNOTAVAIL; 713faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irqrestore(&port->lock, flags); 714faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 715faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return ret; 716faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 717faec2f7b96b555055d0aa6cc6b83a537270bed52Sean HeftyEXPORT_SYMBOL(ib_sa_get_mcmember_rec); 718faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 719faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftyint ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num, 720faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_sa_mcmember_rec *rec, 721faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_ah_attr *ah_attr) 722faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 723faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int ret; 724faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty u16 gid_index; 725faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty u8 p; 726faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 727faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ret = ib_find_cached_gid(device, &rec->port_gid, &p, &gid_index); 728faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (ret) 729faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return ret; 730faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 731faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty memset(ah_attr, 0, sizeof *ah_attr); 732faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ah_attr->dlid = be16_to_cpu(rec->mlid); 733faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ah_attr->sl = rec->sl; 734faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ah_attr->port_num = port_num; 735faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ah_attr->static_rate = rec->rate; 736faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 737faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ah_attr->ah_flags = IB_AH_GRH; 738faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ah_attr->grh.dgid = rec->mgid; 739faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 740faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ah_attr->grh.sgid_index = (u8) gid_index; 741faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ah_attr->grh.flow_label = be32_to_cpu(rec->flow_label); 742faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ah_attr->grh.hop_limit = rec->hop_limit; 743faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ah_attr->grh.traffic_class = rec->traffic_class; 744faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 745faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return 0; 746faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 747faec2f7b96b555055d0aa6cc6b83a537270bed52Sean HeftyEXPORT_SYMBOL(ib_init_ah_from_mcmember); 748faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 749547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Heftystatic void mcast_groups_event(struct mcast_port *port, 750547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty enum mcast_group_state state) 751faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 752faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_group *group; 753faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct rb_node *node; 754faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty unsigned long flags; 755faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 756faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_irqsave(&port->lock, flags); 757faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty for (node = rb_first(&port->table); node; node = rb_next(node)) { 758faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty group = rb_entry(node, struct mcast_group, node); 759faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock(&group->lock); 760faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (group->state == MCAST_IDLE) { 761faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty atomic_inc(&group->refcount); 762faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty queue_work(mcast_wq, &group->work); 763faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 764547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty if (group->state != MCAST_GROUP_ERROR) 765547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty group->state = state; 766faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock(&group->lock); 767faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 768faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_unlock_irqrestore(&port->lock, flags); 769faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 770faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 771faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void mcast_event_handler(struct ib_event_handler *handler, 772faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct ib_event *event) 773faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 774faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_device *dev; 775547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty int index; 776faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 777faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty dev = container_of(handler, struct mcast_device, event_handler); 778fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen if (rdma_port_get_link_layer(dev->device, event->element.port_num) != 779fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen IB_LINK_LAYER_INFINIBAND) 780fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen return; 781fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen 782547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty index = event->element.port_num - dev->start_port; 783faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 784faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty switch (event->event) { 785faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty case IB_EVENT_PORT_ERR: 786faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty case IB_EVENT_LID_CHANGE: 787faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty case IB_EVENT_SM_CHANGE: 788faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty case IB_EVENT_CLIENT_REREGISTER: 789547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty mcast_groups_event(&dev->port[index], MCAST_GROUP_ERROR); 790547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty break; 791547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty case IB_EVENT_PKEY_CHANGE: 792547af76521b3fd4b9ec5c9a9975a17eadb95e6f6Sean Hefty mcast_groups_event(&dev->port[index], MCAST_PKEY_EVENT); 793faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty break; 794faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty default: 795faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty break; 796faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 797faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 798faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 799faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void mcast_add_one(struct ib_device *device) 800faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 801faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_device *dev; 802faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_port *port; 803faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int i; 804fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen int count = 0; 805faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 806faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) 807faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return; 808faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 809faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty dev = kmalloc(sizeof *dev + device->phys_port_cnt * sizeof *port, 810faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty GFP_KERNEL); 811faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!dev) 812faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return; 813faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 814faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (device->node_type == RDMA_NODE_IB_SWITCH) 815faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty dev->start_port = dev->end_port = 0; 816faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty else { 817faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty dev->start_port = 1; 818faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty dev->end_port = device->phys_port_cnt; 819faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 820faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 821faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty for (i = 0; i <= dev->end_port - dev->start_port; i++) { 822fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen if (rdma_port_get_link_layer(device, dev->start_port + i) != 823fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen IB_LINK_LAYER_INFINIBAND) 824fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen continue; 825faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty port = &dev->port[i]; 826faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty port->dev = dev; 827faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty port->port_num = dev->start_port + i; 828faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty spin_lock_init(&port->lock); 829faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty port->table = RB_ROOT; 830faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty init_completion(&port->comp); 831faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty atomic_set(&port->refcount, 1); 832fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen ++count; 833fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen } 834fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen 835fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen if (!count) { 836fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen kfree(dev); 837fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen return; 838faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 839faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 840faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty dev->device = device; 841faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_set_client_data(device, &mcast_client, dev); 842faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 843faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty INIT_IB_EVENT_HANDLER(&dev->event_handler, device, mcast_event_handler); 844faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_register_event_handler(&dev->event_handler); 845faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 846faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 847faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftystatic void mcast_remove_one(struct ib_device *device) 848faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 849faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_device *dev; 850faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty struct mcast_port *port; 851faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int i; 852faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 853faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty dev = ib_get_client_data(device, &mcast_client); 854faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!dev) 855faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return; 856faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 857faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_unregister_event_handler(&dev->event_handler); 858faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty flush_workqueue(mcast_wq); 859faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 860faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty for (i = 0; i <= dev->end_port - dev->start_port; i++) { 861fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen if (rdma_port_get_link_layer(device, dev->start_port + i) == 862fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen IB_LINK_LAYER_INFINIBAND) { 863fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen port = &dev->port[i]; 864fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen deref_port(port); 865fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen wait_for_completion(&port->comp); 866fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen } 867faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty } 868faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 869faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty kfree(dev); 870faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 871faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 872faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftyint mcast_init(void) 873faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 874faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty int ret; 875faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 876faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty mcast_wq = create_singlethread_workqueue("ib_mcast"); 877faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (!mcast_wq) 878faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return -ENOMEM; 879faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 880faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_sa_register_client(&sa_client); 881faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 882faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ret = ib_register_client(&mcast_client); 883faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty if (ret) 884faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty goto err; 885faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return 0; 886faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 887faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftyerr: 888faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_sa_unregister_client(&sa_client); 889faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty destroy_workqueue(mcast_wq); 890faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty return ret; 891faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 892faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty 893faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Heftyvoid mcast_cleanup(void) 894faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty{ 895faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_unregister_client(&mcast_client); 896faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty ib_sa_unregister_client(&sa_client); 897faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty destroy_workqueue(mcast_wq); 898faec2f7b96b555055d0aa6cc6b83a537270bed52Sean Hefty} 899