diff options
Diffstat (limited to 'drivers')
33 files changed, 3889 insertions, 958 deletions
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index afc612b8577d..ba2d6505e9a4 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig | |||
| @@ -29,6 +29,11 @@ config INFINIBAND_USER_ACCESS | |||
| 29 | libibverbs, libibcm and a hardware driver library from | 29 | libibverbs, libibcm and a hardware driver library from |
| 30 | <http://www.openib.org>. | 30 | <http://www.openib.org>. |
| 31 | 31 | ||
| 32 | config INFINIBAND_ADDR_TRANS | ||
| 33 | bool | ||
| 34 | depends on INFINIBAND && INET | ||
| 35 | default y | ||
| 36 | |||
| 32 | source "drivers/infiniband/hw/mthca/Kconfig" | 37 | source "drivers/infiniband/hw/mthca/Kconfig" |
| 33 | source "drivers/infiniband/hw/ipath/Kconfig" | 38 | source "drivers/infiniband/hw/ipath/Kconfig" |
| 34 | 39 | ||
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index ec3353f24b27..68e73ec2d1f8 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | infiniband-$(CONFIG_INFINIBAND_ADDR_TRANS) := ib_addr.o rdma_cm.o | ||
| 2 | |||
| 1 | obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o \ | 3 | obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o \ |
| 2 | ib_cm.o | 4 | ib_cm.o $(infiniband-y) |
| 3 | obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o | 5 | obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o |
| 4 | obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o | 6 | obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o |
| 5 | 7 | ||
| @@ -12,8 +14,13 @@ ib_sa-y := sa_query.o | |||
| 12 | 14 | ||
| 13 | ib_cm-y := cm.o | 15 | ib_cm-y := cm.o |
| 14 | 16 | ||
| 17 | rdma_cm-y := cma.o | ||
| 18 | |||
| 19 | ib_addr-y := addr.o | ||
| 20 | |||
| 15 | ib_umad-y := user_mad.o | 21 | ib_umad-y := user_mad.o |
| 16 | 22 | ||
| 17 | ib_ucm-y := ucm.o | 23 | ib_ucm-y := ucm.o |
| 18 | 24 | ||
| 19 | ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_mem.o | 25 | ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_mem.o \ |
| 26 | uverbs_marshall.o | ||
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c new file mode 100644 index 000000000000..d294bbc42f09 --- /dev/null +++ b/drivers/infiniband/core/addr.c | |||
| @@ -0,0 +1,367 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2005 Voltaire Inc. All rights reserved. | ||
| 3 | * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. | ||
| 4 | * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved. | ||
| 5 | * Copyright (c) 2005 Intel Corporation. All rights reserved. | ||
| 6 | * | ||
| 7 | * This Software is licensed under one of the following licenses: | ||
| 8 | * | ||
| 9 | * 1) under the terms of the "Common Public License 1.0" a copy of which is | ||
| 10 | * available from the Open Source Initiative, see | ||
| 11 | * http://www.opensource.org/licenses/cpl.php. | ||
| 12 | * | ||
| 13 | * 2) under the terms of the "The BSD License" a copy of which is | ||
| 14 | * available from the Open Source Initiative, see | ||
| 15 | * http://www.opensource.org/licenses/bsd-license.php. | ||
| 16 | * | ||
| 17 | * 3) under the terms of the "GNU General Public License (GPL) Version 2" a | ||
| 18 | * copy of which is available from the Open Source Initiative, see | ||
| 19 | * http://www.opensource.org/licenses/gpl-license.php. | ||
| 20 | * | ||
| 21 | * Licensee has the right to choose one of the above licenses. | ||
| 22 | * | ||
| 23 | * Redistributions of source code must retain the above copyright | ||
| 24 | * notice and one of the license notices. | ||
| 25 | * | ||
| 26 | * Redistributions in binary form must reproduce both the above copyright | ||
| 27 | * notice, one of the license notices in the documentation | ||
| 28 | * and/or other materials provided with the distribution. | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include <linux/mutex.h> | ||
| 32 | #include <linux/inetdevice.h> | ||
| 33 | #include <linux/workqueue.h> | ||
| 34 | #include <linux/if_arp.h> | ||
| 35 | #include <net/arp.h> | ||
| 36 | #include <net/neighbour.h> | ||
| 37 | #include <net/route.h> | ||
| 38 | #include <rdma/ib_addr.h> | ||
| 39 | |||
| 40 | MODULE_AUTHOR("Sean Hefty"); | ||
| 41 | MODULE_DESCRIPTION("IB Address Translation"); | ||
| 42 | MODULE_LICENSE("Dual BSD/GPL"); | ||
| 43 | |||
| 44 | struct addr_req { | ||
| 45 | struct list_head list; | ||
| 46 | struct sockaddr src_addr; | ||
| 47 | struct sockaddr dst_addr; | ||
| 48 | struct rdma_dev_addr *addr; | ||
| 49 | void *context; | ||
| 50 | void (*callback)(int status, struct sockaddr *src_addr, | ||
| 51 | struct rdma_dev_addr *addr, void *context); | ||
| 52 | unsigned long timeout; | ||
| 53 | int status; | ||
| 54 | }; | ||
| 55 | |||
| 56 | static void process_req(void *data); | ||
| 57 | |||
| 58 | static DEFINE_MUTEX(lock); | ||
| 59 | static LIST_HEAD(req_list); | ||
| 60 | static DECLARE_WORK(work, process_req, NULL); | ||
| 61 | static struct workqueue_struct *addr_wq; | ||
| 62 | |||
| 63 | static int copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, | ||
| 64 | unsigned char *dst_dev_addr) | ||
| 65 | { | ||
| 66 | switch (dev->type) { | ||
| 67 | case ARPHRD_INFINIBAND: | ||
| 68 | dev_addr->dev_type = IB_NODE_CA; | ||
| 69 | break; | ||
| 70 | default: | ||
| 71 | return -EADDRNOTAVAIL; | ||
| 72 | } | ||
| 73 | |||
| 74 | memcpy(dev_addr->src_dev_addr, dev->dev_addr, MAX_ADDR_LEN); | ||
| 75 | memcpy(dev_addr->broadcast, dev->broadcast, MAX_ADDR_LEN); | ||
| 76 | if (dst_dev_addr) | ||
| 77 | memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN); | ||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) | ||
| 82 | { | ||
| 83 | struct net_device *dev; | ||
| 84 | u32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr; | ||
| 85 | int ret; | ||
| 86 | |||
| 87 | dev = ip_dev_find(ip); | ||
| 88 | if (!dev) | ||
| 89 | return -EADDRNOTAVAIL; | ||
| 90 | |||
| 91 | ret = copy_addr(dev_addr, dev, NULL); | ||
| 92 | dev_put(dev); | ||
| 93 | return ret; | ||
| 94 | } | ||
| 95 | EXPORT_SYMBOL(rdma_translate_ip); | ||
| 96 | |||
| 97 | static void set_timeout(unsigned long time) | ||
| 98 | { | ||
| 99 | unsigned long delay; | ||
| 100 | |||
| 101 | cancel_delayed_work(&work); | ||
| 102 | |||
| 103 | delay = time - jiffies; | ||
| 104 | if ((long)delay <= 0) | ||
| 105 | delay = 1; | ||
| 106 | |||
| 107 | queue_delayed_work(addr_wq, &work, delay); | ||
| 108 | } | ||
| 109 | |||
| 110 | static void queue_req(struct addr_req *req) | ||
| 111 | { | ||
| 112 | struct addr_req *temp_req; | ||
| 113 | |||
| 114 | mutex_lock(&lock); | ||
| 115 | list_for_each_entry_reverse(temp_req, &req_list, list) { | ||
| 116 | if (time_after(req->timeout, temp_req->timeout)) | ||
| 117 | break; | ||
| 118 | } | ||
| 119 | |||
| 120 | list_add(&req->list, &temp_req->list); | ||
| 121 | |||
| 122 | if (req_list.next == &req->list) | ||
| 123 | set_timeout(req->timeout); | ||
| 124 | mutex_unlock(&lock); | ||
| 125 | } | ||
| 126 | |||
| 127 | static void addr_send_arp(struct sockaddr_in *dst_in) | ||
| 128 | { | ||
| 129 | struct rtable *rt; | ||
| 130 | struct flowi fl; | ||
| 131 | u32 dst_ip = dst_in->sin_addr.s_addr; | ||
| 132 | |||
| 133 | memset(&fl, 0, sizeof fl); | ||
| 134 | fl.nl_u.ip4_u.daddr = dst_ip; | ||
| 135 | if (ip_route_output_key(&rt, &fl)) | ||
| 136 | return; | ||
| 137 | |||
| 138 | arp_send(ARPOP_REQUEST, ETH_P_ARP, rt->rt_gateway, rt->idev->dev, | ||
| 139 | rt->rt_src, NULL, rt->idev->dev->dev_addr, NULL); | ||
| 140 | ip_rt_put(rt); | ||
| 141 | } | ||
| 142 | |||
| 143 | static int addr_resolve_remote(struct sockaddr_in *src_in, | ||
| 144 | struct sockaddr_in *dst_in, | ||
| 145 | struct rdma_dev_addr *addr) | ||
| 146 | { | ||
| 147 | u32 src_ip = src_in->sin_addr.s_addr; | ||
| 148 | u32 dst_ip = dst_in->sin_addr.s_addr; | ||
| 149 | struct flowi fl; | ||
| 150 | struct rtable *rt; | ||
| 151 | struct neighbour *neigh; | ||
| 152 | int ret; | ||
| 153 | |||
| 154 | memset(&fl, 0, sizeof fl); | ||
| 155 | fl.nl_u.ip4_u.daddr = dst_ip; | ||
| 156 | fl.nl_u.ip4_u.saddr = src_ip; | ||
| 157 | ret = ip_route_output_key(&rt, &fl); | ||
| 158 | if (ret) | ||
| 159 | goto out; | ||
| 160 | |||
| 161 | /* If the device does ARP internally, return 'done' */ | ||
| 162 | if (rt->idev->dev->flags & IFF_NOARP) { | ||
| 163 | copy_addr(addr, rt->idev->dev, NULL); | ||
| 164 | goto put; | ||
| 165 | } | ||
| 166 | |||
| 167 | neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev); | ||
| 168 | if (!neigh) { | ||
| 169 | ret = -ENODATA; | ||
| 170 | goto put; | ||
| 171 | } | ||
| 172 | |||
| 173 | if (!(neigh->nud_state & NUD_VALID)) { | ||
| 174 | ret = -ENODATA; | ||
| 175 | goto release; | ||
| 176 | } | ||
| 177 | |||
| 178 | if (!src_ip) { | ||
| 179 | src_in->sin_family = dst_in->sin_family; | ||
| 180 | src_in->sin_addr.s_addr = rt->rt_src; | ||
| 181 | } | ||
| 182 | |||
| 183 | ret = copy_addr(addr, neigh->dev, neigh->ha); | ||
| 184 | release: | ||
| 185 | neigh_release(neigh); | ||
| 186 | put: | ||
| 187 | ip_rt_put(rt); | ||
| 188 | out: | ||
| 189 | return ret; | ||
| 190 | } | ||
| 191 | |||
| 192 | static void process_req(void *data) | ||
| 193 | { | ||
| 194 | struct addr_req *req, *temp_req; | ||
| 195 | struct sockaddr_in *src_in, *dst_in; | ||
| 196 | struct list_head done_list; | ||
| 197 | |||
| 198 | INIT_LIST_HEAD(&done_list); | ||
| 199 | |||
| 200 | mutex_lock(&lock); | ||
| 201 | list_for_each_entry_safe(req, temp_req, &req_list, list) { | ||
| 202 | if (req->status) { | ||
| 203 | src_in = (struct sockaddr_in *) &req->src_addr; | ||
| 204 | dst_in = (struct sockaddr_in *) &req->dst_addr; | ||
| 205 | req->status = addr_resolve_remote(src_in, dst_in, | ||
| 206 | req->addr); | ||
| 207 | } | ||
| 208 | if (req->status && time_after(jiffies, req->timeout)) | ||
| 209 | req->status = -ETIMEDOUT; | ||
| 210 | else if (req->status == -ENODATA) | ||
| 211 | continue; | ||
| 212 | |||
| 213 | list_del(&req->list); | ||
| 214 | list_add_tail(&req->list, &done_list); | ||
| 215 | } | ||
| 216 | |||
| 217 | if (!list_empty(&req_list)) { | ||
| 218 | req = list_entry(req_list.next, struct addr_req, list); | ||
| 219 | set_timeout(req->timeout); | ||
| 220 | } | ||
| 221 | mutex_unlock(&lock); | ||
| 222 | |||
| 223 | list_for_each_entry_safe(req, temp_req, &done_list, list) { | ||
| 224 | list_del(&req->list); | ||
| 225 | req->callback(req->status, &req->src_addr, req->addr, | ||
| 226 | req->context); | ||
| 227 | kfree(req); | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | static int addr_resolve_local(struct sockaddr_in *src_in, | ||
| 232 | struct sockaddr_in *dst_in, | ||
| 233 | struct rdma_dev_addr *addr) | ||
| 234 | { | ||
| 235 | struct net_device *dev; | ||
| 236 | u32 src_ip = src_in->sin_addr.s_addr; | ||
| 237 | u32 dst_ip = dst_in->sin_addr.s_addr; | ||
| 238 | int ret; | ||
| 239 | |||
| 240 | dev = ip_dev_find(dst_ip); | ||
| 241 | if (!dev) | ||
| 242 | return -EADDRNOTAVAIL; | ||
| 243 | |||
| 244 | if (ZERONET(src_ip)) { | ||
| 245 | src_in->sin_family = dst_in->sin_family; | ||
| 246 | src_in->sin_addr.s_addr = dst_ip; | ||
| 247 | ret = copy_addr(addr, dev, dev->dev_addr); | ||
| 248 | } else if (LOOPBACK(src_ip)) { | ||
| 249 | ret = rdma_translate_ip((struct sockaddr *)dst_in, addr); | ||
| 250 | if (!ret) | ||
| 251 | memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); | ||
| 252 | } else { | ||
| 253 | ret = rdma_translate_ip((struct sockaddr *)src_in, addr); | ||
| 254 | if (!ret) | ||
| 255 | memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); | ||
| 256 | } | ||
| 257 | |||
| 258 | dev_put(dev); | ||
| 259 | return ret; | ||
| 260 | } | ||
| 261 | |||
| 262 | int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr, | ||
| 263 | struct rdma_dev_addr *addr, int timeout_ms, | ||
| 264 | void (*callback)(int status, struct sockaddr *src_addr, | ||
| 265 | struct rdma_dev_addr *addr, void *context), | ||
| 266 | void *context) | ||
| 267 | { | ||
| 268 | struct sockaddr_in *src_in, *dst_in; | ||
| 269 | struct addr_req *req; | ||
| 270 | int ret = 0; | ||
| 271 | |||
| 272 | req = kmalloc(sizeof *req, GFP_KERNEL); | ||
| 273 | if (!req) | ||
| 274 | return -ENOMEM; | ||
| 275 | memset(req, 0, sizeof *req); | ||
| 276 | |||
| 277 | if (src_addr) | ||
| 278 | memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr)); | ||
| 279 | memcpy(&req->dst_addr, dst_addr, ip_addr_size(dst_addr)); | ||
| 280 | req->addr = addr; | ||
| 281 | req->callback = callback; | ||
| 282 | req->context = context; | ||
| 283 | |||
| 284 | src_in = (struct sockaddr_in *) &req->src_addr; | ||
| 285 | dst_in = (struct sockaddr_in *) &req->dst_addr; | ||
| 286 | |||
| 287 | req->status = addr_resolve_local(src_in, dst_in, addr); | ||
| 288 | if (req->status == -EADDRNOTAVAIL) | ||
| 289 | req->status = addr_resolve_remote(src_in, dst_in, addr); | ||
| 290 | |||
| 291 | switch (req->status) { | ||
| 292 | case 0: | ||
| 293 | req->timeout = jiffies; | ||
| 294 | queue_req(req); | ||
| 295 | break; | ||
| 296 | case -ENODATA: | ||
| 297 | req->timeout = msecs_to_jiffies(timeout_ms) + jiffies; | ||
| 298 | queue_req(req); | ||
| 299 | addr_send_arp(dst_in); | ||
| 300 | break; | ||
| 301 | default: | ||
| 302 | ret = req->status; | ||
| 303 | kfree(req); | ||
| 304 | break; | ||
| 305 | } | ||
| 306 | return ret; | ||
| 307 | } | ||
| 308 | EXPORT_SYMBOL(rdma_resolve_ip); | ||
| 309 | |||
| 310 | void rdma_addr_cancel(struct rdma_dev_addr *addr) | ||
| 311 | { | ||
| 312 | struct addr_req *req, *temp_req; | ||
| 313 | |||
| 314 | mutex_lock(&lock); | ||
| 315 | list_for_each_entry_safe(req, temp_req, &req_list, list) { | ||
| 316 | if (req->addr == addr) { | ||
| 317 | req->status = -ECANCELED; | ||
| 318 | req->timeout = jiffies; | ||
| 319 | list_del(&req->list); | ||
| 320 | list_add(&req->list, &req_list); | ||
| 321 | set_timeout(req->timeout); | ||
| 322 | break; | ||
| 323 | } | ||
| 324 | } | ||
| 325 | mutex_unlock(&lock); | ||
| 326 | } | ||
| 327 | EXPORT_SYMBOL(rdma_addr_cancel); | ||
| 328 | |||
| 329 | static int addr_arp_recv(struct sk_buff *skb, struct net_device *dev, | ||
| 330 | struct packet_type *pkt, struct net_device *orig_dev) | ||
| 331 | { | ||
| 332 | struct arphdr *arp_hdr; | ||
| 333 | |||
| 334 | arp_hdr = (struct arphdr *) skb->nh.raw; | ||
| 335 | |||
| 336 | if (arp_hdr->ar_op == htons(ARPOP_REQUEST) || | ||
| 337 | arp_hdr->ar_op == htons(ARPOP_REPLY)) | ||
| 338 | set_timeout(jiffies); | ||
| 339 | |||
| 340 | kfree_skb(skb); | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | |||
| 344 | static struct packet_type addr_arp = { | ||
| 345 | .type = __constant_htons(ETH_P_ARP), | ||
| 346 | .func = addr_arp_recv, | ||
| 347 | .af_packet_priv = (void*) 1, | ||
| 348 | }; | ||
| 349 | |||
| 350 | static int addr_init(void) | ||
| 351 | { | ||
| 352 | addr_wq = create_singlethread_workqueue("ib_addr_wq"); | ||
| 353 | if (!addr_wq) | ||
| 354 | return -ENOMEM; | ||
| 355 | |||
| 356 | dev_add_pack(&addr_arp); | ||
| 357 | return 0; | ||
| 358 | } | ||
| 359 | |||
| 360 | static void addr_cleanup(void) | ||
| 361 | { | ||
| 362 | dev_remove_pack(&addr_arp); | ||
| 363 | destroy_workqueue(addr_wq); | ||
| 364 | } | ||
| 365 | |||
| 366 | module_init(addr_init); | ||
| 367 | module_exit(addr_cleanup); | ||
diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 50364c0b090c..e05ca2cdc73f 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c | |||
| @@ -191,6 +191,24 @@ int ib_find_cached_pkey(struct ib_device *device, | |||
| 191 | } | 191 | } |
| 192 | EXPORT_SYMBOL(ib_find_cached_pkey); | 192 | EXPORT_SYMBOL(ib_find_cached_pkey); |
| 193 | 193 | ||
| 194 | int ib_get_cached_lmc(struct ib_device *device, | ||
| 195 | u8 port_num, | ||
| 196 | u8 *lmc) | ||
| 197 | { | ||
| 198 | unsigned long flags; | ||
| 199 | int ret = 0; | ||
| 200 | |||
| 201 | if (port_num < start_port(device) || port_num > end_port(device)) | ||
| 202 | return -EINVAL; | ||
| 203 | |||
| 204 | read_lock_irqsave(&device->cache.lock, flags); | ||
| 205 | *lmc = device->cache.lmc_cache[port_num - start_port(device)]; | ||
| 206 | read_unlock_irqrestore(&device->cache.lock, flags); | ||
| 207 | |||
| 208 | return ret; | ||
| 209 | } | ||
| 210 | EXPORT_SYMBOL(ib_get_cached_lmc); | ||
| 211 | |||
| 194 | static void ib_cache_update(struct ib_device *device, | 212 | static void ib_cache_update(struct ib_device *device, |
| 195 | u8 port) | 213 | u8 port) |
| 196 | { | 214 | { |
| @@ -251,6 +269,8 @@ static void ib_cache_update(struct ib_device *device, | |||
| 251 | device->cache.pkey_cache[port - start_port(device)] = pkey_cache; | 269 | device->cache.pkey_cache[port - start_port(device)] = pkey_cache; |
| 252 | device->cache.gid_cache [port - start_port(device)] = gid_cache; | 270 | device->cache.gid_cache [port - start_port(device)] = gid_cache; |
| 253 | 271 | ||
| 272 | device->cache.lmc_cache[port - start_port(device)] = tprops->lmc; | ||
| 273 | |||
| 254 | write_unlock_irq(&device->cache.lock); | 274 | write_unlock_irq(&device->cache.lock); |
| 255 | 275 | ||
| 256 | kfree(old_pkey_cache); | 276 | kfree(old_pkey_cache); |
| @@ -305,7 +325,13 @@ static void ib_cache_setup_one(struct ib_device *device) | |||
| 305 | kmalloc(sizeof *device->cache.gid_cache * | 325 | kmalloc(sizeof *device->cache.gid_cache * |
| 306 | (end_port(device) - start_port(device) + 1), GFP_KERNEL); | 326 | (end_port(device) - start_port(device) + 1), GFP_KERNEL); |
| 307 | 327 | ||
| 308 | if (!device->cache.pkey_cache || !device->cache.gid_cache) { | 328 | device->cache.lmc_cache = kmalloc(sizeof *device->cache.lmc_cache * |
| 329 | (end_port(device) - | ||
| 330 | start_port(device) + 1), | ||
| 331 | GFP_KERNEL); | ||
| 332 | |||
| 333 | if (!device->cache.pkey_cache || !device->cache.gid_cache || | ||
| 334 | !device->cache.lmc_cache) { | ||
| 309 | printk(KERN_WARNING "Couldn't allocate cache " | 335 | printk(KERN_WARNING "Couldn't allocate cache " |
| 310 | "for %s\n", device->name); | 336 | "for %s\n", device->name); |
| 311 | goto err; | 337 | goto err; |
| @@ -333,6 +359,7 @@ err_cache: | |||
| 333 | err: | 359 | err: |
| 334 | kfree(device->cache.pkey_cache); | 360 | kfree(device->cache.pkey_cache); |
| 335 | kfree(device->cache.gid_cache); | 361 | kfree(device->cache.gid_cache); |
| 362 | kfree(device->cache.lmc_cache); | ||
| 336 | } | 363 | } |
| 337 | 364 | ||
| 338 | static void ib_cache_cleanup_one(struct ib_device *device) | 365 | static void ib_cache_cleanup_one(struct ib_device *device) |
| @@ -349,6 +376,7 @@ static void ib_cache_cleanup_one(struct ib_device *device) | |||
| 349 | 376 | ||
| 350 | kfree(device->cache.pkey_cache); | 377 | kfree(device->cache.pkey_cache); |
| 351 | kfree(device->cache.gid_cache); | 378 | kfree(device->cache.gid_cache); |
| 379 | kfree(device->cache.lmc_cache); | ||
| 352 | } | 380 | } |
| 353 | 381 | ||
| 354 | static struct ib_client cache_client = { | 382 | static struct ib_client cache_client = { |
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 86fee43502cd..450adfe0a4f1 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c | |||
| @@ -32,7 +32,7 @@ | |||
| 32 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 32 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 33 | * SOFTWARE. | 33 | * SOFTWARE. |
| 34 | * | 34 | * |
| 35 | * $Id: cm.c 2821 2005-07-08 17:07:28Z sean.hefty $ | 35 | * $Id: cm.c 4311 2005-12-05 18:42:01Z sean.hefty $ |
| 36 | */ | 36 | */ |
| 37 | 37 | ||
| 38 | #include <linux/completion.h> | 38 | #include <linux/completion.h> |
| @@ -132,6 +132,7 @@ struct cm_id_private { | |||
| 132 | /* todo: use alternate port on send failure */ | 132 | /* todo: use alternate port on send failure */ |
| 133 | struct cm_av av; | 133 | struct cm_av av; |
| 134 | struct cm_av alt_av; | 134 | struct cm_av alt_av; |
| 135 | struct ib_cm_compare_data *compare_data; | ||
| 135 | 136 | ||
| 136 | void *private_data; | 137 | void *private_data; |
| 137 | __be64 tid; | 138 | __be64 tid; |
| @@ -253,23 +254,13 @@ static void cm_set_private_data(struct cm_id_private *cm_id_priv, | |||
| 253 | cm_id_priv->private_data_len = private_data_len; | 254 | cm_id_priv->private_data_len = private_data_len; |
| 254 | } | 255 | } |
| 255 | 256 | ||
| 256 | static void cm_set_ah_attr(struct ib_ah_attr *ah_attr, u8 port_num, | 257 | static void cm_init_av_for_response(struct cm_port *port, struct ib_wc *wc, |
| 257 | u16 dlid, u8 sl, u16 src_path_bits) | 258 | struct ib_grh *grh, struct cm_av *av) |
| 258 | { | ||
| 259 | memset(ah_attr, 0, sizeof ah_attr); | ||
| 260 | ah_attr->dlid = dlid; | ||
| 261 | ah_attr->sl = sl; | ||
| 262 | ah_attr->src_path_bits = src_path_bits; | ||
| 263 | ah_attr->port_num = port_num; | ||
| 264 | } | ||
| 265 | |||
| 266 | static void cm_init_av_for_response(struct cm_port *port, | ||
| 267 | struct ib_wc *wc, struct cm_av *av) | ||
| 268 | { | 259 | { |
| 269 | av->port = port; | 260 | av->port = port; |
| 270 | av->pkey_index = wc->pkey_index; | 261 | av->pkey_index = wc->pkey_index; |
| 271 | cm_set_ah_attr(&av->ah_attr, port->port_num, wc->slid, | 262 | ib_init_ah_from_wc(port->cm_dev->device, port->port_num, wc, |
| 272 | wc->sl, wc->dlid_path_bits); | 263 | grh, &av->ah_attr); |
| 273 | } | 264 | } |
| 274 | 265 | ||
| 275 | static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av) | 266 | static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av) |
| @@ -299,9 +290,8 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av) | |||
| 299 | return ret; | 290 | return ret; |
| 300 | 291 | ||
| 301 | av->port = port; | 292 | av->port = port; |
| 302 | cm_set_ah_attr(&av->ah_attr, av->port->port_num, | 293 | ib_init_ah_from_path(cm_dev->device, port->port_num, path, |
| 303 | be16_to_cpu(path->dlid), path->sl, | 294 | &av->ah_attr); |
| 304 | be16_to_cpu(path->slid) & 0x7F); | ||
| 305 | av->packet_life_time = path->packet_life_time; | 295 | av->packet_life_time = path->packet_life_time; |
| 306 | return 0; | 296 | return 0; |
| 307 | } | 297 | } |
| @@ -357,6 +347,41 @@ static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id) | |||
| 357 | return cm_id_priv; | 347 | return cm_id_priv; |
| 358 | } | 348 | } |
| 359 | 349 | ||
| 350 | static void cm_mask_copy(u8 *dst, u8 *src, u8 *mask) | ||
| 351 | { | ||
| 352 | int i; | ||
| 353 | |||
| 354 | for (i = 0; i < IB_CM_COMPARE_SIZE / sizeof(unsigned long); i++) | ||
| 355 | ((unsigned long *) dst)[i] = ((unsigned long *) src)[i] & | ||
| 356 | ((unsigned long *) mask)[i]; | ||
| 357 | } | ||
| 358 | |||
| 359 | static int cm_compare_data(struct ib_cm_compare_data *src_data, | ||
| 360 | struct ib_cm_compare_data *dst_data) | ||
| 361 | { | ||
| 362 | u8 src[IB_CM_COMPARE_SIZE]; | ||
| 363 | u8 dst[IB_CM_COMPARE_SIZE]; | ||
| 364 | |||
| 365 | if (!src_data || !dst_data) | ||
| 366 | return 0; | ||
| 367 | |||
| 368 | cm_mask_copy(src, src_data->data, dst_data->mask); | ||
| 369 | cm_mask_copy(dst, dst_data->data, src_data->mask); | ||
| 370 | return memcmp(src, dst, IB_CM_COMPARE_SIZE); | ||
| 371 | } | ||
| 372 | |||
| 373 | static int cm_compare_private_data(u8 *private_data, | ||
| 374 | struct ib_cm_compare_data *dst_data) | ||
| 375 | { | ||
| 376 | u8 src[IB_CM_COMPARE_SIZE]; | ||
| 377 | |||
| 378 | if (!dst_data) | ||
| 379 | return 0; | ||
| 380 | |||
| 381 | cm_mask_copy(src, private_data, dst_data->mask); | ||
| 382 | return memcmp(src, dst_data->data, IB_CM_COMPARE_SIZE); | ||
| 383 | } | ||
| 384 | |||
| 360 | static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) | 385 | static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) |
| 361 | { | 386 | { |
| 362 | struct rb_node **link = &cm.listen_service_table.rb_node; | 387 | struct rb_node **link = &cm.listen_service_table.rb_node; |
| @@ -364,14 +389,18 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) | |||
| 364 | struct cm_id_private *cur_cm_id_priv; | 389 | struct cm_id_private *cur_cm_id_priv; |
| 365 | __be64 service_id = cm_id_priv->id.service_id; | 390 | __be64 service_id = cm_id_priv->id.service_id; |
| 366 | __be64 service_mask = cm_id_priv->id.service_mask; | 391 | __be64 service_mask = cm_id_priv->id.service_mask; |
| 392 | int data_cmp; | ||
| 367 | 393 | ||
| 368 | while (*link) { | 394 | while (*link) { |
| 369 | parent = *link; | 395 | parent = *link; |
| 370 | cur_cm_id_priv = rb_entry(parent, struct cm_id_private, | 396 | cur_cm_id_priv = rb_entry(parent, struct cm_id_private, |
| 371 | service_node); | 397 | service_node); |
| 398 | data_cmp = cm_compare_data(cm_id_priv->compare_data, | ||
| 399 | cur_cm_id_priv->compare_data); | ||
| 372 | if ((cur_cm_id_priv->id.service_mask & service_id) == | 400 | if ((cur_cm_id_priv->id.service_mask & service_id) == |
| 373 | (service_mask & cur_cm_id_priv->id.service_id) && | 401 | (service_mask & cur_cm_id_priv->id.service_id) && |
| 374 | (cm_id_priv->id.device == cur_cm_id_priv->id.device)) | 402 | (cm_id_priv->id.device == cur_cm_id_priv->id.device) && |
| 403 | !data_cmp) | ||
| 375 | return cur_cm_id_priv; | 404 | return cur_cm_id_priv; |
| 376 | 405 | ||
| 377 | if (cm_id_priv->id.device < cur_cm_id_priv->id.device) | 406 | if (cm_id_priv->id.device < cur_cm_id_priv->id.device) |
| @@ -380,6 +409,10 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) | |||
| 380 | link = &(*link)->rb_right; | 409 | link = &(*link)->rb_right; |
| 381 | else if (service_id < cur_cm_id_priv->id.service_id) | 410 | else if (service_id < cur_cm_id_priv->id.service_id) |
| 382 | link = &(*link)->rb_left; | 411 | link = &(*link)->rb_left; |
| 412 | else if (service_id > cur_cm_id_priv->id.service_id) | ||
| 413 | link = &(*link)->rb_right; | ||
| 414 | else if (data_cmp < 0) | ||
| 415 | link = &(*link)->rb_left; | ||
| 383 | else | 416 | else |
| 384 | link = &(*link)->rb_right; | 417 | link = &(*link)->rb_right; |
| 385 | } | 418 | } |
| @@ -389,16 +422,20 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) | |||
| 389 | } | 422 | } |
| 390 | 423 | ||
| 391 | static struct cm_id_private * cm_find_listen(struct ib_device *device, | 424 | static struct cm_id_private * cm_find_listen(struct ib_device *device, |
| 392 | __be64 service_id) | 425 | __be64 service_id, |
| 426 | u8 *private_data) | ||
| 393 | { | 427 | { |
| 394 | struct rb_node *node = cm.listen_service_table.rb_node; | 428 | struct rb_node *node = cm.listen_service_table.rb_node; |
| 395 | struct cm_id_private *cm_id_priv; | 429 | struct cm_id_private *cm_id_priv; |
| 430 | int data_cmp; | ||
| 396 | 431 | ||
| 397 | while (node) { | 432 | while (node) { |
| 398 | cm_id_priv = rb_entry(node, struct cm_id_private, service_node); | 433 | cm_id_priv = rb_entry(node, struct cm_id_private, service_node); |
| 434 | data_cmp = cm_compare_private_data(private_data, | ||
| 435 | cm_id_priv->compare_data); | ||
| 399 | if ((cm_id_priv->id.service_mask & service_id) == | 436 | if ((cm_id_priv->id.service_mask & service_id) == |
| 400 | cm_id_priv->id.service_id && | 437 | cm_id_priv->id.service_id && |
| 401 | (cm_id_priv->id.device == device)) | 438 | (cm_id_priv->id.device == device) && !data_cmp) |
| 402 | return cm_id_priv; | 439 | return cm_id_priv; |
| 403 | 440 | ||
| 404 | if (device < cm_id_priv->id.device) | 441 | if (device < cm_id_priv->id.device) |
| @@ -407,6 +444,10 @@ static struct cm_id_private * cm_find_listen(struct ib_device *device, | |||
| 407 | node = node->rb_right; | 444 | node = node->rb_right; |
| 408 | else if (service_id < cm_id_priv->id.service_id) | 445 | else if (service_id < cm_id_priv->id.service_id) |
| 409 | node = node->rb_left; | 446 | node = node->rb_left; |
| 447 | else if (service_id > cm_id_priv->id.service_id) | ||
| 448 | node = node->rb_right; | ||
| 449 | else if (data_cmp < 0) | ||
| 450 | node = node->rb_left; | ||
| 410 | else | 451 | else |
| 411 | node = node->rb_right; | 452 | node = node->rb_right; |
| 412 | } | 453 | } |
| @@ -730,15 +771,14 @@ retest: | |||
| 730 | wait_for_completion(&cm_id_priv->comp); | 771 | wait_for_completion(&cm_id_priv->comp); |
| 731 | while ((work = cm_dequeue_work(cm_id_priv)) != NULL) | 772 | while ((work = cm_dequeue_work(cm_id_priv)) != NULL) |
| 732 | cm_free_work(work); | 773 | cm_free_work(work); |
| 733 | if (cm_id_priv->private_data && cm_id_priv->private_data_len) | 774 | kfree(cm_id_priv->compare_data); |
| 734 | kfree(cm_id_priv->private_data); | 775 | kfree(cm_id_priv->private_data); |
| 735 | kfree(cm_id_priv); | 776 | kfree(cm_id_priv); |
| 736 | } | 777 | } |
| 737 | EXPORT_SYMBOL(ib_destroy_cm_id); | 778 | EXPORT_SYMBOL(ib_destroy_cm_id); |
| 738 | 779 | ||
| 739 | int ib_cm_listen(struct ib_cm_id *cm_id, | 780 | int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, |
| 740 | __be64 service_id, | 781 | struct ib_cm_compare_data *compare_data) |
| 741 | __be64 service_mask) | ||
| 742 | { | 782 | { |
| 743 | struct cm_id_private *cm_id_priv, *cur_cm_id_priv; | 783 | struct cm_id_private *cm_id_priv, *cur_cm_id_priv; |
| 744 | unsigned long flags; | 784 | unsigned long flags; |
| @@ -752,7 +792,19 @@ int ib_cm_listen(struct ib_cm_id *cm_id, | |||
| 752 | return -EINVAL; | 792 | return -EINVAL; |
| 753 | 793 | ||
| 754 | cm_id_priv = container_of(cm_id, struct cm_id_private, id); | 794 | cm_id_priv = container_of(cm_id, struct cm_id_private, id); |
| 755 | BUG_ON(cm_id->state != IB_CM_IDLE); | 795 | if (cm_id->state != IB_CM_IDLE) |
| 796 | return -EINVAL; | ||
| 797 | |||
| 798 | if (compare_data) { | ||
| 799 | cm_id_priv->compare_data = kzalloc(sizeof *compare_data, | ||
| 800 | GFP_KERNEL); | ||
| 801 | if (!cm_id_priv->compare_data) | ||
| 802 | return -ENOMEM; | ||
| 803 | cm_mask_copy(cm_id_priv->compare_data->data, | ||
| 804 | compare_data->data, compare_data->mask); | ||
| 805 | memcpy(cm_id_priv->compare_data->mask, compare_data->mask, | ||
| 806 | IB_CM_COMPARE_SIZE); | ||
| 807 | } | ||
| 756 | 808 | ||
| 757 | cm_id->state = IB_CM_LISTEN; | 809 | cm_id->state = IB_CM_LISTEN; |
| 758 | 810 | ||
| @@ -769,6 +821,8 @@ int ib_cm_listen(struct ib_cm_id *cm_id, | |||
| 769 | 821 | ||
| 770 | if (cur_cm_id_priv) { | 822 | if (cur_cm_id_priv) { |
| 771 | cm_id->state = IB_CM_IDLE; | 823 | cm_id->state = IB_CM_IDLE; |
| 824 | kfree(cm_id_priv->compare_data); | ||
| 825 | cm_id_priv->compare_data = NULL; | ||
| 772 | ret = -EBUSY; | 826 | ret = -EBUSY; |
| 773 | } | 827 | } |
| 774 | return ret; | 828 | return ret; |
| @@ -1241,7 +1295,8 @@ static struct cm_id_private * cm_match_req(struct cm_work *work, | |||
| 1241 | 1295 | ||
| 1242 | /* Find matching listen request. */ | 1296 | /* Find matching listen request. */ |
| 1243 | listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device, | 1297 | listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device, |
| 1244 | req_msg->service_id); | 1298 | req_msg->service_id, |
| 1299 | req_msg->private_data); | ||
| 1245 | if (!listen_cm_id_priv) { | 1300 | if (!listen_cm_id_priv) { |
| 1246 | spin_unlock_irqrestore(&cm.lock, flags); | 1301 | spin_unlock_irqrestore(&cm.lock, flags); |
| 1247 | cm_issue_rej(work->port, work->mad_recv_wc, | 1302 | cm_issue_rej(work->port, work->mad_recv_wc, |
| @@ -1276,6 +1331,7 @@ static int cm_req_handler(struct cm_work *work) | |||
| 1276 | cm_id_priv = container_of(cm_id, struct cm_id_private, id); | 1331 | cm_id_priv = container_of(cm_id, struct cm_id_private, id); |
| 1277 | cm_id_priv->id.remote_id = req_msg->local_comm_id; | 1332 | cm_id_priv->id.remote_id = req_msg->local_comm_id; |
| 1278 | cm_init_av_for_response(work->port, work->mad_recv_wc->wc, | 1333 | cm_init_av_for_response(work->port, work->mad_recv_wc->wc, |
| 1334 | work->mad_recv_wc->recv_buf.grh, | ||
| 1279 | &cm_id_priv->av); | 1335 | &cm_id_priv->av); |
| 1280 | cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv-> | 1336 | cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv-> |
| 1281 | id.local_id); | 1337 | id.local_id); |
| @@ -2549,7 +2605,7 @@ static void cm_format_sidr_req(struct cm_sidr_req_msg *sidr_req_msg, | |||
| 2549 | cm_format_mad_hdr(&sidr_req_msg->hdr, CM_SIDR_REQ_ATTR_ID, | 2605 | cm_format_mad_hdr(&sidr_req_msg->hdr, CM_SIDR_REQ_ATTR_ID, |
| 2550 | cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_SIDR)); | 2606 | cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_SIDR)); |
| 2551 | sidr_req_msg->request_id = cm_id_priv->id.local_id; | 2607 | sidr_req_msg->request_id = cm_id_priv->id.local_id; |
| 2552 | sidr_req_msg->pkey = cpu_to_be16(param->pkey); | 2608 | sidr_req_msg->pkey = cpu_to_be16(param->path->pkey); |
| 2553 | sidr_req_msg->service_id = param->service_id; | 2609 | sidr_req_msg->service_id = param->service_id; |
| 2554 | 2610 | ||
| 2555 | if (param->private_data && param->private_data_len) | 2611 | if (param->private_data && param->private_data_len) |
| @@ -2641,6 +2697,7 @@ static int cm_sidr_req_handler(struct cm_work *work) | |||
| 2641 | cm_id_priv->av.dgid.global.subnet_prefix = cpu_to_be64(wc->slid); | 2697 | cm_id_priv->av.dgid.global.subnet_prefix = cpu_to_be64(wc->slid); |
| 2642 | cm_id_priv->av.dgid.global.interface_id = 0; | 2698 | cm_id_priv->av.dgid.global.interface_id = 0; |
| 2643 | cm_init_av_for_response(work->port, work->mad_recv_wc->wc, | 2699 | cm_init_av_for_response(work->port, work->mad_recv_wc->wc, |
| 2700 | work->mad_recv_wc->recv_buf.grh, | ||
| 2644 | &cm_id_priv->av); | 2701 | &cm_id_priv->av); |
| 2645 | cm_id_priv->id.remote_id = sidr_req_msg->request_id; | 2702 | cm_id_priv->id.remote_id = sidr_req_msg->request_id; |
| 2646 | cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD; | 2703 | cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD; |
| @@ -2654,7 +2711,8 @@ static int cm_sidr_req_handler(struct cm_work *work) | |||
| 2654 | goto out; /* Duplicate message. */ | 2711 | goto out; /* Duplicate message. */ |
| 2655 | } | 2712 | } |
| 2656 | cur_cm_id_priv = cm_find_listen(cm_id->device, | 2713 | cur_cm_id_priv = cm_find_listen(cm_id->device, |
| 2657 | sidr_req_msg->service_id); | 2714 | sidr_req_msg->service_id, |
| 2715 | sidr_req_msg->private_data); | ||
| 2658 | if (!cur_cm_id_priv) { | 2716 | if (!cur_cm_id_priv) { |
| 2659 | rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); | 2717 | rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); |
| 2660 | spin_unlock_irqrestore(&cm.lock, flags); | 2718 | spin_unlock_irqrestore(&cm.lock, flags); |
| @@ -3291,7 +3349,6 @@ error: | |||
| 3291 | 3349 | ||
| 3292 | static void __exit ib_cm_cleanup(void) | 3350 | static void __exit ib_cm_cleanup(void) |
| 3293 | { | 3351 | { |
| 3294 | flush_workqueue(cm.wq); | ||
| 3295 | destroy_workqueue(cm.wq); | 3352 | destroy_workqueue(cm.wq); |
| 3296 | ib_unregister_client(&cm_client); | 3353 | ib_unregister_client(&cm_client); |
| 3297 | idr_destroy(&cm.local_id_table); | 3354 | idr_destroy(&cm.local_id_table); |
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c new file mode 100644 index 000000000000..a76834edf608 --- /dev/null +++ b/drivers/infiniband/core/cma.c | |||
| @@ -0,0 +1,1927 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2005 Voltaire Inc. All rights reserved. | ||
| 3 | * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. | ||
| 4 | * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved. | ||
| 5 | * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. | ||
| 6 | * | ||
| 7 | * This Software is licensed under one of the following licenses: | ||
| 8 | * | ||
| 9 | * 1) under the terms of the "Common Public License 1.0" a copy of which is | ||
| 10 | * available from the Open Source Initiative, see | ||
| 11 | * http://www.opensource.org/licenses/cpl.php. | ||
| 12 | * | ||
| 13 | * 2) under the terms of the "The BSD License" a copy of which is | ||
| 14 | * available from the Open Source Initiative, see | ||
| 15 | * http://www.opensource.org/licenses/bsd-license.php. | ||
| 16 | * | ||
| 17 | * 3) under the terms of the "GNU General Public License (GPL) Version 2" a | ||
| 18 | * copy of which is available from the Open Source Initiative, see | ||
| 19 | * http://www.opensource.org/licenses/gpl-license.php. | ||
| 20 | * | ||
| 21 | * Licensee has the right to choose one of the above licenses. | ||
| 22 | * | ||
| 23 | * Redistributions of source code must retain the above copyright | ||
| 24 | * notice and one of the license notices. | ||
| 25 | * | ||
| 26 | * Redistributions in binary form must reproduce both the above copyright | ||
| 27 | * notice, one of the license notices in the documentation | ||
| 28 | * and/or other materials provided with the distribution. | ||
| 29 | * | ||
| 30 | */ | ||
| 31 | |||
| 32 | #include <linux/completion.h> | ||
| 33 | #include <linux/in.h> | ||
| 34 | #include <linux/in6.h> | ||
| 35 | #include <linux/mutex.h> | ||
| 36 | #include <linux/random.h> | ||
| 37 | #include <linux/idr.h> | ||
| 38 | |||
| 39 | #include <net/tcp.h> | ||
| 40 | |||
| 41 | #include <rdma/rdma_cm.h> | ||
| 42 | #include <rdma/rdma_cm_ib.h> | ||
| 43 | #include <rdma/ib_cache.h> | ||
| 44 | #include <rdma/ib_cm.h> | ||
| 45 | #include <rdma/ib_sa.h> | ||
| 46 | |||
| 47 | MODULE_AUTHOR("Sean Hefty"); | ||
| 48 | MODULE_DESCRIPTION("Generic RDMA CM Agent"); | ||
| 49 | MODULE_LICENSE("Dual BSD/GPL"); | ||
| 50 | |||
| 51 | #define CMA_CM_RESPONSE_TIMEOUT 20 | ||
| 52 | #define CMA_MAX_CM_RETRIES 3 | ||
| 53 | |||
| 54 | static void cma_add_one(struct ib_device *device); | ||
| 55 | static void cma_remove_one(struct ib_device *device); | ||
| 56 | |||
| 57 | static struct ib_client cma_client = { | ||
| 58 | .name = "cma", | ||
| 59 | .add = cma_add_one, | ||
| 60 | .remove = cma_remove_one | ||
| 61 | }; | ||
| 62 | |||
| 63 | static LIST_HEAD(dev_list); | ||
| 64 | static LIST_HEAD(listen_any_list); | ||
| 65 | static DEFINE_MUTEX(lock); | ||
| 66 | static struct workqueue_struct *cma_wq; | ||
| 67 | static DEFINE_IDR(sdp_ps); | ||
| 68 | static DEFINE_IDR(tcp_ps); | ||
| 69 | |||
| 70 | struct cma_device { | ||
| 71 | struct list_head list; | ||
| 72 | struct ib_device *device; | ||
| 73 | __be64 node_guid; | ||
| 74 | struct completion comp; | ||
| 75 | atomic_t refcount; | ||
| 76 | struct list_head id_list; | ||
| 77 | }; | ||
| 78 | |||
| 79 | enum cma_state { | ||
| 80 | CMA_IDLE, | ||
| 81 | CMA_ADDR_QUERY, | ||
| 82 | CMA_ADDR_RESOLVED, | ||
| 83 | CMA_ROUTE_QUERY, | ||
| 84 | CMA_ROUTE_RESOLVED, | ||
| 85 | CMA_CONNECT, | ||
| 86 | CMA_DISCONNECT, | ||
| 87 | CMA_ADDR_BOUND, | ||
| 88 | CMA_LISTEN, | ||
| 89 | CMA_DEVICE_REMOVAL, | ||
| 90 | CMA_DESTROYING | ||
| 91 | }; | ||
| 92 | |||
| 93 | struct rdma_bind_list { | ||
| 94 | struct idr *ps; | ||
| 95 | struct hlist_head owners; | ||
| 96 | unsigned short port; | ||
| 97 | }; | ||
| 98 | |||
| 99 | /* | ||
| 100 | * Device removal can occur at anytime, so we need extra handling to | ||
| 101 | * serialize notifying the user of device removal with other callbacks. | ||
| 102 | * We do this by disabling removal notification while a callback is in process, | ||
| 103 | * and reporting it after the callback completes. | ||
| 104 | */ | ||
| 105 | struct rdma_id_private { | ||
| 106 | struct rdma_cm_id id; | ||
| 107 | |||
| 108 | struct rdma_bind_list *bind_list; | ||
| 109 | struct hlist_node node; | ||
| 110 | struct list_head list; | ||
| 111 | struct list_head listen_list; | ||
| 112 | struct cma_device *cma_dev; | ||
| 113 | |||
| 114 | enum cma_state state; | ||
| 115 | spinlock_t lock; | ||
| 116 | struct completion comp; | ||
| 117 | atomic_t refcount; | ||
| 118 | wait_queue_head_t wait_remove; | ||
| 119 | atomic_t dev_remove; | ||
| 120 | |||
| 121 | int backlog; | ||
| 122 | int timeout_ms; | ||
| 123 | struct ib_sa_query *query; | ||
| 124 | int query_id; | ||
| 125 | union { | ||
| 126 | struct ib_cm_id *ib; | ||
| 127 | } cm_id; | ||
| 128 | |||
| 129 | u32 seq_num; | ||
| 130 | u32 qp_num; | ||
| 131 | enum ib_qp_type qp_type; | ||
| 132 | u8 srq; | ||
| 133 | }; | ||
| 134 | |||
| 135 | struct cma_work { | ||
| 136 | struct work_struct work; | ||
| 137 | struct rdma_id_private *id; | ||
| 138 | enum cma_state old_state; | ||
| 139 | enum cma_state new_state; | ||
| 140 | struct rdma_cm_event event; | ||
| 141 | }; | ||
| 142 | |||
| 143 | union cma_ip_addr { | ||
| 144 | struct in6_addr ip6; | ||
| 145 | struct { | ||
| 146 | __u32 pad[3]; | ||
| 147 | __u32 addr; | ||
| 148 | } ip4; | ||
| 149 | }; | ||
| 150 | |||
| 151 | struct cma_hdr { | ||
| 152 | u8 cma_version; | ||
| 153 | u8 ip_version; /* IP version: 7:4 */ | ||
| 154 | __u16 port; | ||
| 155 | union cma_ip_addr src_addr; | ||
| 156 | union cma_ip_addr dst_addr; | ||
| 157 | }; | ||
| 158 | |||
| 159 | struct sdp_hh { | ||
| 160 | u8 bsdh[16]; | ||
| 161 | u8 sdp_version; /* Major version: 7:4 */ | ||
| 162 | u8 ip_version; /* IP version: 7:4 */ | ||
| 163 | u8 sdp_specific1[10]; | ||
| 164 | __u16 port; | ||
| 165 | __u16 sdp_specific2; | ||
| 166 | union cma_ip_addr src_addr; | ||
| 167 | union cma_ip_addr dst_addr; | ||
| 168 | }; | ||
| 169 | |||
| 170 | struct sdp_hah { | ||
| 171 | u8 bsdh[16]; | ||
| 172 | u8 sdp_version; | ||
| 173 | }; | ||
| 174 | |||
| 175 | #define CMA_VERSION 0x00 | ||
| 176 | #define SDP_MAJ_VERSION 0x2 | ||
| 177 | |||
| 178 | static int cma_comp(struct rdma_id_private *id_priv, enum cma_state comp) | ||
| 179 | { | ||
| 180 | unsigned long flags; | ||
| 181 | int ret; | ||
| 182 | |||
| 183 | spin_lock_irqsave(&id_priv->lock, flags); | ||
| 184 | ret = (id_priv->state == comp); | ||
| 185 | spin_unlock_irqrestore(&id_priv->lock, flags); | ||
| 186 | return ret; | ||
| 187 | } | ||
| 188 | |||
| 189 | static int cma_comp_exch(struct rdma_id_private *id_priv, | ||
| 190 | enum cma_state comp, enum cma_state exch) | ||
| 191 | { | ||
| 192 | unsigned long flags; | ||
| 193 | int ret; | ||
| 194 | |||
| 195 | spin_lock_irqsave(&id_priv->lock, flags); | ||
| 196 | if ((ret = (id_priv->state == comp))) | ||
| 197 | id_priv->state = exch; | ||
| 198 | spin_unlock_irqrestore(&id_priv->lock, flags); | ||
| 199 | return ret; | ||
| 200 | } | ||
| 201 | |||
| 202 | static enum cma_state cma_exch(struct rdma_id_private *id_priv, | ||
| 203 | enum cma_state exch) | ||
| 204 | { | ||
| 205 | unsigned long flags; | ||
| 206 | enum cma_state old; | ||
| 207 | |||
| 208 | spin_lock_irqsave(&id_priv->lock, flags); | ||
| 209 | old = id_priv->state; | ||
| 210 | id_priv->state = exch; | ||
| 211 | spin_unlock_irqrestore(&id_priv->lock, flags); | ||
| 212 | return old; | ||
| 213 | } | ||
| 214 | |||
| 215 | static inline u8 cma_get_ip_ver(struct cma_hdr *hdr) | ||
| 216 | { | ||
| 217 | return hdr->ip_version >> 4; | ||
| 218 | } | ||
| 219 | |||
| 220 | static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver) | ||
| 221 | { | ||
| 222 | hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF); | ||
| 223 | } | ||
| 224 | |||
| 225 | static inline u8 sdp_get_majv(u8 sdp_version) | ||
| 226 | { | ||
| 227 | return sdp_version >> 4; | ||
| 228 | } | ||
| 229 | |||
| 230 | static inline u8 sdp_get_ip_ver(struct sdp_hh *hh) | ||
| 231 | { | ||
| 232 | return hh->ip_version >> 4; | ||
| 233 | } | ||
| 234 | |||
| 235 | static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver) | ||
| 236 | { | ||
| 237 | hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF); | ||
| 238 | } | ||
| 239 | |||
| 240 | static void cma_attach_to_dev(struct rdma_id_private *id_priv, | ||
| 241 | struct cma_device *cma_dev) | ||
| 242 | { | ||
| 243 | atomic_inc(&cma_dev->refcount); | ||
| 244 | id_priv->cma_dev = cma_dev; | ||
| 245 | id_priv->id.device = cma_dev->device; | ||
| 246 | list_add_tail(&id_priv->list, &cma_dev->id_list); | ||
| 247 | } | ||
| 248 | |||
| 249 | static inline void cma_deref_dev(struct cma_device *cma_dev) | ||
| 250 | { | ||
| 251 | if (atomic_dec_and_test(&cma_dev->refcount)) | ||
| 252 | complete(&cma_dev->comp); | ||
| 253 | } | ||
| 254 | |||
| 255 | static void cma_detach_from_dev(struct rdma_id_private *id_priv) | ||
| 256 | { | ||
| 257 | list_del(&id_priv->list); | ||
| 258 | cma_deref_dev(id_priv->cma_dev); | ||
| 259 | id_priv->cma_dev = NULL; | ||
| 260 | } | ||
| 261 | |||
| 262 | static int cma_acquire_ib_dev(struct rdma_id_private *id_priv) | ||
| 263 | { | ||
| 264 | struct cma_device *cma_dev; | ||
| 265 | union ib_gid *gid; | ||
| 266 | int ret = -ENODEV; | ||
| 267 | |||
| 268 | gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr); | ||
| 269 | |||
| 270 | mutex_lock(&lock); | ||
| 271 | list_for_each_entry(cma_dev, &dev_list, list) { | ||
| 272 | ret = ib_find_cached_gid(cma_dev->device, gid, | ||
| 273 | &id_priv->id.port_num, NULL); | ||
| 274 | if (!ret) { | ||
| 275 | cma_attach_to_dev(id_priv, cma_dev); | ||
| 276 | break; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | mutex_unlock(&lock); | ||
| 280 | return ret; | ||
| 281 | } | ||
| 282 | |||
| 283 | static int cma_acquire_dev(struct rdma_id_private *id_priv) | ||
| 284 | { | ||
| 285 | switch (id_priv->id.route.addr.dev_addr.dev_type) { | ||
| 286 | case IB_NODE_CA: | ||
| 287 | return cma_acquire_ib_dev(id_priv); | ||
| 288 | default: | ||
| 289 | return -ENODEV; | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | static void cma_deref_id(struct rdma_id_private *id_priv) | ||
| 294 | { | ||
| 295 | if (atomic_dec_and_test(&id_priv->refcount)) | ||
| 296 | complete(&id_priv->comp); | ||
| 297 | } | ||
| 298 | |||
| 299 | static void cma_release_remove(struct rdma_id_private *id_priv) | ||
| 300 | { | ||
| 301 | if (atomic_dec_and_test(&id_priv->dev_remove)) | ||
| 302 | wake_up(&id_priv->wait_remove); | ||
| 303 | } | ||
| 304 | |||
| 305 | struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, | ||
| 306 | void *context, enum rdma_port_space ps) | ||
| 307 | { | ||
| 308 | struct rdma_id_private *id_priv; | ||
| 309 | |||
| 310 | id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL); | ||
| 311 | if (!id_priv) | ||
| 312 | return ERR_PTR(-ENOMEM); | ||
| 313 | |||
| 314 | id_priv->state = CMA_IDLE; | ||
| 315 | id_priv->id.context = context; | ||
| 316 | id_priv->id.event_handler = event_handler; | ||
| 317 | id_priv->id.ps = ps; | ||
| 318 | spin_lock_init(&id_priv->lock); | ||
| 319 | init_completion(&id_priv->comp); | ||
| 320 | atomic_set(&id_priv->refcount, 1); | ||
| 321 | init_waitqueue_head(&id_priv->wait_remove); | ||
| 322 | atomic_set(&id_priv->dev_remove, 0); | ||
| 323 | INIT_LIST_HEAD(&id_priv->listen_list); | ||
| 324 | get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); | ||
| 325 | |||
| 326 | return &id_priv->id; | ||
| 327 | } | ||
| 328 | EXPORT_SYMBOL(rdma_create_id); | ||
| 329 | |||
| 330 | static int cma_init_ib_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) | ||
| 331 | { | ||
| 332 | struct ib_qp_attr qp_attr; | ||
| 333 | struct rdma_dev_addr *dev_addr; | ||
| 334 | int ret; | ||
| 335 | |||
| 336 | dev_addr = &id_priv->id.route.addr.dev_addr; | ||
| 337 | ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, | ||
| 338 | ib_addr_get_pkey(dev_addr), | ||
| 339 | &qp_attr.pkey_index); | ||
| 340 | if (ret) | ||
| 341 | return ret; | ||
| 342 | |||
| 343 | qp_attr.qp_state = IB_QPS_INIT; | ||
| 344 | qp_attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE; | ||
| 345 | qp_attr.port_num = id_priv->id.port_num; | ||
| 346 | return ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_ACCESS_FLAGS | | ||
| 347 | IB_QP_PKEY_INDEX | IB_QP_PORT); | ||
| 348 | } | ||
| 349 | |||
| 350 | int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, | ||
| 351 | struct ib_qp_init_attr *qp_init_attr) | ||
| 352 | { | ||
| 353 | struct rdma_id_private *id_priv; | ||
| 354 | struct ib_qp *qp; | ||
| 355 | int ret; | ||
| 356 | |||
| 357 | id_priv = container_of(id, struct rdma_id_private, id); | ||
| 358 | if (id->device != pd->device) | ||
| 359 | return -EINVAL; | ||
| 360 | |||
| 361 | qp = ib_create_qp(pd, qp_init_attr); | ||
| 362 | if (IS_ERR(qp)) | ||
| 363 | return PTR_ERR(qp); | ||
| 364 | |||
| 365 | switch (id->device->node_type) { | ||
| 366 | case IB_NODE_CA: | ||
| 367 | ret = cma_init_ib_qp(id_priv, qp); | ||
| 368 | break; | ||
| 369 | default: | ||
| 370 | ret = -ENOSYS; | ||
| 371 | break; | ||
| 372 | } | ||
| 373 | |||
| 374 | if (ret) | ||
| 375 | goto err; | ||
| 376 | |||
| 377 | id->qp = qp; | ||
| 378 | id_priv->qp_num = qp->qp_num; | ||
| 379 | id_priv->qp_type = qp->qp_type; | ||
| 380 | id_priv->srq = (qp->srq != NULL); | ||
| 381 | return 0; | ||
| 382 | err: | ||
| 383 | ib_destroy_qp(qp); | ||
| 384 | return ret; | ||
| 385 | } | ||
| 386 | EXPORT_SYMBOL(rdma_create_qp); | ||
| 387 | |||
| 388 | void rdma_destroy_qp(struct rdma_cm_id *id) | ||
| 389 | { | ||
| 390 | ib_destroy_qp(id->qp); | ||
| 391 | } | ||
| 392 | EXPORT_SYMBOL(rdma_destroy_qp); | ||
| 393 | |||
| 394 | static int cma_modify_qp_rtr(struct rdma_cm_id *id) | ||
| 395 | { | ||
| 396 | struct ib_qp_attr qp_attr; | ||
| 397 | int qp_attr_mask, ret; | ||
| 398 | |||
| 399 | if (!id->qp) | ||
| 400 | return 0; | ||
| 401 | |||
| 402 | /* Need to update QP attributes from default values. */ | ||
| 403 | qp_attr.qp_state = IB_QPS_INIT; | ||
| 404 | ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask); | ||
| 405 | if (ret) | ||
| 406 | return ret; | ||
| 407 | |||
| 408 | ret = ib_modify_qp(id->qp, &qp_attr, qp_attr_mask); | ||
| 409 | if (ret) | ||
| 410 | return ret; | ||
| 411 | |||
| 412 | qp_attr.qp_state = IB_QPS_RTR; | ||
| 413 | ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask); | ||
| 414 | if (ret) | ||
| 415 | return ret; | ||
| 416 | |||
| 417 | return ib_modify_qp(id->qp, &qp_attr, qp_attr_mask); | ||
| 418 | } | ||
| 419 | |||
| 420 | static int cma_modify_qp_rts(struct rdma_cm_id *id) | ||
| 421 | { | ||
| 422 | struct ib_qp_attr qp_attr; | ||
| 423 | int qp_attr_mask, ret; | ||
| 424 | |||
| 425 | if (!id->qp) | ||
| 426 | return 0; | ||
| 427 | |||
| 428 | qp_attr.qp_state = IB_QPS_RTS; | ||
| 429 | ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask); | ||
| 430 | if (ret) | ||
| 431 | return ret; | ||
| 432 | |||
| 433 | return ib_modify_qp(id->qp, &qp_attr, qp_attr_mask); | ||
| 434 | } | ||
| 435 | |||
| 436 | static int cma_modify_qp_err(struct rdma_cm_id *id) | ||
| 437 | { | ||
| 438 | struct ib_qp_attr qp_attr; | ||
| 439 | |||
| 440 | if (!id->qp) | ||
| 441 | return 0; | ||
| 442 | |||
| 443 | qp_attr.qp_state = IB_QPS_ERR; | ||
| 444 | return ib_modify_qp(id->qp, &qp_attr, IB_QP_STATE); | ||
| 445 | } | ||
| 446 | |||
| 447 | int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, | ||
| 448 | int *qp_attr_mask) | ||
| 449 | { | ||
| 450 | struct rdma_id_private *id_priv; | ||
| 451 | int ret; | ||
| 452 | |||
| 453 | id_priv = container_of(id, struct rdma_id_private, id); | ||
| 454 | switch (id_priv->id.device->node_type) { | ||
| 455 | case IB_NODE_CA: | ||
| 456 | ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, | ||
| 457 | qp_attr_mask); | ||
| 458 | if (qp_attr->qp_state == IB_QPS_RTR) | ||
| 459 | qp_attr->rq_psn = id_priv->seq_num; | ||
| 460 | break; | ||
| 461 | default: | ||
| 462 | ret = -ENOSYS; | ||
| 463 | break; | ||
| 464 | } | ||
| 465 | |||
| 466 | return ret; | ||
| 467 | } | ||
| 468 | EXPORT_SYMBOL(rdma_init_qp_attr); | ||
| 469 | |||
| 470 | static inline int cma_zero_addr(struct sockaddr *addr) | ||
| 471 | { | ||
| 472 | struct in6_addr *ip6; | ||
| 473 | |||
| 474 | if (addr->sa_family == AF_INET) | ||
| 475 | return ZERONET(((struct sockaddr_in *) addr)->sin_addr.s_addr); | ||
| 476 | else { | ||
| 477 | ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr; | ||
| 478 | return (ip6->s6_addr32[0] | ip6->s6_addr32[1] | | ||
| 479 | ip6->s6_addr32[3] | ip6->s6_addr32[4]) == 0; | ||
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | static inline int cma_loopback_addr(struct sockaddr *addr) | ||
| 484 | { | ||
| 485 | return LOOPBACK(((struct sockaddr_in *) addr)->sin_addr.s_addr); | ||
| 486 | } | ||
| 487 | |||
| 488 | static inline int cma_any_addr(struct sockaddr *addr) | ||
| 489 | { | ||
| 490 | return cma_zero_addr(addr) || cma_loopback_addr(addr); | ||
| 491 | } | ||
| 492 | |||
| 493 | static inline int cma_any_port(struct sockaddr *addr) | ||
| 494 | { | ||
| 495 | return !((struct sockaddr_in *) addr)->sin_port; | ||
| 496 | } | ||
| 497 | |||
| 498 | static int cma_get_net_info(void *hdr, enum rdma_port_space ps, | ||
| 499 | u8 *ip_ver, __u16 *port, | ||
| 500 | union cma_ip_addr **src, union cma_ip_addr **dst) | ||
| 501 | { | ||
| 502 | switch (ps) { | ||
| 503 | case RDMA_PS_SDP: | ||
| 504 | if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) != | ||
| 505 | SDP_MAJ_VERSION) | ||
| 506 | return -EINVAL; | ||
| 507 | |||
| 508 | *ip_ver = sdp_get_ip_ver(hdr); | ||
| 509 | *port = ((struct sdp_hh *) hdr)->port; | ||
| 510 | *src = &((struct sdp_hh *) hdr)->src_addr; | ||
| 511 | *dst = &((struct sdp_hh *) hdr)->dst_addr; | ||
| 512 | break; | ||
| 513 | default: | ||
| 514 | if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION) | ||
| 515 | return -EINVAL; | ||
| 516 | |||
| 517 | *ip_ver = cma_get_ip_ver(hdr); | ||
| 518 | *port = ((struct cma_hdr *) hdr)->port; | ||
| 519 | *src = &((struct cma_hdr *) hdr)->src_addr; | ||
| 520 | *dst = &((struct cma_hdr *) hdr)->dst_addr; | ||
| 521 | break; | ||
| 522 | } | ||
| 523 | |||
| 524 | if (*ip_ver != 4 && *ip_ver != 6) | ||
| 525 | return -EINVAL; | ||
| 526 | return 0; | ||
| 527 | } | ||
| 528 | |||
| 529 | static void cma_save_net_info(struct rdma_addr *addr, | ||
| 530 | struct rdma_addr *listen_addr, | ||
| 531 | u8 ip_ver, __u16 port, | ||
| 532 | union cma_ip_addr *src, union cma_ip_addr *dst) | ||
| 533 | { | ||
| 534 | struct sockaddr_in *listen4, *ip4; | ||
| 535 | struct sockaddr_in6 *listen6, *ip6; | ||
| 536 | |||
| 537 | switch (ip_ver) { | ||
| 538 | case 4: | ||
| 539 | listen4 = (struct sockaddr_in *) &listen_addr->src_addr; | ||
| 540 | ip4 = (struct sockaddr_in *) &addr->src_addr; | ||
| 541 | ip4->sin_family = listen4->sin_family; | ||
| 542 | ip4->sin_addr.s_addr = dst->ip4.addr; | ||
| 543 | ip4->sin_port = listen4->sin_port; | ||
| 544 | |||
| 545 | ip4 = (struct sockaddr_in *) &addr->dst_addr; | ||
| 546 | ip4->sin_family = listen4->sin_family; | ||
| 547 | ip4->sin_addr.s_addr = src->ip4.addr; | ||
| 548 | ip4->sin_port = port; | ||
| 549 | break; | ||
| 550 | case 6: | ||
| 551 | listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr; | ||
| 552 | ip6 = (struct sockaddr_in6 *) &addr->src_addr; | ||
| 553 | ip6->sin6_family = listen6->sin6_family; | ||
| 554 | ip6->sin6_addr = dst->ip6; | ||
| 555 | ip6->sin6_port = listen6->sin6_port; | ||
| 556 | |||
| 557 | ip6 = (struct sockaddr_in6 *) &addr->dst_addr; | ||
| 558 | ip6->sin6_family = listen6->sin6_family; | ||
| 559 | ip6->sin6_addr = src->ip6; | ||
| 560 | ip6->sin6_port = port; | ||
| 561 | break; | ||
| 562 | default: | ||
| 563 | break; | ||
| 564 | } | ||
| 565 | } | ||
| 566 | |||
| 567 | static inline int cma_user_data_offset(enum rdma_port_space ps) | ||
| 568 | { | ||
| 569 | switch (ps) { | ||
| 570 | case RDMA_PS_SDP: | ||
| 571 | return 0; | ||
| 572 | default: | ||
| 573 | return sizeof(struct cma_hdr); | ||
| 574 | } | ||
| 575 | } | ||
| 576 | |||
| 577 | static int cma_notify_user(struct rdma_id_private *id_priv, | ||
| 578 | enum rdma_cm_event_type type, int status, | ||
| 579 | void *data, u8 data_len) | ||
| 580 | { | ||
| 581 | struct rdma_cm_event event; | ||
| 582 | |||
| 583 | event.event = type; | ||
| 584 | event.status = status; | ||
| 585 | event.private_data = data; | ||
| 586 | event.private_data_len = data_len; | ||
| 587 | |||
| 588 | return id_priv->id.event_handler(&id_priv->id, &event); | ||
| 589 | } | ||
| 590 | |||
| 591 | static void cma_cancel_route(struct rdma_id_private *id_priv) | ||
| 592 | { | ||
| 593 | switch (id_priv->id.device->node_type) { | ||
| 594 | case IB_NODE_CA: | ||
| 595 | if (id_priv->query) | ||
| 596 | ib_sa_cancel_query(id_priv->query_id, id_priv->query); | ||
| 597 | break; | ||
| 598 | default: | ||
| 599 | break; | ||
| 600 | } | ||
| 601 | } | ||
| 602 | |||
| 603 | static inline int cma_internal_listen(struct rdma_id_private *id_priv) | ||
| 604 | { | ||
| 605 | return (id_priv->state == CMA_LISTEN) && id_priv->cma_dev && | ||
| 606 | cma_any_addr(&id_priv->id.route.addr.src_addr); | ||
| 607 | } | ||
| 608 | |||
| 609 | static void cma_destroy_listen(struct rdma_id_private *id_priv) | ||
| 610 | { | ||
| 611 | cma_exch(id_priv, CMA_DESTROYING); | ||
| 612 | |||
| 613 | if (id_priv->cma_dev) { | ||
| 614 | switch (id_priv->id.device->node_type) { | ||
| 615 | case IB_NODE_CA: | ||
| 616 | if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib)) | ||
| 617 | ib_destroy_cm_id(id_priv->cm_id.ib); | ||
| 618 | break; | ||
| 619 | default: | ||
| 620 | break; | ||
| 621 | } | ||
| 622 | cma_detach_from_dev(id_priv); | ||
| 623 | } | ||
| 624 | list_del(&id_priv->listen_list); | ||
| 625 | |||
| 626 | cma_deref_id(id_priv); | ||
| 627 | wait_for_completion(&id_priv->comp); | ||
| 628 | |||
| 629 | kfree(id_priv); | ||
| 630 | } | ||
| 631 | |||
| 632 | static void cma_cancel_listens(struct rdma_id_private *id_priv) | ||
| 633 | { | ||
| 634 | struct rdma_id_private *dev_id_priv; | ||
| 635 | |||
| 636 | mutex_lock(&lock); | ||
| 637 | list_del(&id_priv->list); | ||
| 638 | |||
| 639 | while (!list_empty(&id_priv->listen_list)) { | ||
| 640 | dev_id_priv = list_entry(id_priv->listen_list.next, | ||
| 641 | struct rdma_id_private, listen_list); | ||
| 642 | cma_destroy_listen(dev_id_priv); | ||
| 643 | } | ||
| 644 | mutex_unlock(&lock); | ||
| 645 | } | ||
| 646 | |||
| 647 | static void cma_cancel_operation(struct rdma_id_private *id_priv, | ||
| 648 | enum cma_state state) | ||
| 649 | { | ||
| 650 | switch (state) { | ||
| 651 | case CMA_ADDR_QUERY: | ||
| 652 | rdma_addr_cancel(&id_priv->id.route.addr.dev_addr); | ||
| 653 | break; | ||
| 654 | case CMA_ROUTE_QUERY: | ||
| 655 | cma_cancel_route(id_priv); | ||
| 656 | break; | ||
| 657 | case CMA_LISTEN: | ||
| 658 | if (cma_any_addr(&id_priv->id.route.addr.src_addr) && | ||
| 659 | !id_priv->cma_dev) | ||
| 660 | cma_cancel_listens(id_priv); | ||
| 661 | break; | ||
| 662 | default: | ||
| 663 | break; | ||
| 664 | } | ||
| 665 | } | ||
| 666 | |||
| 667 | static void cma_release_port(struct rdma_id_private *id_priv) | ||
| 668 | { | ||
| 669 | struct rdma_bind_list *bind_list = id_priv->bind_list; | ||
| 670 | |||
| 671 | if (!bind_list) | ||
| 672 | return; | ||
| 673 | |||
| 674 | mutex_lock(&lock); | ||
| 675 | hlist_del(&id_priv->node); | ||
| 676 | if (hlist_empty(&bind_list->owners)) { | ||
| 677 | idr_remove(bind_list->ps, bind_list->port); | ||
| 678 | kfree(bind_list); | ||
| 679 | } | ||
| 680 | mutex_unlock(&lock); | ||
| 681 | } | ||
| 682 | |||
| 683 | void rdma_destroy_id(struct rdma_cm_id *id) | ||
| 684 | { | ||
| 685 | struct rdma_id_private *id_priv; | ||
| 686 | enum cma_state state; | ||
| 687 | |||
| 688 | id_priv = container_of(id, struct rdma_id_private, id); | ||
| 689 | state = cma_exch(id_priv, CMA_DESTROYING); | ||
| 690 | cma_cancel_operation(id_priv, state); | ||
| 691 | |||
| 692 | if (id_priv->cma_dev) { | ||
| 693 | switch (id->device->node_type) { | ||
| 694 | case IB_NODE_CA: | ||
| 695 | if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib)) | ||
| 696 | ib_destroy_cm_id(id_priv->cm_id.ib); | ||
| 697 | break; | ||
| 698 | default: | ||
| 699 | break; | ||
| 700 | } | ||
| 701 | mutex_lock(&lock); | ||
| 702 | cma_detach_from_dev(id_priv); | ||
| 703 | mutex_unlock(&lock); | ||
| 704 | } | ||
| 705 | |||
| 706 | cma_release_port(id_priv); | ||
| 707 | cma_deref_id(id_priv); | ||
| 708 | wait_for_completion(&id_priv->comp); | ||
| 709 | |||
| 710 | kfree(id_priv->id.route.path_rec); | ||
| 711 | kfree(id_priv); | ||
| 712 | } | ||
| 713 | EXPORT_SYMBOL(rdma_destroy_id); | ||
| 714 | |||
| 715 | static int cma_rep_recv(struct rdma_id_private *id_priv) | ||
| 716 | { | ||
| 717 | int ret; | ||
| 718 | |||
| 719 | ret = cma_modify_qp_rtr(&id_priv->id); | ||
| 720 | if (ret) | ||
| 721 | goto reject; | ||
| 722 | |||
| 723 | ret = cma_modify_qp_rts(&id_priv->id); | ||
| 724 | if (ret) | ||
| 725 | goto reject; | ||
| 726 | |||
| 727 | ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0); | ||
| 728 | if (ret) | ||
| 729 | goto reject; | ||
| 730 | |||
| 731 | return 0; | ||
| 732 | reject: | ||
| 733 | cma_modify_qp_err(&id_priv->id); | ||
| 734 | ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, | ||
| 735 | NULL, 0, NULL, 0); | ||
| 736 | return ret; | ||
| 737 | } | ||
| 738 | |||
| 739 | static int cma_verify_rep(struct rdma_id_private *id_priv, void *data) | ||
| 740 | { | ||
| 741 | if (id_priv->id.ps == RDMA_PS_SDP && | ||
| 742 | sdp_get_majv(((struct sdp_hah *) data)->sdp_version) != | ||
| 743 | SDP_MAJ_VERSION) | ||
| 744 | return -EINVAL; | ||
| 745 | |||
| 746 | return 0; | ||
| 747 | } | ||
| 748 | |||
| 749 | static int cma_rtu_recv(struct rdma_id_private *id_priv) | ||
| 750 | { | ||
| 751 | int ret; | ||
| 752 | |||
| 753 | ret = cma_modify_qp_rts(&id_priv->id); | ||
| 754 | if (ret) | ||
| 755 | goto reject; | ||
| 756 | |||
| 757 | return 0; | ||
| 758 | reject: | ||
| 759 | cma_modify_qp_err(&id_priv->id); | ||
| 760 | ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, | ||
| 761 | NULL, 0, NULL, 0); | ||
| 762 | return ret; | ||
| 763 | } | ||
| 764 | |||
| 765 | static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) | ||
| 766 | { | ||
| 767 | struct rdma_id_private *id_priv = cm_id->context; | ||
| 768 | enum rdma_cm_event_type event; | ||
| 769 | u8 private_data_len = 0; | ||
| 770 | int ret = 0, status = 0; | ||
| 771 | |||
| 772 | atomic_inc(&id_priv->dev_remove); | ||
| 773 | if (!cma_comp(id_priv, CMA_CONNECT)) | ||
| 774 | goto out; | ||
| 775 | |||
| 776 | switch (ib_event->event) { | ||
| 777 | case IB_CM_REQ_ERROR: | ||
| 778 | case IB_CM_REP_ERROR: | ||
| 779 | event = RDMA_CM_EVENT_UNREACHABLE; | ||
| 780 | status = -ETIMEDOUT; | ||
| 781 | break; | ||
| 782 | case IB_CM_REP_RECEIVED: | ||
| 783 | status = cma_verify_rep(id_priv, ib_event->private_data); | ||
| 784 | if (status) | ||
| 785 | event = RDMA_CM_EVENT_CONNECT_ERROR; | ||
| 786 | else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) { | ||
| 787 | status = cma_rep_recv(id_priv); | ||
| 788 | event = status ? RDMA_CM_EVENT_CONNECT_ERROR : | ||
| 789 | RDMA_CM_EVENT_ESTABLISHED; | ||
| 790 | } else | ||
| 791 | event = RDMA_CM_EVENT_CONNECT_RESPONSE; | ||
| 792 | private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE; | ||
| 793 | break; | ||
| 794 | case IB_CM_RTU_RECEIVED: | ||
| 795 | status = cma_rtu_recv(id_priv); | ||
| 796 | event = status ? RDMA_CM_EVENT_CONNECT_ERROR : | ||
| 797 | RDMA_CM_EVENT_ESTABLISHED; | ||
| 798 | break; | ||
| 799 | case IB_CM_DREQ_ERROR: | ||
| 800 | status = -ETIMEDOUT; /* fall through */ | ||
| 801 | case IB_CM_DREQ_RECEIVED: | ||
| 802 | case IB_CM_DREP_RECEIVED: | ||
| 803 | if (!cma_comp_exch(id_priv, CMA_CONNECT, CMA_DISCONNECT)) | ||
| 804 | goto out; | ||
| 805 | event = RDMA_CM_EVENT_DISCONNECTED; | ||
| 806 | break; | ||
| 807 | case IB_CM_TIMEWAIT_EXIT: | ||
| 808 | case IB_CM_MRA_RECEIVED: | ||
| 809 | /* ignore event */ | ||
| 810 | goto out; | ||
| 811 | case IB_CM_REJ_RECEIVED: | ||
| 812 | cma_modify_qp_err(&id_priv->id); | ||
| 813 | status = ib_event->param.rej_rcvd.reason; | ||
| 814 | event = RDMA_CM_EVENT_REJECTED; | ||
| 815 | break; | ||
| 816 | default: | ||
| 817 | printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d", | ||
| 818 | ib_event->event); | ||
| 819 | goto out; | ||
| 820 | } | ||
| 821 | |||
| 822 | ret = cma_notify_user(id_priv, event, status, ib_event->private_data, | ||
| 823 | private_data_len); | ||
| 824 | if (ret) { | ||
| 825 | /* Destroy the CM ID by returning a non-zero value. */ | ||
| 826 | id_priv->cm_id.ib = NULL; | ||
| 827 | cma_exch(id_priv, CMA_DESTROYING); | ||
| 828 | cma_release_remove(id_priv); | ||
| 829 | rdma_destroy_id(&id_priv->id); | ||
| 830 | return ret; | ||
| 831 | } | ||
| 832 | out: | ||
| 833 | cma_release_remove(id_priv); | ||
| 834 | return ret; | ||
| 835 | } | ||
| 836 | |||
| 837 | static struct rdma_id_private *cma_new_id(struct rdma_cm_id *listen_id, | ||
| 838 | struct ib_cm_event *ib_event) | ||
| 839 | { | ||
| 840 | struct rdma_id_private *id_priv; | ||
| 841 | struct rdma_cm_id *id; | ||
| 842 | struct rdma_route *rt; | ||
| 843 | union cma_ip_addr *src, *dst; | ||
| 844 | __u16 port; | ||
| 845 | u8 ip_ver; | ||
| 846 | |||
| 847 | id = rdma_create_id(listen_id->event_handler, listen_id->context, | ||
| 848 | listen_id->ps); | ||
| 849 | if (IS_ERR(id)) | ||
| 850 | return NULL; | ||
| 851 | |||
| 852 | rt = &id->route; | ||
| 853 | rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; | ||
| 854 | rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, GFP_KERNEL); | ||
| 855 | if (!rt->path_rec) | ||
| 856 | goto err; | ||
| 857 | |||
| 858 | if (cma_get_net_info(ib_event->private_data, listen_id->ps, | ||
| 859 | &ip_ver, &port, &src, &dst)) | ||
| 860 | goto err; | ||
| 861 | |||
| 862 | cma_save_net_info(&id->route.addr, &listen_id->route.addr, | ||
| 863 | ip_ver, port, src, dst); | ||
| 864 | rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path; | ||
| 865 | if (rt->num_paths == 2) | ||
| 866 | rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; | ||
| 867 | |||
| 868 | ib_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid); | ||
| 869 | ib_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); | ||
| 870 | ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey)); | ||
| 871 | rt->addr.dev_addr.dev_type = IB_NODE_CA; | ||
| 872 | |||
| 873 | id_priv = container_of(id, struct rdma_id_private, id); | ||
| 874 | id_priv->state = CMA_CONNECT; | ||
| 875 | return id_priv; | ||
| 876 | err: | ||
| 877 | rdma_destroy_id(id); | ||
| 878 | return NULL; | ||
| 879 | } | ||
| 880 | |||
| 881 | static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) | ||
| 882 | { | ||
| 883 | struct rdma_id_private *listen_id, *conn_id; | ||
| 884 | int offset, ret; | ||
| 885 | |||
| 886 | listen_id = cm_id->context; | ||
| 887 | atomic_inc(&listen_id->dev_remove); | ||
| 888 | if (!cma_comp(listen_id, CMA_LISTEN)) { | ||
| 889 | ret = -ECONNABORTED; | ||
| 890 | goto out; | ||
| 891 | } | ||
| 892 | |||
| 893 | conn_id = cma_new_id(&listen_id->id, ib_event); | ||
| 894 | if (!conn_id) { | ||
| 895 | ret = -ENOMEM; | ||
| 896 | goto out; | ||
| 897 | } | ||
| 898 | |||
| 899 | atomic_inc(&conn_id->dev_remove); | ||
| 900 | ret = cma_acquire_ib_dev(conn_id); | ||
| 901 | if (ret) { | ||
| 902 | ret = -ENODEV; | ||
| 903 | cma_release_remove(conn_id); | ||
| 904 | rdma_destroy_id(&conn_id->id); | ||
| 905 | goto out; | ||
| 906 | } | ||
| 907 | |||
| 908 | conn_id->cm_id.ib = cm_id; | ||
| 909 | cm_id->context = conn_id; | ||
| 910 | cm_id->cm_handler = cma_ib_handler; | ||
| 911 | |||
| 912 | offset = cma_user_data_offset(listen_id->id.ps); | ||
| 913 | ret = cma_notify_user(conn_id, RDMA_CM_EVENT_CONNECT_REQUEST, 0, | ||
| 914 | ib_event->private_data + offset, | ||
| 915 | IB_CM_REQ_PRIVATE_DATA_SIZE - offset); | ||
| 916 | if (ret) { | ||
| 917 | /* Destroy the CM ID by returning a non-zero value. */ | ||
| 918 | conn_id->cm_id.ib = NULL; | ||
| 919 | cma_exch(conn_id, CMA_DESTROYING); | ||
| 920 | cma_release_remove(conn_id); | ||
| 921 | rdma_destroy_id(&conn_id->id); | ||
| 922 | } | ||
| 923 | out: | ||
| 924 | cma_release_remove(listen_id); | ||
| 925 | return ret; | ||
| 926 | } | ||
| 927 | |||
| 928 | static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr) | ||
| 929 | { | ||
| 930 | return cpu_to_be64(((u64)ps << 16) + | ||
| 931 | be16_to_cpu(((struct sockaddr_in *) addr)->sin_port)); | ||
| 932 | } | ||
| 933 | |||
| 934 | static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr, | ||
| 935 | struct ib_cm_compare_data *compare) | ||
| 936 | { | ||
| 937 | struct cma_hdr *cma_data, *cma_mask; | ||
| 938 | struct sdp_hh *sdp_data, *sdp_mask; | ||
| 939 | __u32 ip4_addr; | ||
| 940 | struct in6_addr ip6_addr; | ||
| 941 | |||
| 942 | memset(compare, 0, sizeof *compare); | ||
| 943 | cma_data = (void *) compare->data; | ||
| 944 | cma_mask = (void *) compare->mask; | ||
| 945 | sdp_data = (void *) compare->data; | ||
| 946 | sdp_mask = (void *) compare->mask; | ||
| 947 | |||
| 948 | switch (addr->sa_family) { | ||
| 949 | case AF_INET: | ||
| 950 | ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; | ||
| 951 | if (ps == RDMA_PS_SDP) { | ||
| 952 | sdp_set_ip_ver(sdp_data, 4); | ||
| 953 | sdp_set_ip_ver(sdp_mask, 0xF); | ||
| 954 | sdp_data->dst_addr.ip4.addr = ip4_addr; | ||
| 955 | sdp_mask->dst_addr.ip4.addr = ~0; | ||
| 956 | } else { | ||
| 957 | cma_set_ip_ver(cma_data, 4); | ||
| 958 | cma_set_ip_ver(cma_mask, 0xF); | ||
| 959 | cma_data->dst_addr.ip4.addr = ip4_addr; | ||
| 960 | cma_mask->dst_addr.ip4.addr = ~0; | ||
| 961 | } | ||
| 962 | break; | ||
| 963 | case AF_INET6: | ||
| 964 | ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr; | ||
| 965 | if (ps == RDMA_PS_SDP) { | ||
| 966 | sdp_set_ip_ver(sdp_data, 6); | ||
| 967 | sdp_set_ip_ver(sdp_mask, 0xF); | ||
| 968 | sdp_data->dst_addr.ip6 = ip6_addr; | ||
| 969 | memset(&sdp_mask->dst_addr.ip6, 0xFF, | ||
| 970 | sizeof sdp_mask->dst_addr.ip6); | ||
| 971 | } else { | ||
| 972 | cma_set_ip_ver(cma_data, 6); | ||
| 973 | cma_set_ip_ver(cma_mask, 0xF); | ||
| 974 | cma_data->dst_addr.ip6 = ip6_addr; | ||
| 975 | memset(&cma_mask->dst_addr.ip6, 0xFF, | ||
| 976 | sizeof cma_mask->dst_addr.ip6); | ||
| 977 | } | ||
| 978 | break; | ||
| 979 | default: | ||
| 980 | break; | ||
| 981 | } | ||
| 982 | } | ||
| 983 | |||
| 984 | static int cma_ib_listen(struct rdma_id_private *id_priv) | ||
| 985 | { | ||
| 986 | struct ib_cm_compare_data compare_data; | ||
| 987 | struct sockaddr *addr; | ||
| 988 | __be64 svc_id; | ||
| 989 | int ret; | ||
| 990 | |||
| 991 | id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_req_handler, | ||
| 992 | id_priv); | ||
| 993 | if (IS_ERR(id_priv->cm_id.ib)) | ||
| 994 | return PTR_ERR(id_priv->cm_id.ib); | ||
| 995 | |||
| 996 | addr = &id_priv->id.route.addr.src_addr; | ||
| 997 | svc_id = cma_get_service_id(id_priv->id.ps, addr); | ||
| 998 | if (cma_any_addr(addr)) | ||
| 999 | ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL); | ||
| 1000 | else { | ||
| 1001 | cma_set_compare_data(id_priv->id.ps, addr, &compare_data); | ||
| 1002 | ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, &compare_data); | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | if (ret) { | ||
| 1006 | ib_destroy_cm_id(id_priv->cm_id.ib); | ||
| 1007 | id_priv->cm_id.ib = NULL; | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | return ret; | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | static int cma_listen_handler(struct rdma_cm_id *id, | ||
| 1014 | struct rdma_cm_event *event) | ||
| 1015 | { | ||
| 1016 | struct rdma_id_private *id_priv = id->context; | ||
| 1017 | |||
| 1018 | id->context = id_priv->id.context; | ||
| 1019 | id->event_handler = id_priv->id.event_handler; | ||
| 1020 | return id_priv->id.event_handler(id, event); | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | static void cma_listen_on_dev(struct rdma_id_private *id_priv, | ||
| 1024 | struct cma_device *cma_dev) | ||
| 1025 | { | ||
| 1026 | struct rdma_id_private *dev_id_priv; | ||
| 1027 | struct rdma_cm_id *id; | ||
| 1028 | int ret; | ||
| 1029 | |||
| 1030 | id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps); | ||
| 1031 | if (IS_ERR(id)) | ||
| 1032 | return; | ||
| 1033 | |||
| 1034 | dev_id_priv = container_of(id, struct rdma_id_private, id); | ||
| 1035 | |||
| 1036 | dev_id_priv->state = CMA_ADDR_BOUND; | ||
| 1037 | memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr, | ||
| 1038 | ip_addr_size(&id_priv->id.route.addr.src_addr)); | ||
| 1039 | |||
| 1040 | cma_attach_to_dev(dev_id_priv, cma_dev); | ||
| 1041 | list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); | ||
| 1042 | |||
| 1043 | ret = rdma_listen(id, id_priv->backlog); | ||
| 1044 | if (ret) | ||
| 1045 | goto err; | ||
| 1046 | |||
| 1047 | return; | ||
| 1048 | err: | ||
| 1049 | cma_destroy_listen(dev_id_priv); | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | static void cma_listen_on_all(struct rdma_id_private *id_priv) | ||
| 1053 | { | ||
| 1054 | struct cma_device *cma_dev; | ||
| 1055 | |||
| 1056 | mutex_lock(&lock); | ||
| 1057 | list_add_tail(&id_priv->list, &listen_any_list); | ||
| 1058 | list_for_each_entry(cma_dev, &dev_list, list) | ||
| 1059 | cma_listen_on_dev(id_priv, cma_dev); | ||
| 1060 | mutex_unlock(&lock); | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | static int cma_bind_any(struct rdma_cm_id *id, sa_family_t af) | ||
| 1064 | { | ||
| 1065 | struct sockaddr_in addr_in; | ||
| 1066 | |||
| 1067 | memset(&addr_in, 0, sizeof addr_in); | ||
| 1068 | addr_in.sin_family = af; | ||
| 1069 | return rdma_bind_addr(id, (struct sockaddr *) &addr_in); | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | int rdma_listen(struct rdma_cm_id *id, int backlog) | ||
| 1073 | { | ||
| 1074 | struct rdma_id_private *id_priv; | ||
| 1075 | int ret; | ||
| 1076 | |||
| 1077 | id_priv = container_of(id, struct rdma_id_private, id); | ||
| 1078 | if (id_priv->state == CMA_IDLE) { | ||
| 1079 | ret = cma_bind_any(id, AF_INET); | ||
| 1080 | if (ret) | ||
| 1081 | return ret; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN)) | ||
| 1085 | return -EINVAL; | ||
| 1086 | |||
| 1087 | id_priv->backlog = backlog; | ||
| 1088 | if (id->device) { | ||
| 1089 | switch (id->device->node_type) { | ||
| 1090 | case IB_NODE_CA: | ||
| 1091 | ret = cma_ib_listen(id_priv); | ||
| 1092 | if (ret) | ||
| 1093 | goto err; | ||
| 1094 | break; | ||
| 1095 | default: | ||
| 1096 | ret = -ENOSYS; | ||
| 1097 | goto err; | ||
| 1098 | } | ||
| 1099 | } else | ||
| 1100 | cma_listen_on_all(id_priv); | ||
| 1101 | |||
| 1102 | return 0; | ||
| 1103 | err: | ||
| 1104 | id_priv->backlog = 0; | ||
| 1105 | cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND); | ||
| 1106 | return ret; | ||
| 1107 | } | ||
| 1108 | EXPORT_SYMBOL(rdma_listen); | ||
| 1109 | |||
| 1110 | static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, | ||
| 1111 | void *context) | ||
| 1112 | { | ||
| 1113 | struct cma_work *work = context; | ||
| 1114 | struct rdma_route *route; | ||
| 1115 | |||
| 1116 | route = &work->id->id.route; | ||
| 1117 | |||
| 1118 | if (!status) { | ||
| 1119 | route->num_paths = 1; | ||
| 1120 | *route->path_rec = *path_rec; | ||
| 1121 | } else { | ||
| 1122 | work->old_state = CMA_ROUTE_QUERY; | ||
| 1123 | work->new_state = CMA_ADDR_RESOLVED; | ||
| 1124 | work->event.event = RDMA_CM_EVENT_ROUTE_ERROR; | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | queue_work(cma_wq, &work->work); | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, | ||
| 1131 | struct cma_work *work) | ||
| 1132 | { | ||
| 1133 | struct rdma_dev_addr *addr = &id_priv->id.route.addr.dev_addr; | ||
| 1134 | struct ib_sa_path_rec path_rec; | ||
| 1135 | |||
| 1136 | memset(&path_rec, 0, sizeof path_rec); | ||
| 1137 | path_rec.sgid = *ib_addr_get_sgid(addr); | ||
| 1138 | path_rec.dgid = *ib_addr_get_dgid(addr); | ||
| 1139 | path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr)); | ||
| 1140 | path_rec.numb_path = 1; | ||
| 1141 | |||
| 1142 | id_priv->query_id = ib_sa_path_rec_get(id_priv->id.device, | ||
| 1143 | id_priv->id.port_num, &path_rec, | ||
| 1144 | IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | | ||
| 1145 | IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH, | ||
| 1146 | timeout_ms, GFP_KERNEL, | ||
| 1147 | cma_query_handler, work, &id_priv->query); | ||
| 1148 | |||
| 1149 | return (id_priv->query_id < 0) ? id_priv->query_id : 0; | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | static void cma_work_handler(void *data) | ||
| 1153 | { | ||
| 1154 | struct cma_work *work = data; | ||
| 1155 | struct rdma_id_private *id_priv = work->id; | ||
| 1156 | int destroy = 0; | ||
| 1157 | |||
| 1158 | atomic_inc(&id_priv->dev_remove); | ||
| 1159 | if (!cma_comp_exch(id_priv, work->old_state, work->new_state)) | ||
| 1160 | goto out; | ||
| 1161 | |||
| 1162 | if (id_priv->id.event_handler(&id_priv->id, &work->event)) { | ||
| 1163 | cma_exch(id_priv, CMA_DESTROYING); | ||
| 1164 | destroy = 1; | ||
| 1165 | } | ||
| 1166 | out: | ||
| 1167 | cma_release_remove(id_priv); | ||
| 1168 | cma_deref_id(id_priv); | ||
| 1169 | if (destroy) | ||
| 1170 | rdma_destroy_id(&id_priv->id); | ||
| 1171 | kfree(work); | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms) | ||
| 1175 | { | ||
| 1176 | struct rdma_route *route = &id_priv->id.route; | ||
| 1177 | struct cma_work *work; | ||
| 1178 | int ret; | ||
| 1179 | |||
| 1180 | work = kzalloc(sizeof *work, GFP_KERNEL); | ||
| 1181 | if (!work) | ||
| 1182 | return -ENOMEM; | ||
| 1183 | |||
| 1184 | work->id = id_priv; | ||
| 1185 | INIT_WORK(&work->work, cma_work_handler, work); | ||
| 1186 | work->old_state = CMA_ROUTE_QUERY; | ||
| 1187 | work->new_state = CMA_ROUTE_RESOLVED; | ||
| 1188 | work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; | ||
| 1189 | |||
| 1190 | route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL); | ||
| 1191 | if (!route->path_rec) { | ||
| 1192 | ret = -ENOMEM; | ||
| 1193 | goto err1; | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | ret = cma_query_ib_route(id_priv, timeout_ms, work); | ||
| 1197 | if (ret) | ||
| 1198 | goto err2; | ||
| 1199 | |||
| 1200 | return 0; | ||
| 1201 | err2: | ||
| 1202 | kfree(route->path_rec); | ||
| 1203 | route->path_rec = NULL; | ||
| 1204 | err1: | ||
| 1205 | kfree(work); | ||
| 1206 | return ret; | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | int rdma_set_ib_paths(struct rdma_cm_id *id, | ||
| 1210 | struct ib_sa_path_rec *path_rec, int num_paths) | ||
| 1211 | { | ||
| 1212 | struct rdma_id_private *id_priv; | ||
| 1213 | int ret; | ||
| 1214 | |||
| 1215 | id_priv = container_of(id, struct rdma_id_private, id); | ||
| 1216 | if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_RESOLVED)) | ||
| 1217 | return -EINVAL; | ||
| 1218 | |||
| 1219 | id->route.path_rec = kmalloc(sizeof *path_rec * num_paths, GFP_KERNEL); | ||
| 1220 | if (!id->route.path_rec) { | ||
| 1221 | ret = -ENOMEM; | ||
| 1222 | goto err; | ||
| 1223 | } | ||
| 1224 | |||
| 1225 | memcpy(id->route.path_rec, path_rec, sizeof *path_rec * num_paths); | ||
| 1226 | return 0; | ||
| 1227 | err: | ||
| 1228 | cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_ADDR_RESOLVED); | ||
| 1229 | return ret; | ||
| 1230 | } | ||
| 1231 | EXPORT_SYMBOL(rdma_set_ib_paths); | ||
| 1232 | |||
| 1233 | int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) | ||
| 1234 | { | ||
| 1235 | struct rdma_id_private *id_priv; | ||
| 1236 | int ret; | ||
| 1237 | |||
| 1238 | id_priv = container_of(id, struct rdma_id_private, id); | ||
| 1239 | if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_QUERY)) | ||
| 1240 | return -EINVAL; | ||
| 1241 | |||
| 1242 | atomic_inc(&id_priv->refcount); | ||
| 1243 | switch (id->device->node_type) { | ||
| 1244 | case IB_NODE_CA: | ||
| 1245 | ret = cma_resolve_ib_route(id_priv, timeout_ms); | ||
| 1246 | break; | ||
| 1247 | default: | ||
| 1248 | ret = -ENOSYS; | ||
| 1249 | break; | ||
| 1250 | } | ||
| 1251 | if (ret) | ||
| 1252 | goto err; | ||
| 1253 | |||
| 1254 | return 0; | ||
| 1255 | err: | ||
| 1256 | cma_comp_exch(id_priv, CMA_ROUTE_QUERY, CMA_ADDR_RESOLVED); | ||
| 1257 | cma_deref_id(id_priv); | ||
| 1258 | return ret; | ||
| 1259 | } | ||
| 1260 | EXPORT_SYMBOL(rdma_resolve_route); | ||
| 1261 | |||
| 1262 | static int cma_bind_loopback(struct rdma_id_private *id_priv) | ||
| 1263 | { | ||
| 1264 | struct cma_device *cma_dev; | ||
| 1265 | struct ib_port_attr port_attr; | ||
| 1266 | union ib_gid *gid; | ||
| 1267 | u16 pkey; | ||
| 1268 | int ret; | ||
| 1269 | u8 p; | ||
| 1270 | |||
| 1271 | mutex_lock(&lock); | ||
| 1272 | list_for_each_entry(cma_dev, &dev_list, list) | ||
| 1273 | for (p = 1; p <= cma_dev->device->phys_port_cnt; ++p) | ||
| 1274 | if (!ib_query_port (cma_dev->device, p, &port_attr) && | ||
| 1275 | port_attr.state == IB_PORT_ACTIVE) | ||
| 1276 | goto port_found; | ||
| 1277 | |||
| 1278 | if (!list_empty(&dev_list)) { | ||
| 1279 | p = 1; | ||
| 1280 | cma_dev = list_entry(dev_list.next, struct cma_device, list); | ||
| 1281 | } else { | ||
| 1282 | ret = -ENODEV; | ||
| 1283 | goto out; | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | port_found: | ||
| 1287 | gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr); | ||
| 1288 | ret = ib_get_cached_gid(cma_dev->device, p, 0, gid); | ||
| 1289 | if (ret) | ||
| 1290 | goto out; | ||
| 1291 | |||
| 1292 | ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey); | ||
| 1293 | if (ret) | ||
| 1294 | goto out; | ||
| 1295 | |||
| 1296 | ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey); | ||
| 1297 | id_priv->id.port_num = p; | ||
| 1298 | cma_attach_to_dev(id_priv, cma_dev); | ||
| 1299 | out: | ||
| 1300 | mutex_unlock(&lock); | ||
| 1301 | return ret; | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | static void addr_handler(int status, struct sockaddr *src_addr, | ||
| 1305 | struct rdma_dev_addr *dev_addr, void *context) | ||
| 1306 | { | ||
| 1307 | struct rdma_id_private *id_priv = context; | ||
| 1308 | enum rdma_cm_event_type event; | ||
| 1309 | |||
| 1310 | atomic_inc(&id_priv->dev_remove); | ||
| 1311 | if (!id_priv->cma_dev && !status) | ||
| 1312 | status = cma_acquire_dev(id_priv); | ||
| 1313 | |||
| 1314 | if (status) { | ||
| 1315 | if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND)) | ||
| 1316 | goto out; | ||
| 1317 | event = RDMA_CM_EVENT_ADDR_ERROR; | ||
| 1318 | } else { | ||
| 1319 | if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED)) | ||
| 1320 | goto out; | ||
| 1321 | memcpy(&id_priv->id.route.addr.src_addr, src_addr, | ||
| 1322 | ip_addr_size(src_addr)); | ||
| 1323 | event = RDMA_CM_EVENT_ADDR_RESOLVED; | ||
| 1324 | } | ||
| 1325 | |||
| 1326 | if (cma_notify_user(id_priv, event, status, NULL, 0)) { | ||
| 1327 | cma_exch(id_priv, CMA_DESTROYING); | ||
| 1328 | cma_release_remove(id_priv); | ||
| 1329 | cma_deref_id(id_priv); | ||
| 1330 | rdma_destroy_id(&id_priv->id); | ||
| 1331 | return; | ||
| 1332 | } | ||
| 1333 | out: | ||
| 1334 | cma_release_remove(id_priv); | ||
| 1335 | cma_deref_id(id_priv); | ||
| 1336 | } | ||
| 1337 | |||
| 1338 | static int cma_resolve_loopback(struct rdma_id_private *id_priv) | ||
| 1339 | { | ||
| 1340 | struct cma_work *work; | ||
| 1341 | struct sockaddr_in *src_in, *dst_in; | ||
| 1342 | int ret; | ||
| 1343 | |||
| 1344 | work = kzalloc(sizeof *work, GFP_KERNEL); | ||
| 1345 | if (!work) | ||
| 1346 | return -ENOMEM; | ||
| 1347 | |||
| 1348 | if (!id_priv->cma_dev) { | ||
| 1349 | ret = cma_bind_loopback(id_priv); | ||
| 1350 | if (ret) | ||
| 1351 | goto err; | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr, | ||
| 1355 | ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr)); | ||
| 1356 | |||
| 1357 | if (cma_zero_addr(&id_priv->id.route.addr.src_addr)) { | ||
| 1358 | src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr; | ||
| 1359 | dst_in = (struct sockaddr_in *)&id_priv->id.route.addr.dst_addr; | ||
| 1360 | src_in->sin_family = dst_in->sin_family; | ||
| 1361 | src_in->sin_addr.s_addr = dst_in->sin_addr.s_addr; | ||
| 1362 | } | ||
| 1363 | |||
| 1364 | work->id = id_priv; | ||
| 1365 | INIT_WORK(&work->work, cma_work_handler, work); | ||
| 1366 | work->old_state = CMA_ADDR_QUERY; | ||
| 1367 | work->new_state = CMA_ADDR_RESOLVED; | ||
| 1368 | work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; | ||
| 1369 | queue_work(cma_wq, &work->work); | ||
| 1370 | return 0; | ||
| 1371 | err: | ||
| 1372 | kfree(work); | ||
| 1373 | return ret; | ||
| 1374 | } | ||
| 1375 | |||
| 1376 | static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, | ||
| 1377 | struct sockaddr *dst_addr) | ||
| 1378 | { | ||
| 1379 | if (src_addr && src_addr->sa_family) | ||
| 1380 | return rdma_bind_addr(id, src_addr); | ||
| 1381 | else | ||
| 1382 | return cma_bind_any(id, dst_addr->sa_family); | ||
| 1383 | } | ||
| 1384 | |||
| 1385 | int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, | ||
| 1386 | struct sockaddr *dst_addr, int timeout_ms) | ||
| 1387 | { | ||
| 1388 | struct rdma_id_private *id_priv; | ||
| 1389 | int ret; | ||
| 1390 | |||
| 1391 | id_priv = container_of(id, struct rdma_id_private, id); | ||
| 1392 | if (id_priv->state == CMA_IDLE) { | ||
| 1393 | ret = cma_bind_addr(id, src_addr, dst_addr); | ||
| 1394 | if (ret) | ||
| 1395 | return ret; | ||
| 1396 | } | ||
| 1397 | |||
| 1398 | if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_ADDR_QUERY)) | ||
| 1399 | return -EINVAL; | ||
| 1400 | |||
| 1401 | atomic_inc(&id_priv->refcount); | ||
| 1402 | memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr)); | ||
| 1403 | if (cma_any_addr(dst_addr)) | ||
| 1404 | ret = cma_resolve_loopback(id_priv); | ||
| 1405 | else | ||
| 1406 | ret = rdma_resolve_ip(&id->route.addr.src_addr, dst_addr, | ||
| 1407 | &id->route.addr.dev_addr, | ||
| 1408 | timeout_ms, addr_handler, id_priv); | ||
| 1409 | if (ret) | ||
| 1410 | goto err; | ||
| 1411 | |||
| 1412 | return 0; | ||
| 1413 | err: | ||
| 1414 | cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND); | ||
| 1415 | cma_deref_id(id_priv); | ||
| 1416 | return ret; | ||
| 1417 | } | ||
| 1418 | EXPORT_SYMBOL(rdma_resolve_addr); | ||
| 1419 | |||
| 1420 | static void cma_bind_port(struct rdma_bind_list *bind_list, | ||
| 1421 | struct rdma_id_private *id_priv) | ||
| 1422 | { | ||
| 1423 | struct sockaddr_in *sin; | ||
| 1424 | |||
| 1425 | sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; | ||
| 1426 | sin->sin_port = htons(bind_list->port); | ||
| 1427 | id_priv->bind_list = bind_list; | ||
| 1428 | hlist_add_head(&id_priv->node, &bind_list->owners); | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, | ||
| 1432 | unsigned short snum) | ||
| 1433 | { | ||
| 1434 | struct rdma_bind_list *bind_list; | ||
| 1435 | int port, start, ret; | ||
| 1436 | |||
| 1437 | bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); | ||
| 1438 | if (!bind_list) | ||
| 1439 | return -ENOMEM; | ||
| 1440 | |||
| 1441 | start = snum ? snum : sysctl_local_port_range[0]; | ||
| 1442 | |||
| 1443 | do { | ||
| 1444 | ret = idr_get_new_above(ps, bind_list, start, &port); | ||
| 1445 | } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); | ||
| 1446 | |||
| 1447 | if (ret) | ||
| 1448 | goto err; | ||
| 1449 | |||
| 1450 | if ((snum && port != snum) || | ||
| 1451 | (!snum && port > sysctl_local_port_range[1])) { | ||
| 1452 | idr_remove(ps, port); | ||
| 1453 | ret = -EADDRNOTAVAIL; | ||
| 1454 | goto err; | ||
| 1455 | } | ||
| 1456 | |||
| 1457 | bind_list->ps = ps; | ||
| 1458 | bind_list->port = (unsigned short) port; | ||
| 1459 | cma_bind_port(bind_list, id_priv); | ||
| 1460 | return 0; | ||
| 1461 | err: | ||
| 1462 | kfree(bind_list); | ||
| 1463 | return ret; | ||
| 1464 | } | ||
| 1465 | |||
| 1466 | static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) | ||
| 1467 | { | ||
| 1468 | struct rdma_id_private *cur_id; | ||
| 1469 | struct sockaddr_in *sin, *cur_sin; | ||
| 1470 | struct rdma_bind_list *bind_list; | ||
| 1471 | struct hlist_node *node; | ||
| 1472 | unsigned short snum; | ||
| 1473 | |||
| 1474 | sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; | ||
| 1475 | snum = ntohs(sin->sin_port); | ||
| 1476 | if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) | ||
| 1477 | return -EACCES; | ||
| 1478 | |||
| 1479 | bind_list = idr_find(ps, snum); | ||
| 1480 | if (!bind_list) | ||
| 1481 | return cma_alloc_port(ps, id_priv, snum); | ||
| 1482 | |||
| 1483 | /* | ||
| 1484 | * We don't support binding to any address if anyone is bound to | ||
| 1485 | * a specific address on the same port. | ||
| 1486 | */ | ||
| 1487 | if (cma_any_addr(&id_priv->id.route.addr.src_addr)) | ||
| 1488 | return -EADDRNOTAVAIL; | ||
| 1489 | |||
| 1490 | hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { | ||
| 1491 | if (cma_any_addr(&cur_id->id.route.addr.src_addr)) | ||
| 1492 | return -EADDRNOTAVAIL; | ||
| 1493 | |||
| 1494 | cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr; | ||
| 1495 | if (sin->sin_addr.s_addr == cur_sin->sin_addr.s_addr) | ||
| 1496 | return -EADDRINUSE; | ||
| 1497 | } | ||
| 1498 | |||
| 1499 | cma_bind_port(bind_list, id_priv); | ||
| 1500 | return 0; | ||
| 1501 | } | ||
| 1502 | |||
| 1503 | static int cma_get_port(struct rdma_id_private *id_priv) | ||
| 1504 | { | ||
| 1505 | struct idr *ps; | ||
| 1506 | int ret; | ||
| 1507 | |||
| 1508 | switch (id_priv->id.ps) { | ||
| 1509 | case RDMA_PS_SDP: | ||
| 1510 | ps = &sdp_ps; | ||
| 1511 | break; | ||
| 1512 | case RDMA_PS_TCP: | ||
| 1513 | ps = &tcp_ps; | ||
| 1514 | break; | ||
| 1515 | default: | ||
| 1516 | return -EPROTONOSUPPORT; | ||
| 1517 | } | ||
| 1518 | |||
| 1519 | mutex_lock(&lock); | ||
| 1520 | if (cma_any_port(&id_priv->id.route.addr.src_addr)) | ||
| 1521 | ret = cma_alloc_port(ps, id_priv, 0); | ||
| 1522 | else | ||
| 1523 | ret = cma_use_port(ps, id_priv); | ||
| 1524 | mutex_unlock(&lock); | ||
| 1525 | |||
| 1526 | return ret; | ||
| 1527 | } | ||
| 1528 | |||
| 1529 | int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) | ||
| 1530 | { | ||
| 1531 | struct rdma_id_private *id_priv; | ||
| 1532 | int ret; | ||
| 1533 | |||
| 1534 | if (addr->sa_family != AF_INET) | ||
| 1535 | return -EAFNOSUPPORT; | ||
| 1536 | |||
| 1537 | id_priv = container_of(id, struct rdma_id_private, id); | ||
| 1538 | if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND)) | ||
| 1539 | return -EINVAL; | ||
| 1540 | |||
| 1541 | if (!cma_any_addr(addr)) { | ||
| 1542 | ret = rdma_translate_ip(addr, &id->route.addr.dev_addr); | ||
| 1543 | if (!ret) | ||
| 1544 | ret = cma_acquire_dev(id_priv); | ||
| 1545 | if (ret) | ||
| 1546 | goto err; | ||
| 1547 | } | ||
| 1548 | |||
| 1549 | memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr)); | ||
| 1550 | ret = cma_get_port(id_priv); | ||
| 1551 | if (ret) | ||
| 1552 | goto err; | ||
| 1553 | |||
| 1554 | return 0; | ||
| 1555 | err: | ||
| 1556 | cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE); | ||
| 1557 | return ret; | ||
| 1558 | } | ||
| 1559 | EXPORT_SYMBOL(rdma_bind_addr); | ||
| 1560 | |||
| 1561 | static int cma_format_hdr(void *hdr, enum rdma_port_space ps, | ||
| 1562 | struct rdma_route *route) | ||
| 1563 | { | ||
| 1564 | struct sockaddr_in *src4, *dst4; | ||
| 1565 | struct cma_hdr *cma_hdr; | ||
| 1566 | struct sdp_hh *sdp_hdr; | ||
| 1567 | |||
| 1568 | src4 = (struct sockaddr_in *) &route->addr.src_addr; | ||
| 1569 | dst4 = (struct sockaddr_in *) &route->addr.dst_addr; | ||
| 1570 | |||
| 1571 | switch (ps) { | ||
| 1572 | case RDMA_PS_SDP: | ||
| 1573 | sdp_hdr = hdr; | ||
| 1574 | if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) | ||
| 1575 | return -EINVAL; | ||
| 1576 | sdp_set_ip_ver(sdp_hdr, 4); | ||
| 1577 | sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; | ||
| 1578 | sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; | ||
| 1579 | sdp_hdr->port = src4->sin_port; | ||
| 1580 | break; | ||
| 1581 | default: | ||
| 1582 | cma_hdr = hdr; | ||
| 1583 | cma_hdr->cma_version = CMA_VERSION; | ||
| 1584 | cma_set_ip_ver(cma_hdr, 4); | ||
| 1585 | cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; | ||
| 1586 | cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; | ||
| 1587 | cma_hdr->port = src4->sin_port; | ||
| 1588 | break; | ||
| 1589 | } | ||
| 1590 | return 0; | ||
| 1591 | } | ||
| 1592 | |||
| 1593 | static int cma_connect_ib(struct rdma_id_private *id_priv, | ||
| 1594 | struct rdma_conn_param *conn_param) | ||
| 1595 | { | ||
| 1596 | struct ib_cm_req_param req; | ||
| 1597 | struct rdma_route *route; | ||
| 1598 | void *private_data; | ||
| 1599 | int offset, ret; | ||
| 1600 | |||
| 1601 | memset(&req, 0, sizeof req); | ||
| 1602 | offset = cma_user_data_offset(id_priv->id.ps); | ||
| 1603 | req.private_data_len = offset + conn_param->private_data_len; | ||
| 1604 | private_data = kzalloc(req.private_data_len, GFP_ATOMIC); | ||
| 1605 | if (!private_data) | ||
| 1606 | return -ENOMEM; | ||
| 1607 | |||
| 1608 | if (conn_param->private_data && conn_param->private_data_len) | ||
| 1609 | memcpy(private_data + offset, conn_param->private_data, | ||
| 1610 | conn_param->private_data_len); | ||
| 1611 | |||
| 1612 | id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_ib_handler, | ||
| 1613 | id_priv); | ||
| 1614 | if (IS_ERR(id_priv->cm_id.ib)) { | ||
| 1615 | ret = PTR_ERR(id_priv->cm_id.ib); | ||
| 1616 | goto out; | ||
| 1617 | } | ||
| 1618 | |||
| 1619 | route = &id_priv->id.route; | ||
| 1620 | ret = cma_format_hdr(private_data, id_priv->id.ps, route); | ||
| 1621 | if (ret) | ||
| 1622 | goto out; | ||
| 1623 | req.private_data = private_data; | ||
| 1624 | |||
| 1625 | req.primary_path = &route->path_rec[0]; | ||
| 1626 | if (route->num_paths == 2) | ||
| 1627 | req.alternate_path = &route->path_rec[1]; | ||
| 1628 | |||
| 1629 | req.service_id = cma_get_service_id(id_priv->id.ps, | ||
| 1630 | &route->addr.dst_addr); | ||
| 1631 | req.qp_num = id_priv->qp_num; | ||
| 1632 | req.qp_type = id_priv->qp_type; | ||
| 1633 | req.starting_psn = id_priv->seq_num; | ||
| 1634 | req.responder_resources = conn_param->responder_resources; | ||
| 1635 | req.initiator_depth = conn_param->initiator_depth; | ||
| 1636 | req.flow_control = conn_param->flow_control; | ||
| 1637 | req.retry_count = conn_param->retry_count; | ||
| 1638 | req.rnr_retry_count = conn_param->rnr_retry_count; | ||
| 1639 | req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; | ||
| 1640 | req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; | ||
| 1641 | req.max_cm_retries = CMA_MAX_CM_RETRIES; | ||
| 1642 | req.srq = id_priv->srq ? 1 : 0; | ||
| 1643 | |||
| 1644 | ret = ib_send_cm_req(id_priv->cm_id.ib, &req); | ||
| 1645 | out: | ||
| 1646 | kfree(private_data); | ||
| 1647 | return ret; | ||
| 1648 | } | ||
| 1649 | |||
| 1650 | int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) | ||
| 1651 | { | ||
| 1652 | struct rdma_id_private *id_priv; | ||
| 1653 | int ret; | ||
| 1654 | |||
| 1655 | id_priv = container_of(id, struct rdma_id_private, id); | ||
| 1656 | if (!cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_CONNECT)) | ||
| 1657 | return -EINVAL; | ||
| 1658 | |||
| 1659 | if (!id->qp) { | ||
| 1660 | id_priv->qp_num = conn_param->qp_num; | ||
| 1661 | id_priv->qp_type = conn_param->qp_type; | ||
| 1662 | id_priv->srq = conn_param->srq; | ||
| 1663 | } | ||
| 1664 | |||
| 1665 | switch (id->device->node_type) { | ||
| 1666 | case IB_NODE_CA: | ||
| 1667 | ret = cma_connect_ib(id_priv, conn_param); | ||
| 1668 | break; | ||
| 1669 | default: | ||
| 1670 | ret = -ENOSYS; | ||
| 1671 | break; | ||
| 1672 | } | ||
| 1673 | if (ret) | ||
| 1674 | goto err; | ||
| 1675 | |||
| 1676 | return 0; | ||
| 1677 | err: | ||
| 1678 | cma_comp_exch(id_priv, CMA_CONNECT, CMA_ROUTE_RESOLVED); | ||
| 1679 | return ret; | ||
| 1680 | } | ||
| 1681 | EXPORT_SYMBOL(rdma_connect); | ||
| 1682 | |||
| 1683 | static int cma_accept_ib(struct rdma_id_private *id_priv, | ||
| 1684 | struct rdma_conn_param *conn_param) | ||
| 1685 | { | ||
| 1686 | struct ib_cm_rep_param rep; | ||
| 1687 | int ret; | ||
| 1688 | |||
| 1689 | ret = cma_modify_qp_rtr(&id_priv->id); | ||
| 1690 | if (ret) | ||
| 1691 | return ret; | ||
| 1692 | |||
| 1693 | memset(&rep, 0, sizeof rep); | ||
| 1694 | rep.qp_num = id_priv->qp_num; | ||
| 1695 | rep.starting_psn = id_priv->seq_num; | ||
| 1696 | rep.private_data = conn_param->private_data; | ||
| 1697 | rep.private_data_len = conn_param->private_data_len; | ||
| 1698 | rep.responder_resources = conn_param->responder_resources; | ||
| 1699 | rep.initiator_depth = conn_param->initiator_depth; | ||
| 1700 | rep.target_ack_delay = CMA_CM_RESPONSE_TIMEOUT; | ||
| 1701 | rep.failover_accepted = 0; | ||
| 1702 | rep.flow_control = conn_param->flow_control; | ||
| 1703 | rep.rnr_retry_count = conn_param->rnr_retry_count; | ||
| 1704 | rep.srq = id_priv->srq ? 1 : 0; | ||
| 1705 | |||
| 1706 | return ib_send_cm_rep(id_priv->cm_id.ib, &rep); | ||
| 1707 | } | ||
| 1708 | |||
| 1709 | int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) | ||
| 1710 | { | ||
| 1711 | struct rdma_id_private *id_priv; | ||
| 1712 | int ret; | ||
| 1713 | |||
| 1714 | id_priv = container_of(id, struct rdma_id_private, id); | ||
| 1715 | if (!cma_comp(id_priv, CMA_CONNECT)) | ||
| 1716 | return -EINVAL; | ||
| 1717 | |||
| 1718 | if (!id->qp && conn_param) { | ||
| 1719 | id_priv->qp_num = conn_param->qp_num; | ||
| 1720 | id_priv->qp_type = conn_param->qp_type; | ||
| 1721 | id_priv->srq = conn_param->srq; | ||
| 1722 | } | ||
| 1723 | |||
| 1724 | switch (id->device->node_type) { | ||
| 1725 | case IB_NODE_CA: | ||
| 1726 | if (conn_param) | ||
| 1727 | ret = cma_accept_ib(id_priv, conn_param); | ||
| 1728 | else | ||
| 1729 | ret = cma_rep_recv(id_priv); | ||
| 1730 | break; | ||
| 1731 | default: | ||
| 1732 | ret = -ENOSYS; | ||
| 1733 | break; | ||
| 1734 | } | ||
| 1735 | |||
| 1736 | if (ret) | ||
| 1737 | goto reject; | ||
| 1738 | |||
| 1739 | return 0; | ||
| 1740 | reject: | ||
| 1741 | cma_modify_qp_err(id); | ||
| 1742 | rdma_reject(id, NULL, 0); | ||
| 1743 | return ret; | ||
| 1744 | } | ||
| 1745 | EXPORT_SYMBOL(rdma_accept); | ||
| 1746 | |||
| 1747 | int rdma_reject(struct rdma_cm_id *id, const void *private_data, | ||
| 1748 | u8 private_data_len) | ||
| 1749 | { | ||
| 1750 | struct rdma_id_private *id_priv; | ||
| 1751 | int ret; | ||
| 1752 | |||
| 1753 | id_priv = container_of(id, struct rdma_id_private, id); | ||
| 1754 | if (!cma_comp(id_priv, CMA_CONNECT)) | ||
| 1755 | return -EINVAL; | ||
| 1756 | |||
| 1757 | switch (id->device->node_type) { | ||
| 1758 | case IB_NODE_CA: | ||
| 1759 | ret = ib_send_cm_rej(id_priv->cm_id.ib, | ||
| 1760 | IB_CM_REJ_CONSUMER_DEFINED, NULL, 0, | ||
| 1761 | private_data, private_data_len); | ||
| 1762 | break; | ||
| 1763 | default: | ||
| 1764 | ret = -ENOSYS; | ||
| 1765 | break; | ||
| 1766 | } | ||
| 1767 | return ret; | ||
| 1768 | } | ||
| 1769 | EXPORT_SYMBOL(rdma_reject); | ||
| 1770 | |||
| 1771 | int rdma_disconnect(struct rdma_cm_id *id) | ||
| 1772 | { | ||
| 1773 | struct rdma_id_private *id_priv; | ||
| 1774 | int ret; | ||
| 1775 | |||
| 1776 | id_priv = container_of(id, struct rdma_id_private, id); | ||
| 1777 | if (!cma_comp(id_priv, CMA_CONNECT) && | ||
| 1778 | !cma_comp(id_priv, CMA_DISCONNECT)) | ||
| 1779 | return -EINVAL; | ||
| 1780 | |||
| 1781 | ret = cma_modify_qp_err(id); | ||
| 1782 | if (ret) | ||
| 1783 | goto out; | ||
| 1784 | |||
| 1785 | switch (id->device->node_type) { | ||
| 1786 | case IB_NODE_CA: | ||
| 1787 | /* Initiate or respond to a disconnect. */ | ||
| 1788 | if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0)) | ||
| 1789 | ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0); | ||
| 1790 | break; | ||
| 1791 | default: | ||
| 1792 | break; | ||
| 1793 | } | ||
| 1794 | out: | ||
| 1795 | return ret; | ||
| 1796 | } | ||
| 1797 | EXPORT_SYMBOL(rdma_disconnect); | ||
| 1798 | |||
| 1799 | static void cma_add_one(struct ib_device *device) | ||
| 1800 | { | ||
| 1801 | struct cma_device *cma_dev; | ||
| 1802 | struct rdma_id_private *id_priv; | ||
| 1803 | |||
| 1804 | cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL); | ||
| 1805 | if (!cma_dev) | ||
| 1806 | return; | ||
| 1807 | |||
| 1808 | cma_dev->device = device; | ||
| 1809 | cma_dev->node_guid = device->node_guid; | ||
| 1810 | if (!cma_dev->node_guid) | ||
| 1811 | goto err; | ||
| 1812 | |||
| 1813 | init_completion(&cma_dev->comp); | ||
| 1814 | atomic_set(&cma_dev->refcount, 1); | ||
| 1815 | INIT_LIST_HEAD(&cma_dev->id_list); | ||
| 1816 | ib_set_client_data(device, &cma_client, cma_dev); | ||
| 1817 | |||
| 1818 | mutex_lock(&lock); | ||
| 1819 | list_add_tail(&cma_dev->list, &dev_list); | ||
| 1820 | list_for_each_entry(id_priv, &listen_any_list, list) | ||
| 1821 | cma_listen_on_dev(id_priv, cma_dev); | ||
| 1822 | mutex_unlock(&lock); | ||
| 1823 | return; | ||
| 1824 | err: | ||
| 1825 | kfree(cma_dev); | ||
| 1826 | } | ||
| 1827 | |||
| 1828 | static int cma_remove_id_dev(struct rdma_id_private *id_priv) | ||
| 1829 | { | ||
| 1830 | enum cma_state state; | ||
| 1831 | |||
| 1832 | /* Record that we want to remove the device */ | ||
| 1833 | state = cma_exch(id_priv, CMA_DEVICE_REMOVAL); | ||
| 1834 | if (state == CMA_DESTROYING) | ||
| 1835 | return 0; | ||
| 1836 | |||
| 1837 | cma_cancel_operation(id_priv, state); | ||
| 1838 | wait_event(id_priv->wait_remove, !atomic_read(&id_priv->dev_remove)); | ||
| 1839 | |||
| 1840 | /* Check for destruction from another callback. */ | ||
| 1841 | if (!cma_comp(id_priv, CMA_DEVICE_REMOVAL)) | ||
| 1842 | return 0; | ||
| 1843 | |||
| 1844 | return cma_notify_user(id_priv, RDMA_CM_EVENT_DEVICE_REMOVAL, | ||
| 1845 | 0, NULL, 0); | ||
| 1846 | } | ||
| 1847 | |||
| 1848 | static void cma_process_remove(struct cma_device *cma_dev) | ||
| 1849 | { | ||
| 1850 | struct list_head remove_list; | ||
| 1851 | struct rdma_id_private *id_priv; | ||
| 1852 | int ret; | ||
| 1853 | |||
| 1854 | INIT_LIST_HEAD(&remove_list); | ||
| 1855 | |||
| 1856 | mutex_lock(&lock); | ||
| 1857 | while (!list_empty(&cma_dev->id_list)) { | ||
| 1858 | id_priv = list_entry(cma_dev->id_list.next, | ||
| 1859 | struct rdma_id_private, list); | ||
| 1860 | |||
| 1861 | if (cma_internal_listen(id_priv)) { | ||
| 1862 | cma_destroy_listen(id_priv); | ||
| 1863 | continue; | ||
| 1864 | } | ||
| 1865 | |||
| 1866 | list_del(&id_priv->list); | ||
| 1867 | list_add_tail(&id_priv->list, &remove_list); | ||
| 1868 | atomic_inc(&id_priv->refcount); | ||
| 1869 | mutex_unlock(&lock); | ||
| 1870 | |||
| 1871 | ret = cma_remove_id_dev(id_priv); | ||
| 1872 | cma_deref_id(id_priv); | ||
| 1873 | if (ret) | ||
| 1874 | rdma_destroy_id(&id_priv->id); | ||
| 1875 | |||
| 1876 | mutex_lock(&lock); | ||
| 1877 | } | ||
| 1878 | mutex_unlock(&lock); | ||
| 1879 | |||
| 1880 | cma_deref_dev(cma_dev); | ||
| 1881 | wait_for_completion(&cma_dev->comp); | ||
| 1882 | } | ||
| 1883 | |||
| 1884 | static void cma_remove_one(struct ib_device *device) | ||
| 1885 | { | ||
| 1886 | struct cma_device *cma_dev; | ||
| 1887 | |||
| 1888 | cma_dev = ib_get_client_data(device, &cma_client); | ||
| 1889 | if (!cma_dev) | ||
| 1890 | return; | ||
| 1891 | |||
| 1892 | mutex_lock(&lock); | ||
| 1893 | list_del(&cma_dev->list); | ||
| 1894 | mutex_unlock(&lock); | ||
| 1895 | |||
| 1896 | cma_process_remove(cma_dev); | ||
| 1897 | kfree(cma_dev); | ||
| 1898 | } | ||
| 1899 | |||
| 1900 | static int cma_init(void) | ||
| 1901 | { | ||
| 1902 | int ret; | ||
| 1903 | |||
| 1904 | cma_wq = create_singlethread_workqueue("rdma_cm_wq"); | ||
| 1905 | if (!cma_wq) | ||
| 1906 | return -ENOMEM; | ||
| 1907 | |||
| 1908 | ret = ib_register_client(&cma_client); | ||
| 1909 | if (ret) | ||
| 1910 | goto err; | ||
| 1911 | return 0; | ||
| 1912 | |||
| 1913 | err: | ||
| 1914 | destroy_workqueue(cma_wq); | ||
| 1915 | return ret; | ||
| 1916 | } | ||
| 1917 | |||
| 1918 | static void cma_cleanup(void) | ||
| 1919 | { | ||
| 1920 | ib_unregister_client(&cma_client); | ||
| 1921 | destroy_workqueue(cma_wq); | ||
| 1922 | idr_destroy(&sdp_ps); | ||
| 1923 | idr_destroy(&tcp_ps); | ||
| 1924 | } | ||
| 1925 | |||
| 1926 | module_init(cma_init); | ||
| 1927 | module_exit(cma_cleanup); | ||
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c index 838bf54458d2..615fe9cc6c56 100644 --- a/drivers/infiniband/core/fmr_pool.c +++ b/drivers/infiniband/core/fmr_pool.c | |||
| @@ -54,7 +54,7 @@ enum { | |||
| 54 | /* | 54 | /* |
| 55 | * If an FMR is not in use, then the list member will point to either | 55 | * If an FMR is not in use, then the list member will point to either |
| 56 | * its pool's free_list (if the FMR can be mapped again; that is, | 56 | * its pool's free_list (if the FMR can be mapped again; that is, |
| 57 | * remap_count < IB_FMR_MAX_REMAPS) or its pool's dirty_list (if the | 57 | * remap_count < pool->max_remaps) or its pool's dirty_list (if the |
| 58 | * FMR needs to be unmapped before being remapped). In either of | 58 | * FMR needs to be unmapped before being remapped). In either of |
| 59 | * these cases it is a bug if the ref_count is not 0. In other words, | 59 | * these cases it is a bug if the ref_count is not 0. In other words, |
| 60 | * if ref_count is > 0, then the list member must not be linked into | 60 | * if ref_count is > 0, then the list member must not be linked into |
| @@ -84,6 +84,7 @@ struct ib_fmr_pool { | |||
| 84 | 84 | ||
| 85 | int pool_size; | 85 | int pool_size; |
| 86 | int max_pages; | 86 | int max_pages; |
| 87 | int max_remaps; | ||
| 87 | int dirty_watermark; | 88 | int dirty_watermark; |
| 88 | int dirty_len; | 89 | int dirty_len; |
| 89 | struct list_head free_list; | 90 | struct list_head free_list; |
| @@ -214,8 +215,10 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, | |||
| 214 | { | 215 | { |
| 215 | struct ib_device *device; | 216 | struct ib_device *device; |
| 216 | struct ib_fmr_pool *pool; | 217 | struct ib_fmr_pool *pool; |
| 218 | struct ib_device_attr *attr; | ||
| 217 | int i; | 219 | int i; |
| 218 | int ret; | 220 | int ret; |
| 221 | int max_remaps; | ||
| 219 | 222 | ||
| 220 | if (!params) | 223 | if (!params) |
| 221 | return ERR_PTR(-EINVAL); | 224 | return ERR_PTR(-EINVAL); |
| @@ -228,6 +231,26 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, | |||
| 228 | return ERR_PTR(-ENOSYS); | 231 | return ERR_PTR(-ENOSYS); |
| 229 | } | 232 | } |
| 230 | 233 | ||
| 234 | attr = kmalloc(sizeof *attr, GFP_KERNEL); | ||
| 235 | if (!attr) { | ||
| 236 | printk(KERN_WARNING "couldn't allocate device attr struct"); | ||
| 237 | return ERR_PTR(-ENOMEM); | ||
| 238 | } | ||
| 239 | |||
| 240 | ret = ib_query_device(device, attr); | ||
| 241 | if (ret) { | ||
| 242 | printk(KERN_WARNING "couldn't query device"); | ||
| 243 | kfree(attr); | ||
| 244 | return ERR_PTR(ret); | ||
| 245 | } | ||
| 246 | |||
| 247 | if (!attr->max_map_per_fmr) | ||
| 248 | max_remaps = IB_FMR_MAX_REMAPS; | ||
| 249 | else | ||
| 250 | max_remaps = attr->max_map_per_fmr; | ||
| 251 | |||
| 252 | kfree(attr); | ||
| 253 | |||
| 231 | pool = kmalloc(sizeof *pool, GFP_KERNEL); | 254 | pool = kmalloc(sizeof *pool, GFP_KERNEL); |
| 232 | if (!pool) { | 255 | if (!pool) { |
| 233 | printk(KERN_WARNING "couldn't allocate pool struct"); | 256 | printk(KERN_WARNING "couldn't allocate pool struct"); |
| @@ -258,6 +281,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, | |||
| 258 | 281 | ||
| 259 | pool->pool_size = 0; | 282 | pool->pool_size = 0; |
| 260 | pool->max_pages = params->max_pages_per_fmr; | 283 | pool->max_pages = params->max_pages_per_fmr; |
| 284 | pool->max_remaps = max_remaps; | ||
| 261 | pool->dirty_watermark = params->dirty_watermark; | 285 | pool->dirty_watermark = params->dirty_watermark; |
| 262 | pool->dirty_len = 0; | 286 | pool->dirty_len = 0; |
| 263 | spin_lock_init(&pool->pool_lock); | 287 | spin_lock_init(&pool->pool_lock); |
| @@ -279,7 +303,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, | |||
| 279 | struct ib_pool_fmr *fmr; | 303 | struct ib_pool_fmr *fmr; |
| 280 | struct ib_fmr_attr attr = { | 304 | struct ib_fmr_attr attr = { |
| 281 | .max_pages = params->max_pages_per_fmr, | 305 | .max_pages = params->max_pages_per_fmr, |
| 282 | .max_maps = IB_FMR_MAX_REMAPS, | 306 | .max_maps = pool->max_remaps, |
| 283 | .page_shift = params->page_shift | 307 | .page_shift = params->page_shift |
| 284 | }; | 308 | }; |
| 285 | 309 | ||
| @@ -489,7 +513,7 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr) | |||
| 489 | 513 | ||
| 490 | --fmr->ref_count; | 514 | --fmr->ref_count; |
| 491 | if (!fmr->ref_count) { | 515 | if (!fmr->ref_count) { |
| 492 | if (fmr->remap_count < IB_FMR_MAX_REMAPS) { | 516 | if (fmr->remap_count < pool->max_remaps) { |
| 493 | list_add_tail(&fmr->list, &pool->free_list); | 517 | list_add_tail(&fmr->list, &pool->free_list); |
| 494 | } else { | 518 | } else { |
| 495 | list_add_tail(&fmr->list, &pool->dirty_list); | 519 | list_add_tail(&fmr->list, &pool->dirty_list); |
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 5ad41a64314c..b38e02a5db35 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | * $Id: mad.c 5596 2006-03-03 01:00:07Z sean.hefty $ | 34 | * $Id: mad.c 5596 2006-03-03 01:00:07Z sean.hefty $ |
| 35 | */ | 35 | */ |
| 36 | #include <linux/dma-mapping.h> | 36 | #include <linux/dma-mapping.h> |
| 37 | #include <rdma/ib_cache.h> | ||
| 37 | 38 | ||
| 38 | #include "mad_priv.h" | 39 | #include "mad_priv.h" |
| 39 | #include "mad_rmpp.h" | 40 | #include "mad_rmpp.h" |
| @@ -45,8 +46,7 @@ MODULE_DESCRIPTION("kernel IB MAD API"); | |||
| 45 | MODULE_AUTHOR("Hal Rosenstock"); | 46 | MODULE_AUTHOR("Hal Rosenstock"); |
| 46 | MODULE_AUTHOR("Sean Hefty"); | 47 | MODULE_AUTHOR("Sean Hefty"); |
| 47 | 48 | ||
| 48 | 49 | static kmem_cache_t *ib_mad_cache; | |
| 49 | kmem_cache_t *ib_mad_cache; | ||
| 50 | 50 | ||
| 51 | static struct list_head ib_mad_port_list; | 51 | static struct list_head ib_mad_port_list; |
| 52 | static u32 ib_mad_client_id = 0; | 52 | static u32 ib_mad_client_id = 0; |
| @@ -1673,20 +1673,21 @@ static inline int rcv_has_same_class(struct ib_mad_send_wr_private *wr, | |||
| 1673 | rwc->recv_buf.mad->mad_hdr.mgmt_class; | 1673 | rwc->recv_buf.mad->mad_hdr.mgmt_class; |
| 1674 | } | 1674 | } |
| 1675 | 1675 | ||
| 1676 | static inline int rcv_has_same_gid(struct ib_mad_send_wr_private *wr, | 1676 | static inline int rcv_has_same_gid(struct ib_mad_agent_private *mad_agent_priv, |
| 1677 | struct ib_mad_send_wr_private *wr, | ||
| 1677 | struct ib_mad_recv_wc *rwc ) | 1678 | struct ib_mad_recv_wc *rwc ) |
| 1678 | { | 1679 | { |
| 1679 | struct ib_ah_attr attr; | 1680 | struct ib_ah_attr attr; |
| 1680 | u8 send_resp, rcv_resp; | 1681 | u8 send_resp, rcv_resp; |
| 1682 | union ib_gid sgid; | ||
| 1683 | struct ib_device *device = mad_agent_priv->agent.device; | ||
| 1684 | u8 port_num = mad_agent_priv->agent.port_num; | ||
| 1685 | u8 lmc; | ||
| 1681 | 1686 | ||
| 1682 | send_resp = ((struct ib_mad *)(wr->send_buf.mad))-> | 1687 | send_resp = ((struct ib_mad *)(wr->send_buf.mad))-> |
| 1683 | mad_hdr.method & IB_MGMT_METHOD_RESP; | 1688 | mad_hdr.method & IB_MGMT_METHOD_RESP; |
| 1684 | rcv_resp = rwc->recv_buf.mad->mad_hdr.method & IB_MGMT_METHOD_RESP; | 1689 | rcv_resp = rwc->recv_buf.mad->mad_hdr.method & IB_MGMT_METHOD_RESP; |
| 1685 | 1690 | ||
| 1686 | if (!send_resp && rcv_resp) | ||
| 1687 | /* is request/response. GID/LIDs are both local (same). */ | ||
| 1688 | return 1; | ||
| 1689 | |||
| 1690 | if (send_resp == rcv_resp) | 1691 | if (send_resp == rcv_resp) |
| 1691 | /* both requests, or both responses. GIDs different */ | 1692 | /* both requests, or both responses. GIDs different */ |
| 1692 | return 0; | 1693 | return 0; |
| @@ -1695,48 +1696,78 @@ static inline int rcv_has_same_gid(struct ib_mad_send_wr_private *wr, | |||
| 1695 | /* Assume not equal, to avoid false positives. */ | 1696 | /* Assume not equal, to avoid false positives. */ |
| 1696 | return 0; | 1697 | return 0; |
| 1697 | 1698 | ||
| 1698 | if (!(attr.ah_flags & IB_AH_GRH) && !(rwc->wc->wc_flags & IB_WC_GRH)) | 1699 | if (!!(attr.ah_flags & IB_AH_GRH) != |
| 1699 | return attr.dlid == rwc->wc->slid; | 1700 | !!(rwc->wc->wc_flags & IB_WC_GRH)) |
| 1700 | else if ((attr.ah_flags & IB_AH_GRH) && | ||
| 1701 | (rwc->wc->wc_flags & IB_WC_GRH)) | ||
| 1702 | return memcmp(attr.grh.dgid.raw, | ||
| 1703 | rwc->recv_buf.grh->sgid.raw, 16) == 0; | ||
| 1704 | else | ||
| 1705 | /* one has GID, other does not. Assume different */ | 1701 | /* one has GID, other does not. Assume different */ |
| 1706 | return 0; | 1702 | return 0; |
| 1703 | |||
| 1704 | if (!send_resp && rcv_resp) { | ||
| 1705 | /* is request/response. */ | ||
| 1706 | if (!(attr.ah_flags & IB_AH_GRH)) { | ||
| 1707 | if (ib_get_cached_lmc(device, port_num, &lmc)) | ||
| 1708 | return 0; | ||
| 1709 | return (!lmc || !((attr.src_path_bits ^ | ||
| 1710 | rwc->wc->dlid_path_bits) & | ||
| 1711 | ((1 << lmc) - 1))); | ||
| 1712 | } else { | ||
| 1713 | if (ib_get_cached_gid(device, port_num, | ||
| 1714 | attr.grh.sgid_index, &sgid)) | ||
| 1715 | return 0; | ||
| 1716 | return !memcmp(sgid.raw, rwc->recv_buf.grh->dgid.raw, | ||
| 1717 | 16); | ||
| 1718 | } | ||
| 1719 | } | ||
| 1720 | |||
| 1721 | if (!(attr.ah_flags & IB_AH_GRH)) | ||
| 1722 | return attr.dlid == rwc->wc->slid; | ||
| 1723 | else | ||
| 1724 | return !memcmp(attr.grh.dgid.raw, rwc->recv_buf.grh->sgid.raw, | ||
| 1725 | 16); | ||
| 1726 | } | ||
| 1727 | |||
| 1728 | static inline int is_direct(u8 class) | ||
| 1729 | { | ||
| 1730 | return (class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE); | ||
| 1707 | } | 1731 | } |
| 1732 | |||
| 1708 | struct ib_mad_send_wr_private* | 1733 | struct ib_mad_send_wr_private* |
| 1709 | ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, | 1734 | ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, |
| 1710 | struct ib_mad_recv_wc *mad_recv_wc) | 1735 | struct ib_mad_recv_wc *wc) |
| 1711 | { | 1736 | { |
| 1712 | struct ib_mad_send_wr_private *mad_send_wr; | 1737 | struct ib_mad_send_wr_private *wr; |
| 1713 | struct ib_mad *mad; | 1738 | struct ib_mad *mad; |
| 1714 | 1739 | ||
| 1715 | mad = (struct ib_mad *)mad_recv_wc->recv_buf.mad; | 1740 | mad = (struct ib_mad *)wc->recv_buf.mad; |
| 1716 | 1741 | ||
| 1717 | list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list, | 1742 | list_for_each_entry(wr, &mad_agent_priv->wait_list, agent_list) { |
| 1718 | agent_list) { | 1743 | if ((wr->tid == mad->mad_hdr.tid) && |
| 1719 | if ((mad_send_wr->tid == mad->mad_hdr.tid) && | 1744 | rcv_has_same_class(wr, wc) && |
| 1720 | rcv_has_same_class(mad_send_wr, mad_recv_wc) && | 1745 | /* |
| 1721 | rcv_has_same_gid(mad_send_wr, mad_recv_wc)) | 1746 | * Don't check GID for direct routed MADs. |
| 1722 | return mad_send_wr; | 1747 | * These might have permissive LIDs. |
| 1748 | */ | ||
| 1749 | (is_direct(wc->recv_buf.mad->mad_hdr.mgmt_class) || | ||
| 1750 | rcv_has_same_gid(mad_agent_priv, wr, wc))) | ||
| 1751 | return wr; | ||
| 1723 | } | 1752 | } |
| 1724 | 1753 | ||
| 1725 | /* | 1754 | /* |
| 1726 | * It's possible to receive the response before we've | 1755 | * It's possible to receive the response before we've |
| 1727 | * been notified that the send has completed | 1756 | * been notified that the send has completed |
| 1728 | */ | 1757 | */ |
| 1729 | list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list, | 1758 | list_for_each_entry(wr, &mad_agent_priv->send_list, agent_list) { |
| 1730 | agent_list) { | 1759 | if (is_data_mad(mad_agent_priv, wr->send_buf.mad) && |
| 1731 | if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) && | 1760 | wr->tid == mad->mad_hdr.tid && |
| 1732 | mad_send_wr->tid == mad->mad_hdr.tid && | 1761 | wr->timeout && |
| 1733 | mad_send_wr->timeout && | 1762 | rcv_has_same_class(wr, wc) && |
| 1734 | rcv_has_same_class(mad_send_wr, mad_recv_wc) && | 1763 | /* |
| 1735 | rcv_has_same_gid(mad_send_wr, mad_recv_wc)) { | 1764 | * Don't check GID for direct routed MADs. |
| 1765 | * These might have permissive LIDs. | ||
| 1766 | */ | ||
| 1767 | (is_direct(wc->recv_buf.mad->mad_hdr.mgmt_class) || | ||
| 1768 | rcv_has_same_gid(mad_agent_priv, wr, wc))) | ||
| 1736 | /* Verify request has not been canceled */ | 1769 | /* Verify request has not been canceled */ |
| 1737 | return (mad_send_wr->status == IB_WC_SUCCESS) ? | 1770 | return (wr->status == IB_WC_SUCCESS) ? wr : NULL; |
| 1738 | mad_send_wr : NULL; | ||
| 1739 | } | ||
| 1740 | } | 1771 | } |
| 1741 | return NULL; | 1772 | return NULL; |
| 1742 | } | 1773 | } |
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index b4fa28d3160f..d147f3bad2ce 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h | |||
| @@ -212,8 +212,6 @@ struct ib_mad_port_private { | |||
| 212 | struct ib_mad_qp_info qp_info[IB_MAD_QPS_CORE]; | 212 | struct ib_mad_qp_info qp_info[IB_MAD_QPS_CORE]; |
| 213 | }; | 213 | }; |
| 214 | 214 | ||
| 215 | extern kmem_cache_t *ib_mad_cache; | ||
| 216 | |||
| 217 | int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr); | 215 | int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr); |
| 218 | 216 | ||
| 219 | struct ib_mad_send_wr_private * | 217 | struct ib_mad_send_wr_private * |
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 501cc054cb3b..e911c99ff843 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c | |||
| @@ -47,6 +47,7 @@ | |||
| 47 | 47 | ||
| 48 | #include <rdma/ib_pack.h> | 48 | #include <rdma/ib_pack.h> |
| 49 | #include <rdma/ib_sa.h> | 49 | #include <rdma/ib_sa.h> |
| 50 | #include <rdma/ib_cache.h> | ||
| 50 | 51 | ||
| 51 | MODULE_AUTHOR("Roland Dreier"); | 52 | MODULE_AUTHOR("Roland Dreier"); |
| 52 | MODULE_DESCRIPTION("InfiniBand subnet administration query support"); | 53 | MODULE_DESCRIPTION("InfiniBand subnet administration query support"); |
| @@ -441,6 +442,36 @@ void ib_sa_cancel_query(int id, struct ib_sa_query *query) | |||
| 441 | } | 442 | } |
| 442 | EXPORT_SYMBOL(ib_sa_cancel_query); | 443 | EXPORT_SYMBOL(ib_sa_cancel_query); |
| 443 | 444 | ||
| 445 | int ib_init_ah_from_path(struct ib_device *device, u8 port_num, | ||
| 446 | struct ib_sa_path_rec *rec, struct ib_ah_attr *ah_attr) | ||
| 447 | { | ||
| 448 | int ret; | ||
| 449 | u16 gid_index; | ||
| 450 | |||
| 451 | memset(ah_attr, 0, sizeof *ah_attr); | ||
| 452 | ah_attr->dlid = be16_to_cpu(rec->dlid); | ||
| 453 | ah_attr->sl = rec->sl; | ||
| 454 | ah_attr->src_path_bits = be16_to_cpu(rec->slid) & 0x7f; | ||
| 455 | ah_attr->port_num = port_num; | ||
| 456 | |||
| 457 | if (rec->hop_limit > 1) { | ||
| 458 | ah_attr->ah_flags = IB_AH_GRH; | ||
| 459 | ah_attr->grh.dgid = rec->dgid; | ||
| 460 | |||
| 461 | ret = ib_find_cached_gid(device, &rec->sgid, &port_num, | ||
| 462 | &gid_index); | ||
| 463 | if (ret) | ||
| 464 | return ret; | ||
| 465 | |||
| 466 | ah_attr->grh.sgid_index = gid_index; | ||
| 467 | ah_attr->grh.flow_label = be32_to_cpu(rec->flow_label); | ||
| 468 | ah_attr->grh.hop_limit = rec->hop_limit; | ||
| 469 | ah_attr->grh.traffic_class = rec->traffic_class; | ||
| 470 | } | ||
| 471 | return 0; | ||
| 472 | } | ||
| 473 | EXPORT_SYMBOL(ib_init_ah_from_path); | ||
| 474 | |||
| 444 | static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent) | 475 | static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent) |
| 445 | { | 476 | { |
| 446 | unsigned long flags; | 477 | unsigned long flags; |
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 9164a09b6ccd..c1c6fda9452c 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c | |||
| @@ -30,7 +30,7 @@ | |||
| 30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 31 | * SOFTWARE. | 31 | * SOFTWARE. |
| 32 | * | 32 | * |
| 33 | * $Id: ucm.c 2594 2005-06-13 19:46:02Z libor $ | 33 | * $Id: ucm.c 4311 2005-12-05 18:42:01Z sean.hefty $ |
| 34 | */ | 34 | */ |
| 35 | 35 | ||
| 36 | #include <linux/completion.h> | 36 | #include <linux/completion.h> |
| @@ -50,6 +50,7 @@ | |||
| 50 | 50 | ||
| 51 | #include <rdma/ib_cm.h> | 51 | #include <rdma/ib_cm.h> |
| 52 | #include <rdma/ib_user_cm.h> | 52 | #include <rdma/ib_user_cm.h> |
| 53 | #include <rdma/ib_marshall.h> | ||
| 53 | 54 | ||
| 54 | MODULE_AUTHOR("Libor Michalek"); | 55 | MODULE_AUTHOR("Libor Michalek"); |
| 55 | MODULE_DESCRIPTION("InfiniBand userspace Connection Manager access"); | 56 | MODULE_DESCRIPTION("InfiniBand userspace Connection Manager access"); |
| @@ -63,7 +64,7 @@ struct ib_ucm_device { | |||
| 63 | }; | 64 | }; |
| 64 | 65 | ||
| 65 | struct ib_ucm_file { | 66 | struct ib_ucm_file { |
| 66 | struct semaphore mutex; | 67 | struct mutex file_mutex; |
| 67 | struct file *filp; | 68 | struct file *filp; |
| 68 | struct ib_ucm_device *device; | 69 | struct ib_ucm_device *device; |
| 69 | 70 | ||
| @@ -152,7 +153,7 @@ static void ib_ucm_cleanup_events(struct ib_ucm_context *ctx) | |||
| 152 | { | 153 | { |
| 153 | struct ib_ucm_event *uevent; | 154 | struct ib_ucm_event *uevent; |
| 154 | 155 | ||
| 155 | down(&ctx->file->mutex); | 156 | mutex_lock(&ctx->file->file_mutex); |
| 156 | list_del(&ctx->file_list); | 157 | list_del(&ctx->file_list); |
| 157 | while (!list_empty(&ctx->events)) { | 158 | while (!list_empty(&ctx->events)) { |
| 158 | 159 | ||
| @@ -167,7 +168,7 @@ static void ib_ucm_cleanup_events(struct ib_ucm_context *ctx) | |||
| 167 | 168 | ||
| 168 | kfree(uevent); | 169 | kfree(uevent); |
| 169 | } | 170 | } |
| 170 | up(&ctx->file->mutex); | 171 | mutex_unlock(&ctx->file->file_mutex); |
| 171 | } | 172 | } |
| 172 | 173 | ||
| 173 | static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file) | 174 | static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file) |
| @@ -205,36 +206,6 @@ error: | |||
| 205 | return NULL; | 206 | return NULL; |
| 206 | } | 207 | } |
| 207 | 208 | ||
| 208 | static void ib_ucm_event_path_get(struct ib_ucm_path_rec *upath, | ||
| 209 | struct ib_sa_path_rec *kpath) | ||
| 210 | { | ||
| 211 | if (!kpath || !upath) | ||
| 212 | return; | ||
| 213 | |||
| 214 | memcpy(upath->dgid, kpath->dgid.raw, sizeof *upath->dgid); | ||
| 215 | memcpy(upath->sgid, kpath->sgid.raw, sizeof *upath->sgid); | ||
| 216 | |||
| 217 | upath->dlid = kpath->dlid; | ||
| 218 | upath->slid = kpath->slid; | ||
| 219 | upath->raw_traffic = kpath->raw_traffic; | ||
| 220 | upath->flow_label = kpath->flow_label; | ||
| 221 | upath->hop_limit = kpath->hop_limit; | ||
| 222 | upath->traffic_class = kpath->traffic_class; | ||
| 223 | upath->reversible = kpath->reversible; | ||
| 224 | upath->numb_path = kpath->numb_path; | ||
| 225 | upath->pkey = kpath->pkey; | ||
| 226 | upath->sl = kpath->sl; | ||
| 227 | upath->mtu_selector = kpath->mtu_selector; | ||
| 228 | upath->mtu = kpath->mtu; | ||
| 229 | upath->rate_selector = kpath->rate_selector; | ||
| 230 | upath->rate = kpath->rate; | ||
| 231 | upath->packet_life_time = kpath->packet_life_time; | ||
| 232 | upath->preference = kpath->preference; | ||
| 233 | |||
| 234 | upath->packet_life_time_selector = | ||
| 235 | kpath->packet_life_time_selector; | ||
| 236 | } | ||
| 237 | |||
| 238 | static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq, | 209 | static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq, |
| 239 | struct ib_cm_req_event_param *kreq) | 210 | struct ib_cm_req_event_param *kreq) |
| 240 | { | 211 | { |
| @@ -253,8 +224,10 @@ static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq, | |||
| 253 | ureq->srq = kreq->srq; | 224 | ureq->srq = kreq->srq; |
| 254 | ureq->port = kreq->port; | 225 | ureq->port = kreq->port; |
| 255 | 226 | ||
| 256 | ib_ucm_event_path_get(&ureq->primary_path, kreq->primary_path); | 227 | ib_copy_path_rec_to_user(&ureq->primary_path, kreq->primary_path); |
| 257 | ib_ucm_event_path_get(&ureq->alternate_path, kreq->alternate_path); | 228 | if (kreq->alternate_path) |
| 229 | ib_copy_path_rec_to_user(&ureq->alternate_path, | ||
| 230 | kreq->alternate_path); | ||
| 258 | } | 231 | } |
| 259 | 232 | ||
| 260 | static void ib_ucm_event_rep_get(struct ib_ucm_rep_event_resp *urep, | 233 | static void ib_ucm_event_rep_get(struct ib_ucm_rep_event_resp *urep, |
| @@ -324,8 +297,8 @@ static int ib_ucm_event_process(struct ib_cm_event *evt, | |||
| 324 | info = evt->param.rej_rcvd.ari; | 297 | info = evt->param.rej_rcvd.ari; |
| 325 | break; | 298 | break; |
| 326 | case IB_CM_LAP_RECEIVED: | 299 | case IB_CM_LAP_RECEIVED: |
| 327 | ib_ucm_event_path_get(&uvt->resp.u.lap_resp.path, | 300 | ib_copy_path_rec_to_user(&uvt->resp.u.lap_resp.path, |
| 328 | evt->param.lap_rcvd.alternate_path); | 301 | evt->param.lap_rcvd.alternate_path); |
| 329 | uvt->data_len = IB_CM_LAP_PRIVATE_DATA_SIZE; | 302 | uvt->data_len = IB_CM_LAP_PRIVATE_DATA_SIZE; |
| 330 | uvt->resp.present = IB_UCM_PRES_ALTERNATE; | 303 | uvt->resp.present = IB_UCM_PRES_ALTERNATE; |
| 331 | break; | 304 | break; |
| @@ -402,11 +375,11 @@ static int ib_ucm_event_handler(struct ib_cm_id *cm_id, | |||
| 402 | if (result) | 375 | if (result) |
| 403 | goto err2; | 376 | goto err2; |
| 404 | 377 | ||
| 405 | down(&ctx->file->mutex); | 378 | mutex_lock(&ctx->file->file_mutex); |
| 406 | list_add_tail(&uevent->file_list, &ctx->file->events); | 379 | list_add_tail(&uevent->file_list, &ctx->file->events); |
| 407 | list_add_tail(&uevent->ctx_list, &ctx->events); | 380 | list_add_tail(&uevent->ctx_list, &ctx->events); |
| 408 | wake_up_interruptible(&ctx->file->poll_wait); | 381 | wake_up_interruptible(&ctx->file->poll_wait); |
| 409 | up(&ctx->file->mutex); | 382 | mutex_unlock(&ctx->file->file_mutex); |
| 410 | return 0; | 383 | return 0; |
| 411 | 384 | ||
| 412 | err2: | 385 | err2: |
| @@ -432,7 +405,7 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, | |||
| 432 | if (copy_from_user(&cmd, inbuf, sizeof(cmd))) | 405 | if (copy_from_user(&cmd, inbuf, sizeof(cmd))) |
| 433 | return -EFAULT; | 406 | return -EFAULT; |
| 434 | 407 | ||
| 435 | down(&file->mutex); | 408 | mutex_lock(&file->file_mutex); |
| 436 | while (list_empty(&file->events)) { | 409 | while (list_empty(&file->events)) { |
| 437 | 410 | ||
| 438 | if (file->filp->f_flags & O_NONBLOCK) { | 411 | if (file->filp->f_flags & O_NONBLOCK) { |
| @@ -447,9 +420,9 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, | |||
| 447 | 420 | ||
| 448 | prepare_to_wait(&file->poll_wait, &wait, TASK_INTERRUPTIBLE); | 421 | prepare_to_wait(&file->poll_wait, &wait, TASK_INTERRUPTIBLE); |
| 449 | 422 | ||
| 450 | up(&file->mutex); | 423 | mutex_unlock(&file->file_mutex); |
| 451 | schedule(); | 424 | schedule(); |
| 452 | down(&file->mutex); | 425 | mutex_lock(&file->file_mutex); |
| 453 | 426 | ||
| 454 | finish_wait(&file->poll_wait, &wait); | 427 | finish_wait(&file->poll_wait, &wait); |
| 455 | } | 428 | } |
| @@ -509,7 +482,7 @@ static ssize_t ib_ucm_event(struct ib_ucm_file *file, | |||
| 509 | kfree(uevent->info); | 482 | kfree(uevent->info); |
| 510 | kfree(uevent); | 483 | kfree(uevent); |
| 511 | done: | 484 | done: |
| 512 | up(&file->mutex); | 485 | mutex_unlock(&file->file_mutex); |
| 513 | return result; | 486 | return result; |
| 514 | } | 487 | } |
| 515 | 488 | ||
| @@ -528,9 +501,9 @@ static ssize_t ib_ucm_create_id(struct ib_ucm_file *file, | |||
| 528 | if (copy_from_user(&cmd, inbuf, sizeof(cmd))) | 501 | if (copy_from_user(&cmd, inbuf, sizeof(cmd))) |
| 529 | return -EFAULT; | 502 | return -EFAULT; |
| 530 | 503 | ||
| 531 | down(&file->mutex); | 504 | mutex_lock(&file->file_mutex); |
| 532 | ctx = ib_ucm_ctx_alloc(file); | 505 | ctx = ib_ucm_ctx_alloc(file); |
| 533 | up(&file->mutex); | 506 | mutex_unlock(&file->file_mutex); |
| 534 | if (!ctx) | 507 | if (!ctx) |
| 535 | return -ENOMEM; | 508 | return -ENOMEM; |
| 536 | 509 | ||
| @@ -637,65 +610,11 @@ static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file, | |||
| 637 | return result; | 610 | return result; |
| 638 | } | 611 | } |
| 639 | 612 | ||
| 640 | static void ib_ucm_copy_ah_attr(struct ib_ucm_ah_attr *dest_attr, | ||
| 641 | struct ib_ah_attr *src_attr) | ||
| 642 | { | ||
| 643 | memcpy(dest_attr->grh_dgid, src_attr->grh.dgid.raw, | ||
| 644 | sizeof src_attr->grh.dgid); | ||
| 645 | dest_attr->grh_flow_label = src_attr->grh.flow_label; | ||
| 646 | dest_attr->grh_sgid_index = src_attr->grh.sgid_index; | ||
| 647 | dest_attr->grh_hop_limit = src_attr->grh.hop_limit; | ||
| 648 | dest_attr->grh_traffic_class = src_attr->grh.traffic_class; | ||
| 649 | |||
| 650 | dest_attr->dlid = src_attr->dlid; | ||
| 651 | dest_attr->sl = src_attr->sl; | ||
| 652 | dest_attr->src_path_bits = src_attr->src_path_bits; | ||
| 653 | dest_attr->static_rate = src_attr->static_rate; | ||
| 654 | dest_attr->is_global = (src_attr->ah_flags & IB_AH_GRH); | ||
| 655 | dest_attr->port_num = src_attr->port_num; | ||
| 656 | } | ||
| 657 | |||
| 658 | static void ib_ucm_copy_qp_attr(struct ib_ucm_init_qp_attr_resp *dest_attr, | ||
| 659 | struct ib_qp_attr *src_attr) | ||
| 660 | { | ||
| 661 | dest_attr->cur_qp_state = src_attr->cur_qp_state; | ||
| 662 | dest_attr->path_mtu = src_attr->path_mtu; | ||
| 663 | dest_attr->path_mig_state = src_attr->path_mig_state; | ||
| 664 | dest_attr->qkey = src_attr->qkey; | ||
| 665 | dest_attr->rq_psn = src_attr->rq_psn; | ||
| 666 | dest_attr->sq_psn = src_attr->sq_psn; | ||
| 667 | dest_attr->dest_qp_num = src_attr->dest_qp_num; | ||
| 668 | dest_attr->qp_access_flags = src_attr->qp_access_flags; | ||
| 669 | |||
| 670 | dest_attr->max_send_wr = src_attr->cap.max_send_wr; | ||
| 671 | dest_attr->max_recv_wr = src_attr->cap.max_recv_wr; | ||
| 672 | dest_attr->max_send_sge = src_attr->cap.max_send_sge; | ||
| 673 | dest_attr->max_recv_sge = src_attr->cap.max_recv_sge; | ||
| 674 | dest_attr->max_inline_data = src_attr->cap.max_inline_data; | ||
| 675 | |||
| 676 | ib_ucm_copy_ah_attr(&dest_attr->ah_attr, &src_attr->ah_attr); | ||
| 677 | ib_ucm_copy_ah_attr(&dest_attr->alt_ah_attr, &src_attr->alt_ah_attr); | ||
| 678 | |||
| 679 | dest_attr->pkey_index = src_attr->pkey_index; | ||
| 680 | dest_attr->alt_pkey_index = src_attr->alt_pkey_index; | ||
| 681 | dest_attr->en_sqd_async_notify = src_attr->en_sqd_async_notify; | ||
| 682 | dest_attr->sq_draining = src_attr->sq_draining; | ||
| 683 | dest_attr->max_rd_atomic = src_attr->max_rd_atomic; | ||
| 684 | dest_attr->max_dest_rd_atomic = src_attr->max_dest_rd_atomic; | ||
| 685 | dest_attr->min_rnr_timer = src_attr->min_rnr_timer; | ||
| 686 | dest_attr->port_num = src_attr->port_num; | ||
| 687 | dest_attr->timeout = src_attr->timeout; | ||
| 688 | dest_attr->retry_cnt = src_attr->retry_cnt; | ||
| 689 | dest_attr->rnr_retry = src_attr->rnr_retry; | ||
| 690 | dest_attr->alt_port_num = src_attr->alt_port_num; | ||
| 691 | dest_attr->alt_timeout = src_attr->alt_timeout; | ||
| 692 | } | ||
| 693 | |||
| 694 | static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file, | 613 | static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file, |
| 695 | const char __user *inbuf, | 614 | const char __user *inbuf, |
| 696 | int in_len, int out_len) | 615 | int in_len, int out_len) |
| 697 | { | 616 | { |
| 698 | struct ib_ucm_init_qp_attr_resp resp; | 617 | struct ib_uverbs_qp_attr resp; |
| 699 | struct ib_ucm_init_qp_attr cmd; | 618 | struct ib_ucm_init_qp_attr cmd; |
| 700 | struct ib_ucm_context *ctx; | 619 | struct ib_ucm_context *ctx; |
| 701 | struct ib_qp_attr qp_attr; | 620 | struct ib_qp_attr qp_attr; |
| @@ -718,7 +637,7 @@ static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file, | |||
| 718 | if (result) | 637 | if (result) |
| 719 | goto out; | 638 | goto out; |
| 720 | 639 | ||
| 721 | ib_ucm_copy_qp_attr(&resp, &qp_attr); | 640 | ib_copy_qp_attr_to_user(&resp, &qp_attr); |
| 722 | 641 | ||
| 723 | if (copy_to_user((void __user *)(unsigned long)cmd.response, | 642 | if (copy_to_user((void __user *)(unsigned long)cmd.response, |
| 724 | &resp, sizeof(resp))) | 643 | &resp, sizeof(resp))) |
| @@ -729,6 +648,17 @@ out: | |||
| 729 | return result; | 648 | return result; |
| 730 | } | 649 | } |
| 731 | 650 | ||
| 651 | static int ucm_validate_listen(__be64 service_id, __be64 service_mask) | ||
| 652 | { | ||
| 653 | service_id &= service_mask; | ||
| 654 | |||
| 655 | if (((service_id & IB_CMA_SERVICE_ID_MASK) == IB_CMA_SERVICE_ID) || | ||
| 656 | ((service_id & IB_SDP_SERVICE_ID_MASK) == IB_SDP_SERVICE_ID)) | ||
| 657 | return -EINVAL; | ||
| 658 | |||
| 659 | return 0; | ||
| 660 | } | ||
| 661 | |||
| 732 | static ssize_t ib_ucm_listen(struct ib_ucm_file *file, | 662 | static ssize_t ib_ucm_listen(struct ib_ucm_file *file, |
| 733 | const char __user *inbuf, | 663 | const char __user *inbuf, |
| 734 | int in_len, int out_len) | 664 | int in_len, int out_len) |
| @@ -744,7 +674,13 @@ static ssize_t ib_ucm_listen(struct ib_ucm_file *file, | |||
| 744 | if (IS_ERR(ctx)) | 674 | if (IS_ERR(ctx)) |
| 745 | return PTR_ERR(ctx); | 675 | return PTR_ERR(ctx); |
| 746 | 676 | ||
| 747 | result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask); | 677 | result = ucm_validate_listen(cmd.service_id, cmd.service_mask); |
| 678 | if (result) | ||
| 679 | goto out; | ||
| 680 | |||
| 681 | result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask, | ||
| 682 | NULL); | ||
| 683 | out: | ||
| 748 | ib_ucm_ctx_put(ctx); | 684 | ib_ucm_ctx_put(ctx); |
| 749 | return result; | 685 | return result; |
| 750 | } | 686 | } |
| @@ -793,7 +729,7 @@ static int ib_ucm_alloc_data(const void **dest, u64 src, u32 len) | |||
| 793 | 729 | ||
| 794 | static int ib_ucm_path_get(struct ib_sa_path_rec **path, u64 src) | 730 | static int ib_ucm_path_get(struct ib_sa_path_rec **path, u64 src) |
| 795 | { | 731 | { |
| 796 | struct ib_ucm_path_rec ucm_path; | 732 | struct ib_user_path_rec upath; |
| 797 | struct ib_sa_path_rec *sa_path; | 733 | struct ib_sa_path_rec *sa_path; |
| 798 | 734 | ||
| 799 | *path = NULL; | 735 | *path = NULL; |
| @@ -805,36 +741,14 @@ static int ib_ucm_path_get(struct ib_sa_path_rec **path, u64 src) | |||
| 805 | if (!sa_path) | 741 | if (!sa_path) |
| 806 | return -ENOMEM; | 742 | return -ENOMEM; |
| 807 | 743 | ||
| 808 | if (copy_from_user(&ucm_path, (void __user *)(unsigned long)src, | 744 | if (copy_from_user(&upath, (void __user *)(unsigned long)src, |
| 809 | sizeof(ucm_path))) { | 745 | sizeof(upath))) { |
| 810 | 746 | ||
| 811 | kfree(sa_path); | 747 | kfree(sa_path); |
| 812 | return -EFAULT; | 748 | return -EFAULT; |
| 813 | } | 749 | } |
| 814 | 750 | ||
| 815 | memcpy(sa_path->dgid.raw, ucm_path.dgid, sizeof sa_path->dgid); | 751 | ib_copy_path_rec_from_user(sa_path, &upath); |
| 816 | memcpy(sa_path->sgid.raw, ucm_path.sgid, sizeof sa_path->sgid); | ||
| 817 | |||
| 818 | sa_path->dlid = ucm_path.dlid; | ||
| 819 | sa_path->slid = ucm_path.slid; | ||
| 820 | sa_path->raw_traffic = ucm_path.raw_traffic; | ||
| 821 | sa_path->flow_label = ucm_path.flow_label; | ||
| 822 | sa_path->hop_limit = ucm_path.hop_limit; | ||
| 823 | sa_path->traffic_class = ucm_path.traffic_class; | ||
| 824 | sa_path->reversible = ucm_path.reversible; | ||
| 825 | sa_path->numb_path = ucm_path.numb_path; | ||
| 826 | sa_path->pkey = ucm_path.pkey; | ||
| 827 | sa_path->sl = ucm_path.sl; | ||
| 828 | sa_path->mtu_selector = ucm_path.mtu_selector; | ||
| 829 | sa_path->mtu = ucm_path.mtu; | ||
| 830 | sa_path->rate_selector = ucm_path.rate_selector; | ||
| 831 | sa_path->rate = ucm_path.rate; | ||
| 832 | sa_path->packet_life_time = ucm_path.packet_life_time; | ||
| 833 | sa_path->preference = ucm_path.preference; | ||
| 834 | |||
| 835 | sa_path->packet_life_time_selector = | ||
| 836 | ucm_path.packet_life_time_selector; | ||
| 837 | |||
| 838 | *path = sa_path; | 752 | *path = sa_path; |
| 839 | return 0; | 753 | return 0; |
| 840 | } | 754 | } |
| @@ -1130,7 +1044,6 @@ static ssize_t ib_ucm_send_sidr_req(struct ib_ucm_file *file, | |||
| 1130 | param.service_id = cmd.sid; | 1044 | param.service_id = cmd.sid; |
| 1131 | param.timeout_ms = cmd.timeout; | 1045 | param.timeout_ms = cmd.timeout; |
| 1132 | param.max_cm_retries = cmd.max_cm_retries; | 1046 | param.max_cm_retries = cmd.max_cm_retries; |
| 1133 | param.pkey = cmd.pkey; | ||
| 1134 | 1047 | ||
| 1135 | ctx = ib_ucm_ctx_get(file, cmd.id); | 1048 | ctx = ib_ucm_ctx_get(file, cmd.id); |
| 1136 | if (!IS_ERR(ctx)) { | 1049 | if (!IS_ERR(ctx)) { |
| @@ -1263,7 +1176,7 @@ static int ib_ucm_open(struct inode *inode, struct file *filp) | |||
| 1263 | INIT_LIST_HEAD(&file->ctxs); | 1176 | INIT_LIST_HEAD(&file->ctxs); |
| 1264 | init_waitqueue_head(&file->poll_wait); | 1177 | init_waitqueue_head(&file->poll_wait); |
| 1265 | 1178 | ||
| 1266 | init_MUTEX(&file->mutex); | 1179 | mutex_init(&file->file_mutex); |
| 1267 | 1180 | ||
| 1268 | filp->private_data = file; | 1181 | filp->private_data = file; |
| 1269 | file->filp = filp; | 1182 | file->filp = filp; |
| @@ -1277,11 +1190,11 @@ static int ib_ucm_close(struct inode *inode, struct file *filp) | |||
| 1277 | struct ib_ucm_file *file = filp->private_data; | 1190 | struct ib_ucm_file *file = filp->private_data; |
| 1278 | struct ib_ucm_context *ctx; | 1191 | struct ib_ucm_context *ctx; |
| 1279 | 1192 | ||
| 1280 | down(&file->mutex); | 1193 | mutex_lock(&file->file_mutex); |
| 1281 | while (!list_empty(&file->ctxs)) { | 1194 | while (!list_empty(&file->ctxs)) { |
| 1282 | ctx = list_entry(file->ctxs.next, | 1195 | ctx = list_entry(file->ctxs.next, |
| 1283 | struct ib_ucm_context, file_list); | 1196 | struct ib_ucm_context, file_list); |
| 1284 | up(&file->mutex); | 1197 | mutex_unlock(&file->file_mutex); |
| 1285 | 1198 | ||
| 1286 | mutex_lock(&ctx_id_mutex); | 1199 | mutex_lock(&ctx_id_mutex); |
| 1287 | idr_remove(&ctx_id_table, ctx->id); | 1200 | idr_remove(&ctx_id_table, ctx->id); |
| @@ -1291,9 +1204,9 @@ static int ib_ucm_close(struct inode *inode, struct file *filp) | |||
| 1291 | ib_ucm_cleanup_events(ctx); | 1204 | ib_ucm_cleanup_events(ctx); |
| 1292 | kfree(ctx); | 1205 | kfree(ctx); |
| 1293 | 1206 | ||
| 1294 | down(&file->mutex); | 1207 | mutex_lock(&file->file_mutex); |
| 1295 | } | 1208 | } |
| 1296 | up(&file->mutex); | 1209 | mutex_unlock(&file->file_mutex); |
| 1297 | kfree(file); | 1210 | kfree(file); |
| 1298 | return 0; | 1211 | return 0; |
| 1299 | } | 1212 | } |
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 3372d67ff139..bb9bee56a824 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h | |||
| @@ -132,7 +132,7 @@ struct ib_ucq_object { | |||
| 132 | u32 async_events_reported; | 132 | u32 async_events_reported; |
| 133 | }; | 133 | }; |
| 134 | 134 | ||
| 135 | extern struct mutex ib_uverbs_idr_mutex; | 135 | extern spinlock_t ib_uverbs_idr_lock; |
| 136 | extern struct idr ib_uverbs_pd_idr; | 136 | extern struct idr ib_uverbs_pd_idr; |
| 137 | extern struct idr ib_uverbs_mr_idr; | 137 | extern struct idr ib_uverbs_mr_idr; |
| 138 | extern struct idr ib_uverbs_mw_idr; | 138 | extern struct idr ib_uverbs_mw_idr; |
| @@ -141,6 +141,8 @@ extern struct idr ib_uverbs_cq_idr; | |||
| 141 | extern struct idr ib_uverbs_qp_idr; | 141 | extern struct idr ib_uverbs_qp_idr; |
| 142 | extern struct idr ib_uverbs_srq_idr; | 142 | extern struct idr ib_uverbs_srq_idr; |
| 143 | 143 | ||
| 144 | void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj); | ||
| 145 | |||
| 144 | struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, | 146 | struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, |
| 145 | int is_async, int *fd); | 147 | int is_async, int *fd); |
| 146 | void ib_uverbs_release_event_file(struct kref *ref); | 148 | void ib_uverbs_release_event_file(struct kref *ref); |
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 9f69bd48eb1b..76bf61e9b552 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c | |||
| @@ -50,6 +50,196 @@ | |||
| 50 | (udata)->outlen = (olen); \ | 50 | (udata)->outlen = (olen); \ |
| 51 | } while (0) | 51 | } while (0) |
| 52 | 52 | ||
| 53 | /* | ||
| 54 | * The ib_uobject locking scheme is as follows: | ||
| 55 | * | ||
| 56 | * - ib_uverbs_idr_lock protects the uverbs idrs themselves, so it | ||
| 57 | * needs to be held during all idr operations. When an object is | ||
| 58 | * looked up, a reference must be taken on the object's kref before | ||
| 59 | * dropping this lock. | ||
| 60 | * | ||
| 61 | * - Each object also has an rwsem. This rwsem must be held for | ||
| 62 | * reading while an operation that uses the object is performed. | ||
| 63 | * For example, while registering an MR, the associated PD's | ||
| 64 | * uobject.mutex must be held for reading. The rwsem must be held | ||
| 65 | * for writing while initializing or destroying an object. | ||
| 66 | * | ||
| 67 | * - In addition, each object has a "live" flag. If this flag is not | ||
| 68 | * set, then lookups of the object will fail even if it is found in | ||
| 69 | * the idr. This handles a reader that blocks and does not acquire | ||
| 70 | * the rwsem until after the object is destroyed. The destroy | ||
| 71 | * operation will set the live flag to 0 and then drop the rwsem; | ||
| 72 | * this will allow the reader to acquire the rwsem, see that the | ||
| 73 | * live flag is 0, and then drop the rwsem and its reference to | ||
| 74 | * object. The underlying storage will not be freed until the last | ||
| 75 | * reference to the object is dropped. | ||
| 76 | */ | ||
| 77 | |||
| 78 | static void init_uobj(struct ib_uobject *uobj, u64 user_handle, | ||
| 79 | struct ib_ucontext *context) | ||
| 80 | { | ||
| 81 | uobj->user_handle = user_handle; | ||
| 82 | uobj->context = context; | ||
| 83 | kref_init(&uobj->ref); | ||
| 84 | init_rwsem(&uobj->mutex); | ||
| 85 | uobj->live = 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | static void release_uobj(struct kref *kref) | ||
| 89 | { | ||
| 90 | kfree(container_of(kref, struct ib_uobject, ref)); | ||
| 91 | } | ||
| 92 | |||
| 93 | static void put_uobj(struct ib_uobject *uobj) | ||
| 94 | { | ||
| 95 | kref_put(&uobj->ref, release_uobj); | ||
| 96 | } | ||
| 97 | |||
| 98 | static void put_uobj_read(struct ib_uobject *uobj) | ||
| 99 | { | ||
| 100 | up_read(&uobj->mutex); | ||
| 101 | put_uobj(uobj); | ||
| 102 | } | ||
| 103 | |||
| 104 | static void put_uobj_write(struct ib_uobject *uobj) | ||
| 105 | { | ||
| 106 | up_write(&uobj->mutex); | ||
| 107 | put_uobj(uobj); | ||
| 108 | } | ||
| 109 | |||
| 110 | static int idr_add_uobj(struct idr *idr, struct ib_uobject *uobj) | ||
| 111 | { | ||
| 112 | int ret; | ||
| 113 | |||
| 114 | retry: | ||
| 115 | if (!idr_pre_get(idr, GFP_KERNEL)) | ||
| 116 | return -ENOMEM; | ||
| 117 | |||
| 118 | spin_lock(&ib_uverbs_idr_lock); | ||
| 119 | ret = idr_get_new(idr, uobj, &uobj->id); | ||
| 120 | spin_unlock(&ib_uverbs_idr_lock); | ||
| 121 | |||
| 122 | if (ret == -EAGAIN) | ||
| 123 | goto retry; | ||
| 124 | |||
| 125 | return ret; | ||
| 126 | } | ||
| 127 | |||
| 128 | void idr_remove_uobj(struct idr *idr, struct ib_uobject *uobj) | ||
| 129 | { | ||
| 130 | spin_lock(&ib_uverbs_idr_lock); | ||
| 131 | idr_remove(idr, uobj->id); | ||
| 132 | spin_unlock(&ib_uverbs_idr_lock); | ||
| 133 | } | ||
| 134 | |||
| 135 | static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id, | ||
| 136 | struct ib_ucontext *context) | ||
| 137 | { | ||
| 138 | struct ib_uobject *uobj; | ||
| 139 | |||
| 140 | spin_lock(&ib_uverbs_idr_lock); | ||
| 141 | uobj = idr_find(idr, id); | ||
| 142 | if (uobj) | ||
| 143 | kref_get(&uobj->ref); | ||
| 144 | spin_unlock(&ib_uverbs_idr_lock); | ||
| 145 | |||
| 146 | return uobj; | ||
| 147 | } | ||
| 148 | |||
| 149 | static struct ib_uobject *idr_read_uobj(struct idr *idr, int id, | ||
| 150 | struct ib_ucontext *context) | ||
| 151 | { | ||
| 152 | struct ib_uobject *uobj; | ||
| 153 | |||
| 154 | uobj = __idr_get_uobj(idr, id, context); | ||
| 155 | if (!uobj) | ||
| 156 | return NULL; | ||
| 157 | |||
| 158 | down_read(&uobj->mutex); | ||
| 159 | if (!uobj->live) { | ||
| 160 | put_uobj_read(uobj); | ||
| 161 | return NULL; | ||
| 162 | } | ||
| 163 | |||
| 164 | return uobj; | ||
| 165 | } | ||
| 166 | |||
| 167 | static struct ib_uobject *idr_write_uobj(struct idr *idr, int id, | ||
| 168 | struct ib_ucontext *context) | ||
| 169 | { | ||
| 170 | struct ib_uobject *uobj; | ||
| 171 | |||
| 172 | uobj = __idr_get_uobj(idr, id, context); | ||
| 173 | if (!uobj) | ||
| 174 | return NULL; | ||
| 175 | |||
| 176 | down_write(&uobj->mutex); | ||
| 177 | if (!uobj->live) { | ||
| 178 | put_uobj_write(uobj); | ||
| 179 | return NULL; | ||
| 180 | } | ||
| 181 | |||
| 182 | return uobj; | ||
| 183 | } | ||
| 184 | |||
| 185 | static void *idr_read_obj(struct idr *idr, int id, struct ib_ucontext *context) | ||
| 186 | { | ||
| 187 | struct ib_uobject *uobj; | ||
| 188 | |||
| 189 | uobj = idr_read_uobj(idr, id, context); | ||
| 190 | return uobj ? uobj->object : NULL; | ||
| 191 | } | ||
| 192 | |||
| 193 | static struct ib_pd *idr_read_pd(int pd_handle, struct ib_ucontext *context) | ||
| 194 | { | ||
| 195 | return idr_read_obj(&ib_uverbs_pd_idr, pd_handle, context); | ||
| 196 | } | ||
| 197 | |||
| 198 | static void put_pd_read(struct ib_pd *pd) | ||
| 199 | { | ||
| 200 | put_uobj_read(pd->uobject); | ||
| 201 | } | ||
| 202 | |||
| 203 | static struct ib_cq *idr_read_cq(int cq_handle, struct ib_ucontext *context) | ||
| 204 | { | ||
| 205 | return idr_read_obj(&ib_uverbs_cq_idr, cq_handle, context); | ||
| 206 | } | ||
| 207 | |||
| 208 | static void put_cq_read(struct ib_cq *cq) | ||
| 209 | { | ||
| 210 | put_uobj_read(cq->uobject); | ||
| 211 | } | ||
| 212 | |||
| 213 | static struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context) | ||
| 214 | { | ||
| 215 | return idr_read_obj(&ib_uverbs_ah_idr, ah_handle, context); | ||
| 216 | } | ||
| 217 | |||
| 218 | static void put_ah_read(struct ib_ah *ah) | ||
| 219 | { | ||
| 220 | put_uobj_read(ah->uobject); | ||
| 221 | } | ||
| 222 | |||
| 223 | static struct ib_qp *idr_read_qp(int qp_handle, struct ib_ucontext *context) | ||
| 224 | { | ||
| 225 | return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context); | ||
| 226 | } | ||
| 227 | |||
| 228 | static void put_qp_read(struct ib_qp *qp) | ||
| 229 | { | ||
| 230 | put_uobj_read(qp->uobject); | ||
| 231 | } | ||
| 232 | |||
| 233 | static struct ib_srq *idr_read_srq(int srq_handle, struct ib_ucontext *context) | ||
| 234 | { | ||
| 235 | return idr_read_obj(&ib_uverbs_srq_idr, srq_handle, context); | ||
| 236 | } | ||
| 237 | |||
| 238 | static void put_srq_read(struct ib_srq *srq) | ||
| 239 | { | ||
| 240 | put_uobj_read(srq->uobject); | ||
| 241 | } | ||
| 242 | |||
| 53 | ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, | 243 | ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, |
| 54 | const char __user *buf, | 244 | const char __user *buf, |
| 55 | int in_len, int out_len) | 245 | int in_len, int out_len) |
| @@ -80,8 +270,10 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, | |||
| 80 | in_len - sizeof cmd, out_len - sizeof resp); | 270 | in_len - sizeof cmd, out_len - sizeof resp); |
| 81 | 271 | ||
| 82 | ucontext = ibdev->alloc_ucontext(ibdev, &udata); | 272 | ucontext = ibdev->alloc_ucontext(ibdev, &udata); |
| 83 | if (IS_ERR(ucontext)) | 273 | if (IS_ERR(ucontext)) { |
| 84 | return PTR_ERR(file->ucontext); | 274 | ret = PTR_ERR(file->ucontext); |
| 275 | goto err; | ||
| 276 | } | ||
| 85 | 277 | ||
| 86 | ucontext->device = ibdev; | 278 | ucontext->device = ibdev; |
| 87 | INIT_LIST_HEAD(&ucontext->pd_list); | 279 | INIT_LIST_HEAD(&ucontext->pd_list); |
| @@ -278,7 +470,8 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, | |||
| 278 | if (!uobj) | 470 | if (!uobj) |
| 279 | return -ENOMEM; | 471 | return -ENOMEM; |
| 280 | 472 | ||
| 281 | uobj->context = file->ucontext; | 473 | init_uobj(uobj, 0, file->ucontext); |
| 474 | down_write(&uobj->mutex); | ||
| 282 | 475 | ||
| 283 | pd = file->device->ib_dev->alloc_pd(file->device->ib_dev, | 476 | pd = file->device->ib_dev->alloc_pd(file->device->ib_dev, |
| 284 | file->ucontext, &udata); | 477 | file->ucontext, &udata); |
| @@ -291,20 +484,10 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, | |||
| 291 | pd->uobject = uobj; | 484 | pd->uobject = uobj; |
| 292 | atomic_set(&pd->usecnt, 0); | 485 | atomic_set(&pd->usecnt, 0); |
| 293 | 486 | ||
| 294 | mutex_lock(&ib_uverbs_idr_mutex); | 487 | uobj->object = pd; |
| 295 | 488 | ret = idr_add_uobj(&ib_uverbs_pd_idr, uobj); | |
| 296 | retry: | ||
| 297 | if (!idr_pre_get(&ib_uverbs_pd_idr, GFP_KERNEL)) { | ||
| 298 | ret = -ENOMEM; | ||
| 299 | goto err_up; | ||
| 300 | } | ||
| 301 | |||
| 302 | ret = idr_get_new(&ib_uverbs_pd_idr, pd, &uobj->id); | ||
| 303 | |||
| 304 | if (ret == -EAGAIN) | ||
| 305 | goto retry; | ||
| 306 | if (ret) | 489 | if (ret) |
| 307 | goto err_up; | 490 | goto err_idr; |
| 308 | 491 | ||
| 309 | memset(&resp, 0, sizeof resp); | 492 | memset(&resp, 0, sizeof resp); |
| 310 | resp.pd_handle = uobj->id; | 493 | resp.pd_handle = uobj->id; |
| @@ -312,26 +495,27 @@ retry: | |||
| 312 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 495 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
| 313 | &resp, sizeof resp)) { | 496 | &resp, sizeof resp)) { |
| 314 | ret = -EFAULT; | 497 | ret = -EFAULT; |
| 315 | goto err_idr; | 498 | goto err_copy; |
| 316 | } | 499 | } |
| 317 | 500 | ||
| 318 | mutex_lock(&file->mutex); | 501 | mutex_lock(&file->mutex); |
| 319 | list_add_tail(&uobj->list, &file->ucontext->pd_list); | 502 | list_add_tail(&uobj->list, &file->ucontext->pd_list); |
| 320 | mutex_unlock(&file->mutex); | 503 | mutex_unlock(&file->mutex); |
| 321 | 504 | ||
| 322 | mutex_unlock(&ib_uverbs_idr_mutex); | 505 | uobj->live = 1; |
| 506 | |||
| 507 | up_write(&uobj->mutex); | ||
| 323 | 508 | ||
| 324 | return in_len; | 509 | return in_len; |
| 325 | 510 | ||
| 326 | err_idr: | 511 | err_copy: |
| 327 | idr_remove(&ib_uverbs_pd_idr, uobj->id); | 512 | idr_remove_uobj(&ib_uverbs_pd_idr, uobj); |
| 328 | 513 | ||
| 329 | err_up: | 514 | err_idr: |
| 330 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 331 | ib_dealloc_pd(pd); | 515 | ib_dealloc_pd(pd); |
| 332 | 516 | ||
| 333 | err: | 517 | err: |
| 334 | kfree(uobj); | 518 | put_uobj_write(uobj); |
| 335 | return ret; | 519 | return ret; |
| 336 | } | 520 | } |
| 337 | 521 | ||
| @@ -340,37 +524,34 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file, | |||
| 340 | int in_len, int out_len) | 524 | int in_len, int out_len) |
| 341 | { | 525 | { |
| 342 | struct ib_uverbs_dealloc_pd cmd; | 526 | struct ib_uverbs_dealloc_pd cmd; |
| 343 | struct ib_pd *pd; | ||
| 344 | struct ib_uobject *uobj; | 527 | struct ib_uobject *uobj; |
| 345 | int ret = -EINVAL; | 528 | int ret; |
| 346 | 529 | ||
| 347 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 530 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| 348 | return -EFAULT; | 531 | return -EFAULT; |
| 349 | 532 | ||
| 350 | mutex_lock(&ib_uverbs_idr_mutex); | 533 | uobj = idr_write_uobj(&ib_uverbs_pd_idr, cmd.pd_handle, file->ucontext); |
| 534 | if (!uobj) | ||
| 535 | return -EINVAL; | ||
| 351 | 536 | ||
| 352 | pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); | 537 | ret = ib_dealloc_pd(uobj->object); |
| 353 | if (!pd || pd->uobject->context != file->ucontext) | 538 | if (!ret) |
| 354 | goto out; | 539 | uobj->live = 0; |
| 355 | 540 | ||
| 356 | uobj = pd->uobject; | 541 | put_uobj_write(uobj); |
| 357 | 542 | ||
| 358 | ret = ib_dealloc_pd(pd); | ||
| 359 | if (ret) | 543 | if (ret) |
| 360 | goto out; | 544 | return ret; |
| 361 | 545 | ||
| 362 | idr_remove(&ib_uverbs_pd_idr, cmd.pd_handle); | 546 | idr_remove_uobj(&ib_uverbs_pd_idr, uobj); |
| 363 | 547 | ||
| 364 | mutex_lock(&file->mutex); | 548 | mutex_lock(&file->mutex); |
| 365 | list_del(&uobj->list); | 549 | list_del(&uobj->list); |
| 366 | mutex_unlock(&file->mutex); | 550 | mutex_unlock(&file->mutex); |
| 367 | 551 | ||
| 368 | kfree(uobj); | 552 | put_uobj(uobj); |
| 369 | |||
| 370 | out: | ||
| 371 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 372 | 553 | ||
| 373 | return ret ? ret : in_len; | 554 | return in_len; |
| 374 | } | 555 | } |
| 375 | 556 | ||
| 376 | ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, | 557 | ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, |
| @@ -410,7 +591,8 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, | |||
| 410 | if (!obj) | 591 | if (!obj) |
| 411 | return -ENOMEM; | 592 | return -ENOMEM; |
| 412 | 593 | ||
| 413 | obj->uobject.context = file->ucontext; | 594 | init_uobj(&obj->uobject, 0, file->ucontext); |
| 595 | down_write(&obj->uobject.mutex); | ||
| 414 | 596 | ||
| 415 | /* | 597 | /* |
| 416 | * We ask for writable memory if any access flags other than | 598 | * We ask for writable memory if any access flags other than |
| @@ -427,23 +609,14 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, | |||
| 427 | 609 | ||
| 428 | obj->umem.virt_base = cmd.hca_va; | 610 | obj->umem.virt_base = cmd.hca_va; |
| 429 | 611 | ||
| 430 | mutex_lock(&ib_uverbs_idr_mutex); | 612 | pd = idr_read_pd(cmd.pd_handle, file->ucontext); |
| 431 | 613 | if (!pd) | |
| 432 | pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); | 614 | goto err_release; |
| 433 | if (!pd || pd->uobject->context != file->ucontext) { | ||
| 434 | ret = -EINVAL; | ||
| 435 | goto err_up; | ||
| 436 | } | ||
| 437 | |||
| 438 | if (!pd->device->reg_user_mr) { | ||
| 439 | ret = -ENOSYS; | ||
| 440 | goto err_up; | ||
| 441 | } | ||
| 442 | 615 | ||
| 443 | mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata); | 616 | mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata); |
| 444 | if (IS_ERR(mr)) { | 617 | if (IS_ERR(mr)) { |
| 445 | ret = PTR_ERR(mr); | 618 | ret = PTR_ERR(mr); |
| 446 | goto err_up; | 619 | goto err_put; |
| 447 | } | 620 | } |
| 448 | 621 | ||
| 449 | mr->device = pd->device; | 622 | mr->device = pd->device; |
| @@ -452,53 +625,48 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, | |||
| 452 | atomic_inc(&pd->usecnt); | 625 | atomic_inc(&pd->usecnt); |
| 453 | atomic_set(&mr->usecnt, 0); | 626 | atomic_set(&mr->usecnt, 0); |
| 454 | 627 | ||
| 455 | memset(&resp, 0, sizeof resp); | 628 | obj->uobject.object = mr; |
| 456 | resp.lkey = mr->lkey; | 629 | ret = idr_add_uobj(&ib_uverbs_mr_idr, &obj->uobject); |
| 457 | resp.rkey = mr->rkey; | ||
| 458 | |||
| 459 | retry: | ||
| 460 | if (!idr_pre_get(&ib_uverbs_mr_idr, GFP_KERNEL)) { | ||
| 461 | ret = -ENOMEM; | ||
| 462 | goto err_unreg; | ||
| 463 | } | ||
| 464 | |||
| 465 | ret = idr_get_new(&ib_uverbs_mr_idr, mr, &obj->uobject.id); | ||
| 466 | |||
| 467 | if (ret == -EAGAIN) | ||
| 468 | goto retry; | ||
| 469 | if (ret) | 630 | if (ret) |
| 470 | goto err_unreg; | 631 | goto err_unreg; |
| 471 | 632 | ||
| 633 | memset(&resp, 0, sizeof resp); | ||
| 634 | resp.lkey = mr->lkey; | ||
| 635 | resp.rkey = mr->rkey; | ||
| 472 | resp.mr_handle = obj->uobject.id; | 636 | resp.mr_handle = obj->uobject.id; |
| 473 | 637 | ||
| 474 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 638 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
| 475 | &resp, sizeof resp)) { | 639 | &resp, sizeof resp)) { |
| 476 | ret = -EFAULT; | 640 | ret = -EFAULT; |
| 477 | goto err_idr; | 641 | goto err_copy; |
| 478 | } | 642 | } |
| 479 | 643 | ||
| 644 | put_pd_read(pd); | ||
| 645 | |||
| 480 | mutex_lock(&file->mutex); | 646 | mutex_lock(&file->mutex); |
| 481 | list_add_tail(&obj->uobject.list, &file->ucontext->mr_list); | 647 | list_add_tail(&obj->uobject.list, &file->ucontext->mr_list); |
| 482 | mutex_unlock(&file->mutex); | 648 | mutex_unlock(&file->mutex); |
| 483 | 649 | ||
| 484 | mutex_unlock(&ib_uverbs_idr_mutex); | 650 | obj->uobject.live = 1; |
| 651 | |||
| 652 | up_write(&obj->uobject.mutex); | ||
| 485 | 653 | ||
| 486 | return in_len; | 654 | return in_len; |
| 487 | 655 | ||
| 488 | err_idr: | 656 | err_copy: |
| 489 | idr_remove(&ib_uverbs_mr_idr, obj->uobject.id); | 657 | idr_remove_uobj(&ib_uverbs_mr_idr, &obj->uobject); |
| 490 | 658 | ||
| 491 | err_unreg: | 659 | err_unreg: |
| 492 | ib_dereg_mr(mr); | 660 | ib_dereg_mr(mr); |
| 493 | atomic_dec(&pd->usecnt); | ||
| 494 | 661 | ||
| 495 | err_up: | 662 | err_put: |
| 496 | mutex_unlock(&ib_uverbs_idr_mutex); | 663 | put_pd_read(pd); |
| 497 | 664 | ||
| 665 | err_release: | ||
| 498 | ib_umem_release(file->device->ib_dev, &obj->umem); | 666 | ib_umem_release(file->device->ib_dev, &obj->umem); |
| 499 | 667 | ||
| 500 | err_free: | 668 | err_free: |
| 501 | kfree(obj); | 669 | put_uobj_write(&obj->uobject); |
| 502 | return ret; | 670 | return ret; |
| 503 | } | 671 | } |
| 504 | 672 | ||
| @@ -508,37 +676,40 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, | |||
| 508 | { | 676 | { |
| 509 | struct ib_uverbs_dereg_mr cmd; | 677 | struct ib_uverbs_dereg_mr cmd; |
| 510 | struct ib_mr *mr; | 678 | struct ib_mr *mr; |
| 679 | struct ib_uobject *uobj; | ||
| 511 | struct ib_umem_object *memobj; | 680 | struct ib_umem_object *memobj; |
| 512 | int ret = -EINVAL; | 681 | int ret = -EINVAL; |
| 513 | 682 | ||
| 514 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 683 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| 515 | return -EFAULT; | 684 | return -EFAULT; |
| 516 | 685 | ||
| 517 | mutex_lock(&ib_uverbs_idr_mutex); | 686 | uobj = idr_write_uobj(&ib_uverbs_mr_idr, cmd.mr_handle, file->ucontext); |
| 518 | 687 | if (!uobj) | |
| 519 | mr = idr_find(&ib_uverbs_mr_idr, cmd.mr_handle); | 688 | return -EINVAL; |
| 520 | if (!mr || mr->uobject->context != file->ucontext) | ||
| 521 | goto out; | ||
| 522 | 689 | ||
| 523 | memobj = container_of(mr->uobject, struct ib_umem_object, uobject); | 690 | memobj = container_of(uobj, struct ib_umem_object, uobject); |
| 691 | mr = uobj->object; | ||
| 524 | 692 | ||
| 525 | ret = ib_dereg_mr(mr); | 693 | ret = ib_dereg_mr(mr); |
| 694 | if (!ret) | ||
| 695 | uobj->live = 0; | ||
| 696 | |||
| 697 | put_uobj_write(uobj); | ||
| 698 | |||
| 526 | if (ret) | 699 | if (ret) |
| 527 | goto out; | 700 | return ret; |
| 528 | 701 | ||
| 529 | idr_remove(&ib_uverbs_mr_idr, cmd.mr_handle); | 702 | idr_remove_uobj(&ib_uverbs_mr_idr, uobj); |
| 530 | 703 | ||
| 531 | mutex_lock(&file->mutex); | 704 | mutex_lock(&file->mutex); |
| 532 | list_del(&memobj->uobject.list); | 705 | list_del(&uobj->list); |
| 533 | mutex_unlock(&file->mutex); | 706 | mutex_unlock(&file->mutex); |
| 534 | 707 | ||
| 535 | ib_umem_release(file->device->ib_dev, &memobj->umem); | 708 | ib_umem_release(file->device->ib_dev, &memobj->umem); |
| 536 | kfree(memobj); | ||
| 537 | 709 | ||
| 538 | out: | 710 | put_uobj(uobj); |
| 539 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 540 | 711 | ||
| 541 | return ret ? ret : in_len; | 712 | return in_len; |
| 542 | } | 713 | } |
| 543 | 714 | ||
| 544 | ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, | 715 | ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, |
| @@ -577,7 +748,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, | |||
| 577 | struct ib_uverbs_create_cq cmd; | 748 | struct ib_uverbs_create_cq cmd; |
| 578 | struct ib_uverbs_create_cq_resp resp; | 749 | struct ib_uverbs_create_cq_resp resp; |
| 579 | struct ib_udata udata; | 750 | struct ib_udata udata; |
| 580 | struct ib_ucq_object *uobj; | 751 | struct ib_ucq_object *obj; |
| 581 | struct ib_uverbs_event_file *ev_file = NULL; | 752 | struct ib_uverbs_event_file *ev_file = NULL; |
| 582 | struct ib_cq *cq; | 753 | struct ib_cq *cq; |
| 583 | int ret; | 754 | int ret; |
| @@ -595,10 +766,13 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, | |||
| 595 | if (cmd.comp_vector >= file->device->num_comp_vectors) | 766 | if (cmd.comp_vector >= file->device->num_comp_vectors) |
| 596 | return -EINVAL; | 767 | return -EINVAL; |
| 597 | 768 | ||
| 598 | uobj = kmalloc(sizeof *uobj, GFP_KERNEL); | 769 | obj = kmalloc(sizeof *obj, GFP_KERNEL); |
| 599 | if (!uobj) | 770 | if (!obj) |
| 600 | return -ENOMEM; | 771 | return -ENOMEM; |
| 601 | 772 | ||
| 773 | init_uobj(&obj->uobject, cmd.user_handle, file->ucontext); | ||
| 774 | down_write(&obj->uobject.mutex); | ||
| 775 | |||
| 602 | if (cmd.comp_channel >= 0) { | 776 | if (cmd.comp_channel >= 0) { |
| 603 | ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel); | 777 | ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel); |
| 604 | if (!ev_file) { | 778 | if (!ev_file) { |
| @@ -607,72 +781,64 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, | |||
| 607 | } | 781 | } |
| 608 | } | 782 | } |
| 609 | 783 | ||
| 610 | uobj->uobject.user_handle = cmd.user_handle; | 784 | obj->uverbs_file = file; |
| 611 | uobj->uobject.context = file->ucontext; | 785 | obj->comp_events_reported = 0; |
| 612 | uobj->uverbs_file = file; | 786 | obj->async_events_reported = 0; |
| 613 | uobj->comp_events_reported = 0; | 787 | INIT_LIST_HEAD(&obj->comp_list); |
| 614 | uobj->async_events_reported = 0; | 788 | INIT_LIST_HEAD(&obj->async_list); |
| 615 | INIT_LIST_HEAD(&uobj->comp_list); | ||
| 616 | INIT_LIST_HEAD(&uobj->async_list); | ||
| 617 | 789 | ||
| 618 | cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe, | 790 | cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe, |
| 619 | file->ucontext, &udata); | 791 | file->ucontext, &udata); |
| 620 | if (IS_ERR(cq)) { | 792 | if (IS_ERR(cq)) { |
| 621 | ret = PTR_ERR(cq); | 793 | ret = PTR_ERR(cq); |
| 622 | goto err; | 794 | goto err_file; |
| 623 | } | 795 | } |
| 624 | 796 | ||
| 625 | cq->device = file->device->ib_dev; | 797 | cq->device = file->device->ib_dev; |
| 626 | cq->uobject = &uobj->uobject; | 798 | cq->uobject = &obj->uobject; |
| 627 | cq->comp_handler = ib_uverbs_comp_handler; | 799 | cq->comp_handler = ib_uverbs_comp_handler; |
| 628 | cq->event_handler = ib_uverbs_cq_event_handler; | 800 | cq->event_handler = ib_uverbs_cq_event_handler; |
| 629 | cq->cq_context = ev_file; | 801 | cq->cq_context = ev_file; |
| 630 | atomic_set(&cq->usecnt, 0); | 802 | atomic_set(&cq->usecnt, 0); |
| 631 | 803 | ||
| 632 | mutex_lock(&ib_uverbs_idr_mutex); | 804 | obj->uobject.object = cq; |
| 633 | 805 | ret = idr_add_uobj(&ib_uverbs_cq_idr, &obj->uobject); | |
| 634 | retry: | ||
| 635 | if (!idr_pre_get(&ib_uverbs_cq_idr, GFP_KERNEL)) { | ||
| 636 | ret = -ENOMEM; | ||
| 637 | goto err_up; | ||
| 638 | } | ||
| 639 | |||
| 640 | ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->uobject.id); | ||
| 641 | |||
| 642 | if (ret == -EAGAIN) | ||
| 643 | goto retry; | ||
| 644 | if (ret) | 806 | if (ret) |
| 645 | goto err_up; | 807 | goto err_free; |
| 646 | 808 | ||
| 647 | memset(&resp, 0, sizeof resp); | 809 | memset(&resp, 0, sizeof resp); |
| 648 | resp.cq_handle = uobj->uobject.id; | 810 | resp.cq_handle = obj->uobject.id; |
| 649 | resp.cqe = cq->cqe; | 811 | resp.cqe = cq->cqe; |
| 650 | 812 | ||
| 651 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 813 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
| 652 | &resp, sizeof resp)) { | 814 | &resp, sizeof resp)) { |
| 653 | ret = -EFAULT; | 815 | ret = -EFAULT; |
| 654 | goto err_idr; | 816 | goto err_copy; |
| 655 | } | 817 | } |
| 656 | 818 | ||
| 657 | mutex_lock(&file->mutex); | 819 | mutex_lock(&file->mutex); |
| 658 | list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list); | 820 | list_add_tail(&obj->uobject.list, &file->ucontext->cq_list); |
| 659 | mutex_unlock(&file->mutex); | 821 | mutex_unlock(&file->mutex); |
| 660 | 822 | ||
| 661 | mutex_unlock(&ib_uverbs_idr_mutex); | 823 | obj->uobject.live = 1; |
| 824 | |||
| 825 | up_write(&obj->uobject.mutex); | ||
| 662 | 826 | ||
| 663 | return in_len; | 827 | return in_len; |
| 664 | 828 | ||
| 665 | err_idr: | 829 | err_copy: |
| 666 | idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id); | 830 | idr_remove_uobj(&ib_uverbs_cq_idr, &obj->uobject); |
| 831 | |||
| 667 | 832 | ||
| 668 | err_up: | 833 | err_free: |
| 669 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 670 | ib_destroy_cq(cq); | 834 | ib_destroy_cq(cq); |
| 671 | 835 | ||
| 672 | err: | 836 | err_file: |
| 673 | if (ev_file) | 837 | if (ev_file) |
| 674 | ib_uverbs_release_ucq(file, ev_file, uobj); | 838 | ib_uverbs_release_ucq(file, ev_file, obj); |
| 675 | kfree(uobj); | 839 | |
| 840 | err: | ||
| 841 | put_uobj_write(&obj->uobject); | ||
| 676 | return ret; | 842 | return ret; |
| 677 | } | 843 | } |
| 678 | 844 | ||
| @@ -693,11 +859,9 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file, | |||
| 693 | (unsigned long) cmd.response + sizeof resp, | 859 | (unsigned long) cmd.response + sizeof resp, |
| 694 | in_len - sizeof cmd, out_len - sizeof resp); | 860 | in_len - sizeof cmd, out_len - sizeof resp); |
| 695 | 861 | ||
| 696 | mutex_lock(&ib_uverbs_idr_mutex); | 862 | cq = idr_read_cq(cmd.cq_handle, file->ucontext); |
| 697 | 863 | if (!cq) | |
| 698 | cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); | 864 | return -EINVAL; |
| 699 | if (!cq || cq->uobject->context != file->ucontext || !cq->device->resize_cq) | ||
| 700 | goto out; | ||
| 701 | 865 | ||
| 702 | ret = cq->device->resize_cq(cq, cmd.cqe, &udata); | 866 | ret = cq->device->resize_cq(cq, cmd.cqe, &udata); |
| 703 | if (ret) | 867 | if (ret) |
| @@ -711,7 +875,7 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file, | |||
| 711 | ret = -EFAULT; | 875 | ret = -EFAULT; |
| 712 | 876 | ||
| 713 | out: | 877 | out: |
| 714 | mutex_unlock(&ib_uverbs_idr_mutex); | 878 | put_cq_read(cq); |
| 715 | 879 | ||
| 716 | return ret ? ret : in_len; | 880 | return ret ? ret : in_len; |
| 717 | } | 881 | } |
| @@ -722,6 +886,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, | |||
| 722 | { | 886 | { |
| 723 | struct ib_uverbs_poll_cq cmd; | 887 | struct ib_uverbs_poll_cq cmd; |
| 724 | struct ib_uverbs_poll_cq_resp *resp; | 888 | struct ib_uverbs_poll_cq_resp *resp; |
| 889 | struct ib_uobject *uobj; | ||
| 725 | struct ib_cq *cq; | 890 | struct ib_cq *cq; |
| 726 | struct ib_wc *wc; | 891 | struct ib_wc *wc; |
| 727 | int ret = 0; | 892 | int ret = 0; |
| @@ -742,15 +907,17 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, | |||
| 742 | goto out_wc; | 907 | goto out_wc; |
| 743 | } | 908 | } |
| 744 | 909 | ||
| 745 | mutex_lock(&ib_uverbs_idr_mutex); | 910 | uobj = idr_read_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext); |
| 746 | cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); | 911 | if (!uobj) { |
| 747 | if (!cq || cq->uobject->context != file->ucontext) { | ||
| 748 | ret = -EINVAL; | 912 | ret = -EINVAL; |
| 749 | goto out; | 913 | goto out; |
| 750 | } | 914 | } |
| 915 | cq = uobj->object; | ||
| 751 | 916 | ||
| 752 | resp->count = ib_poll_cq(cq, cmd.ne, wc); | 917 | resp->count = ib_poll_cq(cq, cmd.ne, wc); |
| 753 | 918 | ||
| 919 | put_uobj_read(uobj); | ||
| 920 | |||
| 754 | for (i = 0; i < resp->count; i++) { | 921 | for (i = 0; i < resp->count; i++) { |
| 755 | resp->wc[i].wr_id = wc[i].wr_id; | 922 | resp->wc[i].wr_id = wc[i].wr_id; |
| 756 | resp->wc[i].status = wc[i].status; | 923 | resp->wc[i].status = wc[i].status; |
| @@ -772,7 +939,6 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, | |||
| 772 | ret = -EFAULT; | 939 | ret = -EFAULT; |
| 773 | 940 | ||
| 774 | out: | 941 | out: |
| 775 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 776 | kfree(resp); | 942 | kfree(resp); |
| 777 | 943 | ||
| 778 | out_wc: | 944 | out_wc: |
| @@ -785,22 +951,23 @@ ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file, | |||
| 785 | int out_len) | 951 | int out_len) |
| 786 | { | 952 | { |
| 787 | struct ib_uverbs_req_notify_cq cmd; | 953 | struct ib_uverbs_req_notify_cq cmd; |
| 954 | struct ib_uobject *uobj; | ||
| 788 | struct ib_cq *cq; | 955 | struct ib_cq *cq; |
| 789 | int ret = -EINVAL; | ||
| 790 | 956 | ||
| 791 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 957 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| 792 | return -EFAULT; | 958 | return -EFAULT; |
| 793 | 959 | ||
| 794 | mutex_lock(&ib_uverbs_idr_mutex); | 960 | uobj = idr_read_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext); |
| 795 | cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); | 961 | if (!uobj) |
| 796 | if (cq && cq->uobject->context == file->ucontext) { | 962 | return -EINVAL; |
| 797 | ib_req_notify_cq(cq, cmd.solicited_only ? | 963 | cq = uobj->object; |
| 798 | IB_CQ_SOLICITED : IB_CQ_NEXT_COMP); | ||
| 799 | ret = in_len; | ||
| 800 | } | ||
| 801 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 802 | 964 | ||
| 803 | return ret; | 965 | ib_req_notify_cq(cq, cmd.solicited_only ? |
| 966 | IB_CQ_SOLICITED : IB_CQ_NEXT_COMP); | ||
| 967 | |||
| 968 | put_uobj_read(uobj); | ||
| 969 | |||
| 970 | return in_len; | ||
| 804 | } | 971 | } |
| 805 | 972 | ||
| 806 | ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, | 973 | ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, |
| @@ -809,52 +976,50 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, | |||
| 809 | { | 976 | { |
| 810 | struct ib_uverbs_destroy_cq cmd; | 977 | struct ib_uverbs_destroy_cq cmd; |
| 811 | struct ib_uverbs_destroy_cq_resp resp; | 978 | struct ib_uverbs_destroy_cq_resp resp; |
| 979 | struct ib_uobject *uobj; | ||
| 812 | struct ib_cq *cq; | 980 | struct ib_cq *cq; |
| 813 | struct ib_ucq_object *uobj; | 981 | struct ib_ucq_object *obj; |
| 814 | struct ib_uverbs_event_file *ev_file; | 982 | struct ib_uverbs_event_file *ev_file; |
| 815 | u64 user_handle; | ||
| 816 | int ret = -EINVAL; | 983 | int ret = -EINVAL; |
| 817 | 984 | ||
| 818 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 985 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| 819 | return -EFAULT; | 986 | return -EFAULT; |
| 820 | 987 | ||
| 821 | memset(&resp, 0, sizeof resp); | 988 | uobj = idr_write_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext); |
| 822 | 989 | if (!uobj) | |
| 823 | mutex_lock(&ib_uverbs_idr_mutex); | 990 | return -EINVAL; |
| 991 | cq = uobj->object; | ||
| 992 | ev_file = cq->cq_context; | ||
| 993 | obj = container_of(cq->uobject, struct ib_ucq_object, uobject); | ||
| 824 | 994 | ||
| 825 | cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); | 995 | ret = ib_destroy_cq(cq); |
| 826 | if (!cq || cq->uobject->context != file->ucontext) | 996 | if (!ret) |
| 827 | goto out; | 997 | uobj->live = 0; |
| 828 | 998 | ||
| 829 | user_handle = cq->uobject->user_handle; | 999 | put_uobj_write(uobj); |
| 830 | uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); | ||
| 831 | ev_file = cq->cq_context; | ||
| 832 | 1000 | ||
| 833 | ret = ib_destroy_cq(cq); | ||
| 834 | if (ret) | 1001 | if (ret) |
| 835 | goto out; | 1002 | return ret; |
| 836 | 1003 | ||
| 837 | idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle); | 1004 | idr_remove_uobj(&ib_uverbs_cq_idr, uobj); |
| 838 | 1005 | ||
| 839 | mutex_lock(&file->mutex); | 1006 | mutex_lock(&file->mutex); |
| 840 | list_del(&uobj->uobject.list); | 1007 | list_del(&uobj->list); |
| 841 | mutex_unlock(&file->mutex); | 1008 | mutex_unlock(&file->mutex); |
| 842 | 1009 | ||
| 843 | ib_uverbs_release_ucq(file, ev_file, uobj); | 1010 | ib_uverbs_release_ucq(file, ev_file, obj); |
| 844 | 1011 | ||
| 845 | resp.comp_events_reported = uobj->comp_events_reported; | 1012 | memset(&resp, 0, sizeof resp); |
| 846 | resp.async_events_reported = uobj->async_events_reported; | 1013 | resp.comp_events_reported = obj->comp_events_reported; |
| 1014 | resp.async_events_reported = obj->async_events_reported; | ||
| 847 | 1015 | ||
| 848 | kfree(uobj); | 1016 | put_uobj(uobj); |
| 849 | 1017 | ||
| 850 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 1018 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
| 851 | &resp, sizeof resp)) | 1019 | &resp, sizeof resp)) |
| 852 | ret = -EFAULT; | 1020 | return -EFAULT; |
| 853 | |||
| 854 | out: | ||
| 855 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 856 | 1021 | ||
| 857 | return ret ? ret : in_len; | 1022 | return in_len; |
| 858 | } | 1023 | } |
| 859 | 1024 | ||
| 860 | ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, | 1025 | ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, |
| @@ -864,7 +1029,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, | |||
| 864 | struct ib_uverbs_create_qp cmd; | 1029 | struct ib_uverbs_create_qp cmd; |
| 865 | struct ib_uverbs_create_qp_resp resp; | 1030 | struct ib_uverbs_create_qp_resp resp; |
| 866 | struct ib_udata udata; | 1031 | struct ib_udata udata; |
| 867 | struct ib_uqp_object *uobj; | 1032 | struct ib_uqp_object *obj; |
| 868 | struct ib_pd *pd; | 1033 | struct ib_pd *pd; |
| 869 | struct ib_cq *scq, *rcq; | 1034 | struct ib_cq *scq, *rcq; |
| 870 | struct ib_srq *srq; | 1035 | struct ib_srq *srq; |
| @@ -882,23 +1047,21 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, | |||
| 882 | (unsigned long) cmd.response + sizeof resp, | 1047 | (unsigned long) cmd.response + sizeof resp, |
| 883 | in_len - sizeof cmd, out_len - sizeof resp); | 1048 | in_len - sizeof cmd, out_len - sizeof resp); |
| 884 | 1049 | ||
| 885 | uobj = kmalloc(sizeof *uobj, GFP_KERNEL); | 1050 | obj = kmalloc(sizeof *obj, GFP_KERNEL); |
| 886 | if (!uobj) | 1051 | if (!obj) |
| 887 | return -ENOMEM; | 1052 | return -ENOMEM; |
| 888 | 1053 | ||
| 889 | mutex_lock(&ib_uverbs_idr_mutex); | 1054 | init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext); |
| 1055 | down_write(&obj->uevent.uobject.mutex); | ||
| 890 | 1056 | ||
| 891 | pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); | 1057 | pd = idr_read_pd(cmd.pd_handle, file->ucontext); |
| 892 | scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle); | 1058 | scq = idr_read_cq(cmd.send_cq_handle, file->ucontext); |
| 893 | rcq = idr_find(&ib_uverbs_cq_idr, cmd.recv_cq_handle); | 1059 | rcq = idr_read_cq(cmd.recv_cq_handle, file->ucontext); |
| 894 | srq = cmd.is_srq ? idr_find(&ib_uverbs_srq_idr, cmd.srq_handle) : NULL; | 1060 | srq = cmd.is_srq ? idr_read_srq(cmd.srq_handle, file->ucontext) : NULL; |
| 895 | 1061 | ||
| 896 | if (!pd || pd->uobject->context != file->ucontext || | 1062 | if (!pd || !scq || !rcq || (cmd.is_srq && !srq)) { |
| 897 | !scq || scq->uobject->context != file->ucontext || | ||
| 898 | !rcq || rcq->uobject->context != file->ucontext || | ||
| 899 | (cmd.is_srq && (!srq || srq->uobject->context != file->ucontext))) { | ||
| 900 | ret = -EINVAL; | 1063 | ret = -EINVAL; |
| 901 | goto err_up; | 1064 | goto err_put; |
| 902 | } | 1065 | } |
| 903 | 1066 | ||
| 904 | attr.event_handler = ib_uverbs_qp_event_handler; | 1067 | attr.event_handler = ib_uverbs_qp_event_handler; |
| @@ -915,16 +1078,14 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, | |||
| 915 | attr.cap.max_recv_sge = cmd.max_recv_sge; | 1078 | attr.cap.max_recv_sge = cmd.max_recv_sge; |
| 916 | attr.cap.max_inline_data = cmd.max_inline_data; | 1079 | attr.cap.max_inline_data = cmd.max_inline_data; |
| 917 | 1080 | ||
| 918 | uobj->uevent.uobject.user_handle = cmd.user_handle; | 1081 | obj->uevent.events_reported = 0; |
| 919 | uobj->uevent.uobject.context = file->ucontext; | 1082 | INIT_LIST_HEAD(&obj->uevent.event_list); |
| 920 | uobj->uevent.events_reported = 0; | 1083 | INIT_LIST_HEAD(&obj->mcast_list); |
| 921 | INIT_LIST_HEAD(&uobj->uevent.event_list); | ||
| 922 | INIT_LIST_HEAD(&uobj->mcast_list); | ||
| 923 | 1084 | ||
| 924 | qp = pd->device->create_qp(pd, &attr, &udata); | 1085 | qp = pd->device->create_qp(pd, &attr, &udata); |
| 925 | if (IS_ERR(qp)) { | 1086 | if (IS_ERR(qp)) { |
| 926 | ret = PTR_ERR(qp); | 1087 | ret = PTR_ERR(qp); |
| 927 | goto err_up; | 1088 | goto err_put; |
| 928 | } | 1089 | } |
| 929 | 1090 | ||
| 930 | qp->device = pd->device; | 1091 | qp->device = pd->device; |
| @@ -932,7 +1093,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, | |||
| 932 | qp->send_cq = attr.send_cq; | 1093 | qp->send_cq = attr.send_cq; |
| 933 | qp->recv_cq = attr.recv_cq; | 1094 | qp->recv_cq = attr.recv_cq; |
| 934 | qp->srq = attr.srq; | 1095 | qp->srq = attr.srq; |
| 935 | qp->uobject = &uobj->uevent.uobject; | 1096 | qp->uobject = &obj->uevent.uobject; |
| 936 | qp->event_handler = attr.event_handler; | 1097 | qp->event_handler = attr.event_handler; |
| 937 | qp->qp_context = attr.qp_context; | 1098 | qp->qp_context = attr.qp_context; |
| 938 | qp->qp_type = attr.qp_type; | 1099 | qp->qp_type = attr.qp_type; |
| @@ -942,23 +1103,14 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, | |||
| 942 | if (attr.srq) | 1103 | if (attr.srq) |
| 943 | atomic_inc(&attr.srq->usecnt); | 1104 | atomic_inc(&attr.srq->usecnt); |
| 944 | 1105 | ||
| 945 | memset(&resp, 0, sizeof resp); | 1106 | obj->uevent.uobject.object = qp; |
| 946 | resp.qpn = qp->qp_num; | 1107 | ret = idr_add_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject); |
| 947 | |||
| 948 | retry: | ||
| 949 | if (!idr_pre_get(&ib_uverbs_qp_idr, GFP_KERNEL)) { | ||
| 950 | ret = -ENOMEM; | ||
| 951 | goto err_destroy; | ||
| 952 | } | ||
| 953 | |||
| 954 | ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->uevent.uobject.id); | ||
| 955 | |||
| 956 | if (ret == -EAGAIN) | ||
| 957 | goto retry; | ||
| 958 | if (ret) | 1108 | if (ret) |
| 959 | goto err_destroy; | 1109 | goto err_destroy; |
| 960 | 1110 | ||
| 961 | resp.qp_handle = uobj->uevent.uobject.id; | 1111 | memset(&resp, 0, sizeof resp); |
| 1112 | resp.qpn = qp->qp_num; | ||
| 1113 | resp.qp_handle = obj->uevent.uobject.id; | ||
| 962 | resp.max_recv_sge = attr.cap.max_recv_sge; | 1114 | resp.max_recv_sge = attr.cap.max_recv_sge; |
| 963 | resp.max_send_sge = attr.cap.max_send_sge; | 1115 | resp.max_send_sge = attr.cap.max_send_sge; |
| 964 | resp.max_recv_wr = attr.cap.max_recv_wr; | 1116 | resp.max_recv_wr = attr.cap.max_recv_wr; |
| @@ -968,32 +1120,42 @@ retry: | |||
| 968 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 1120 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
| 969 | &resp, sizeof resp)) { | 1121 | &resp, sizeof resp)) { |
| 970 | ret = -EFAULT; | 1122 | ret = -EFAULT; |
| 971 | goto err_idr; | 1123 | goto err_copy; |
| 972 | } | 1124 | } |
| 973 | 1125 | ||
| 1126 | put_pd_read(pd); | ||
| 1127 | put_cq_read(scq); | ||
| 1128 | put_cq_read(rcq); | ||
| 1129 | if (srq) | ||
| 1130 | put_srq_read(srq); | ||
| 1131 | |||
| 974 | mutex_lock(&file->mutex); | 1132 | mutex_lock(&file->mutex); |
| 975 | list_add_tail(&uobj->uevent.uobject.list, &file->ucontext->qp_list); | 1133 | list_add_tail(&obj->uevent.uobject.list, &file->ucontext->qp_list); |
| 976 | mutex_unlock(&file->mutex); | 1134 | mutex_unlock(&file->mutex); |
| 977 | 1135 | ||
| 978 | mutex_unlock(&ib_uverbs_idr_mutex); | 1136 | obj->uevent.uobject.live = 1; |
| 1137 | |||
| 1138 | up_write(&obj->uevent.uobject.mutex); | ||
| 979 | 1139 | ||
| 980 | return in_len; | 1140 | return in_len; |
| 981 | 1141 | ||
| 982 | err_idr: | 1142 | err_copy: |
| 983 | idr_remove(&ib_uverbs_qp_idr, uobj->uevent.uobject.id); | 1143 | idr_remove_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject); |
| 984 | 1144 | ||
| 985 | err_destroy: | 1145 | err_destroy: |
| 986 | ib_destroy_qp(qp); | 1146 | ib_destroy_qp(qp); |
| 987 | atomic_dec(&pd->usecnt); | ||
| 988 | atomic_dec(&attr.send_cq->usecnt); | ||
| 989 | atomic_dec(&attr.recv_cq->usecnt); | ||
| 990 | if (attr.srq) | ||
| 991 | atomic_dec(&attr.srq->usecnt); | ||
| 992 | |||
| 993 | err_up: | ||
| 994 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 995 | 1147 | ||
| 996 | kfree(uobj); | 1148 | err_put: |
| 1149 | if (pd) | ||
| 1150 | put_pd_read(pd); | ||
| 1151 | if (scq) | ||
| 1152 | put_cq_read(scq); | ||
| 1153 | if (rcq) | ||
| 1154 | put_cq_read(rcq); | ||
| 1155 | if (srq) | ||
| 1156 | put_srq_read(srq); | ||
| 1157 | |||
| 1158 | put_uobj_write(&obj->uevent.uobject); | ||
| 997 | return ret; | 1159 | return ret; |
| 998 | } | 1160 | } |
| 999 | 1161 | ||
| @@ -1018,15 +1180,15 @@ ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file, | |||
| 1018 | goto out; | 1180 | goto out; |
| 1019 | } | 1181 | } |
| 1020 | 1182 | ||
| 1021 | mutex_lock(&ib_uverbs_idr_mutex); | 1183 | qp = idr_read_qp(cmd.qp_handle, file->ucontext); |
| 1022 | 1184 | if (!qp) { | |
| 1023 | qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); | ||
| 1024 | if (qp && qp->uobject->context == file->ucontext) | ||
| 1025 | ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr); | ||
| 1026 | else | ||
| 1027 | ret = -EINVAL; | 1185 | ret = -EINVAL; |
| 1186 | goto out; | ||
| 1187 | } | ||
| 1028 | 1188 | ||
| 1029 | mutex_unlock(&ib_uverbs_idr_mutex); | 1189 | ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr); |
| 1190 | |||
| 1191 | put_qp_read(qp); | ||
| 1030 | 1192 | ||
| 1031 | if (ret) | 1193 | if (ret) |
| 1032 | goto out; | 1194 | goto out; |
| @@ -1113,10 +1275,8 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file, | |||
| 1113 | if (!attr) | 1275 | if (!attr) |
| 1114 | return -ENOMEM; | 1276 | return -ENOMEM; |
| 1115 | 1277 | ||
| 1116 | mutex_lock(&ib_uverbs_idr_mutex); | 1278 | qp = idr_read_qp(cmd.qp_handle, file->ucontext); |
| 1117 | 1279 | if (!qp) { | |
| 1118 | qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); | ||
| 1119 | if (!qp || qp->uobject->context != file->ucontext) { | ||
| 1120 | ret = -EINVAL; | 1280 | ret = -EINVAL; |
| 1121 | goto out; | 1281 | goto out; |
| 1122 | } | 1282 | } |
| @@ -1168,13 +1328,15 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file, | |||
| 1168 | attr->alt_ah_attr.port_num = cmd.alt_dest.port_num; | 1328 | attr->alt_ah_attr.port_num = cmd.alt_dest.port_num; |
| 1169 | 1329 | ||
| 1170 | ret = ib_modify_qp(qp, attr, cmd.attr_mask); | 1330 | ret = ib_modify_qp(qp, attr, cmd.attr_mask); |
| 1331 | |||
| 1332 | put_qp_read(qp); | ||
| 1333 | |||
| 1171 | if (ret) | 1334 | if (ret) |
| 1172 | goto out; | 1335 | goto out; |
| 1173 | 1336 | ||
| 1174 | ret = in_len; | 1337 | ret = in_len; |
| 1175 | 1338 | ||
| 1176 | out: | 1339 | out: |
| 1177 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 1178 | kfree(attr); | 1340 | kfree(attr); |
| 1179 | 1341 | ||
| 1180 | return ret; | 1342 | return ret; |
| @@ -1186,8 +1348,9 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, | |||
| 1186 | { | 1348 | { |
| 1187 | struct ib_uverbs_destroy_qp cmd; | 1349 | struct ib_uverbs_destroy_qp cmd; |
| 1188 | struct ib_uverbs_destroy_qp_resp resp; | 1350 | struct ib_uverbs_destroy_qp_resp resp; |
| 1351 | struct ib_uobject *uobj; | ||
| 1189 | struct ib_qp *qp; | 1352 | struct ib_qp *qp; |
| 1190 | struct ib_uqp_object *uobj; | 1353 | struct ib_uqp_object *obj; |
| 1191 | int ret = -EINVAL; | 1354 | int ret = -EINVAL; |
| 1192 | 1355 | ||
| 1193 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 1356 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| @@ -1195,43 +1358,43 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, | |||
| 1195 | 1358 | ||
| 1196 | memset(&resp, 0, sizeof resp); | 1359 | memset(&resp, 0, sizeof resp); |
| 1197 | 1360 | ||
| 1198 | mutex_lock(&ib_uverbs_idr_mutex); | 1361 | uobj = idr_write_uobj(&ib_uverbs_qp_idr, cmd.qp_handle, file->ucontext); |
| 1199 | 1362 | if (!uobj) | |
| 1200 | qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); | 1363 | return -EINVAL; |
| 1201 | if (!qp || qp->uobject->context != file->ucontext) | 1364 | qp = uobj->object; |
| 1202 | goto out; | 1365 | obj = container_of(uobj, struct ib_uqp_object, uevent.uobject); |
| 1203 | |||
| 1204 | uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); | ||
| 1205 | 1366 | ||
| 1206 | if (!list_empty(&uobj->mcast_list)) { | 1367 | if (!list_empty(&obj->mcast_list)) { |
| 1207 | ret = -EBUSY; | 1368 | put_uobj_write(uobj); |
| 1208 | goto out; | 1369 | return -EBUSY; |
| 1209 | } | 1370 | } |
| 1210 | 1371 | ||
| 1211 | ret = ib_destroy_qp(qp); | 1372 | ret = ib_destroy_qp(qp); |
| 1373 | if (!ret) | ||
| 1374 | uobj->live = 0; | ||
| 1375 | |||
| 1376 | put_uobj_write(uobj); | ||
| 1377 | |||
| 1212 | if (ret) | 1378 | if (ret) |
| 1213 | goto out; | 1379 | return ret; |
| 1214 | 1380 | ||
| 1215 | idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle); | 1381 | idr_remove_uobj(&ib_uverbs_qp_idr, uobj); |
| 1216 | 1382 | ||
| 1217 | mutex_lock(&file->mutex); | 1383 | mutex_lock(&file->mutex); |
| 1218 | list_del(&uobj->uevent.uobject.list); | 1384 | list_del(&uobj->list); |
| 1219 | mutex_unlock(&file->mutex); | 1385 | mutex_unlock(&file->mutex); |
| 1220 | 1386 | ||
| 1221 | ib_uverbs_release_uevent(file, &uobj->uevent); | 1387 | ib_uverbs_release_uevent(file, &obj->uevent); |
| 1222 | 1388 | ||
| 1223 | resp.events_reported = uobj->uevent.events_reported; | 1389 | resp.events_reported = obj->uevent.events_reported; |
| 1224 | 1390 | ||
| 1225 | kfree(uobj); | 1391 | put_uobj(uobj); |
| 1226 | 1392 | ||
| 1227 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 1393 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
| 1228 | &resp, sizeof resp)) | 1394 | &resp, sizeof resp)) |
| 1229 | ret = -EFAULT; | 1395 | return -EFAULT; |
| 1230 | |||
| 1231 | out: | ||
| 1232 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 1233 | 1396 | ||
| 1234 | return ret ? ret : in_len; | 1397 | return in_len; |
| 1235 | } | 1398 | } |
| 1236 | 1399 | ||
| 1237 | ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, | 1400 | ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, |
| @@ -1244,6 +1407,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, | |||
| 1244 | struct ib_send_wr *wr = NULL, *last, *next, *bad_wr; | 1407 | struct ib_send_wr *wr = NULL, *last, *next, *bad_wr; |
| 1245 | struct ib_qp *qp; | 1408 | struct ib_qp *qp; |
| 1246 | int i, sg_ind; | 1409 | int i, sg_ind; |
| 1410 | int is_ud; | ||
| 1247 | ssize_t ret = -EINVAL; | 1411 | ssize_t ret = -EINVAL; |
| 1248 | 1412 | ||
| 1249 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 1413 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| @@ -1260,12 +1424,11 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, | |||
| 1260 | if (!user_wr) | 1424 | if (!user_wr) |
| 1261 | return -ENOMEM; | 1425 | return -ENOMEM; |
| 1262 | 1426 | ||
| 1263 | mutex_lock(&ib_uverbs_idr_mutex); | 1427 | qp = idr_read_qp(cmd.qp_handle, file->ucontext); |
| 1264 | 1428 | if (!qp) | |
| 1265 | qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); | ||
| 1266 | if (!qp || qp->uobject->context != file->ucontext) | ||
| 1267 | goto out; | 1429 | goto out; |
| 1268 | 1430 | ||
| 1431 | is_ud = qp->qp_type == IB_QPT_UD; | ||
| 1269 | sg_ind = 0; | 1432 | sg_ind = 0; |
| 1270 | last = NULL; | 1433 | last = NULL; |
| 1271 | for (i = 0; i < cmd.wr_count; ++i) { | 1434 | for (i = 0; i < cmd.wr_count; ++i) { |
| @@ -1273,12 +1436,12 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, | |||
| 1273 | buf + sizeof cmd + i * cmd.wqe_size, | 1436 | buf + sizeof cmd + i * cmd.wqe_size, |
| 1274 | cmd.wqe_size)) { | 1437 | cmd.wqe_size)) { |
| 1275 | ret = -EFAULT; | 1438 | ret = -EFAULT; |
| 1276 | goto out; | 1439 | goto out_put; |
| 1277 | } | 1440 | } |
| 1278 | 1441 | ||
| 1279 | if (user_wr->num_sge + sg_ind > cmd.sge_count) { | 1442 | if (user_wr->num_sge + sg_ind > cmd.sge_count) { |
| 1280 | ret = -EINVAL; | 1443 | ret = -EINVAL; |
| 1281 | goto out; | 1444 | goto out_put; |
| 1282 | } | 1445 | } |
| 1283 | 1446 | ||
| 1284 | next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) + | 1447 | next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) + |
| @@ -1286,7 +1449,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, | |||
| 1286 | GFP_KERNEL); | 1449 | GFP_KERNEL); |
| 1287 | if (!next) { | 1450 | if (!next) { |
| 1288 | ret = -ENOMEM; | 1451 | ret = -ENOMEM; |
| 1289 | goto out; | 1452 | goto out_put; |
| 1290 | } | 1453 | } |
| 1291 | 1454 | ||
| 1292 | if (!last) | 1455 | if (!last) |
| @@ -1302,12 +1465,12 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, | |||
| 1302 | next->send_flags = user_wr->send_flags; | 1465 | next->send_flags = user_wr->send_flags; |
| 1303 | next->imm_data = (__be32 __force) user_wr->imm_data; | 1466 | next->imm_data = (__be32 __force) user_wr->imm_data; |
| 1304 | 1467 | ||
| 1305 | if (qp->qp_type == IB_QPT_UD) { | 1468 | if (is_ud) { |
| 1306 | next->wr.ud.ah = idr_find(&ib_uverbs_ah_idr, | 1469 | next->wr.ud.ah = idr_read_ah(user_wr->wr.ud.ah, |
| 1307 | user_wr->wr.ud.ah); | 1470 | file->ucontext); |
| 1308 | if (!next->wr.ud.ah) { | 1471 | if (!next->wr.ud.ah) { |
| 1309 | ret = -EINVAL; | 1472 | ret = -EINVAL; |
| 1310 | goto out; | 1473 | goto out_put; |
| 1311 | } | 1474 | } |
| 1312 | next->wr.ud.remote_qpn = user_wr->wr.ud.remote_qpn; | 1475 | next->wr.ud.remote_qpn = user_wr->wr.ud.remote_qpn; |
| 1313 | next->wr.ud.remote_qkey = user_wr->wr.ud.remote_qkey; | 1476 | next->wr.ud.remote_qkey = user_wr->wr.ud.remote_qkey; |
| @@ -1344,7 +1507,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, | |||
| 1344 | sg_ind * sizeof (struct ib_sge), | 1507 | sg_ind * sizeof (struct ib_sge), |
| 1345 | next->num_sge * sizeof (struct ib_sge))) { | 1508 | next->num_sge * sizeof (struct ib_sge))) { |
| 1346 | ret = -EFAULT; | 1509 | ret = -EFAULT; |
| 1347 | goto out; | 1510 | goto out_put; |
| 1348 | } | 1511 | } |
| 1349 | sg_ind += next->num_sge; | 1512 | sg_ind += next->num_sge; |
| 1350 | } else | 1513 | } else |
| @@ -1364,10 +1527,13 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, | |||
| 1364 | &resp, sizeof resp)) | 1527 | &resp, sizeof resp)) |
| 1365 | ret = -EFAULT; | 1528 | ret = -EFAULT; |
| 1366 | 1529 | ||
| 1367 | out: | 1530 | out_put: |
| 1368 | mutex_unlock(&ib_uverbs_idr_mutex); | 1531 | put_qp_read(qp); |
| 1369 | 1532 | ||
| 1533 | out: | ||
| 1370 | while (wr) { | 1534 | while (wr) { |
| 1535 | if (is_ud && wr->wr.ud.ah) | ||
| 1536 | put_ah_read(wr->wr.ud.ah); | ||
| 1371 | next = wr->next; | 1537 | next = wr->next; |
| 1372 | kfree(wr); | 1538 | kfree(wr); |
| 1373 | wr = next; | 1539 | wr = next; |
| @@ -1482,14 +1648,15 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file, | |||
| 1482 | if (IS_ERR(wr)) | 1648 | if (IS_ERR(wr)) |
| 1483 | return PTR_ERR(wr); | 1649 | return PTR_ERR(wr); |
| 1484 | 1650 | ||
| 1485 | mutex_lock(&ib_uverbs_idr_mutex); | 1651 | qp = idr_read_qp(cmd.qp_handle, file->ucontext); |
| 1486 | 1652 | if (!qp) | |
| 1487 | qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); | ||
| 1488 | if (!qp || qp->uobject->context != file->ucontext) | ||
| 1489 | goto out; | 1653 | goto out; |
| 1490 | 1654 | ||
| 1491 | resp.bad_wr = 0; | 1655 | resp.bad_wr = 0; |
| 1492 | ret = qp->device->post_recv(qp, wr, &bad_wr); | 1656 | ret = qp->device->post_recv(qp, wr, &bad_wr); |
| 1657 | |||
| 1658 | put_qp_read(qp); | ||
| 1659 | |||
| 1493 | if (ret) | 1660 | if (ret) |
| 1494 | for (next = wr; next; next = next->next) { | 1661 | for (next = wr; next; next = next->next) { |
| 1495 | ++resp.bad_wr; | 1662 | ++resp.bad_wr; |
| @@ -1503,8 +1670,6 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file, | |||
| 1503 | ret = -EFAULT; | 1670 | ret = -EFAULT; |
| 1504 | 1671 | ||
| 1505 | out: | 1672 | out: |
| 1506 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 1507 | |||
| 1508 | while (wr) { | 1673 | while (wr) { |
| 1509 | next = wr->next; | 1674 | next = wr->next; |
| 1510 | kfree(wr); | 1675 | kfree(wr); |
| @@ -1533,14 +1698,15 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file, | |||
| 1533 | if (IS_ERR(wr)) | 1698 | if (IS_ERR(wr)) |
| 1534 | return PTR_ERR(wr); | 1699 | return PTR_ERR(wr); |
| 1535 | 1700 | ||
| 1536 | mutex_lock(&ib_uverbs_idr_mutex); | 1701 | srq = idr_read_srq(cmd.srq_handle, file->ucontext); |
| 1537 | 1702 | if (!srq) | |
| 1538 | srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); | ||
| 1539 | if (!srq || srq->uobject->context != file->ucontext) | ||
| 1540 | goto out; | 1703 | goto out; |
| 1541 | 1704 | ||
| 1542 | resp.bad_wr = 0; | 1705 | resp.bad_wr = 0; |
| 1543 | ret = srq->device->post_srq_recv(srq, wr, &bad_wr); | 1706 | ret = srq->device->post_srq_recv(srq, wr, &bad_wr); |
| 1707 | |||
| 1708 | put_srq_read(srq); | ||
| 1709 | |||
| 1544 | if (ret) | 1710 | if (ret) |
| 1545 | for (next = wr; next; next = next->next) { | 1711 | for (next = wr; next; next = next->next) { |
| 1546 | ++resp.bad_wr; | 1712 | ++resp.bad_wr; |
| @@ -1554,8 +1720,6 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file, | |||
| 1554 | ret = -EFAULT; | 1720 | ret = -EFAULT; |
| 1555 | 1721 | ||
| 1556 | out: | 1722 | out: |
| 1557 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 1558 | |||
| 1559 | while (wr) { | 1723 | while (wr) { |
| 1560 | next = wr->next; | 1724 | next = wr->next; |
| 1561 | kfree(wr); | 1725 | kfree(wr); |
| @@ -1587,17 +1751,15 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, | |||
| 1587 | if (!uobj) | 1751 | if (!uobj) |
| 1588 | return -ENOMEM; | 1752 | return -ENOMEM; |
| 1589 | 1753 | ||
| 1590 | mutex_lock(&ib_uverbs_idr_mutex); | 1754 | init_uobj(uobj, cmd.user_handle, file->ucontext); |
| 1755 | down_write(&uobj->mutex); | ||
| 1591 | 1756 | ||
| 1592 | pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); | 1757 | pd = idr_read_pd(cmd.pd_handle, file->ucontext); |
| 1593 | if (!pd || pd->uobject->context != file->ucontext) { | 1758 | if (!pd) { |
| 1594 | ret = -EINVAL; | 1759 | ret = -EINVAL; |
| 1595 | goto err_up; | 1760 | goto err; |
| 1596 | } | 1761 | } |
| 1597 | 1762 | ||
| 1598 | uobj->user_handle = cmd.user_handle; | ||
| 1599 | uobj->context = file->ucontext; | ||
| 1600 | |||
| 1601 | attr.dlid = cmd.attr.dlid; | 1763 | attr.dlid = cmd.attr.dlid; |
| 1602 | attr.sl = cmd.attr.sl; | 1764 | attr.sl = cmd.attr.sl; |
| 1603 | attr.src_path_bits = cmd.attr.src_path_bits; | 1765 | attr.src_path_bits = cmd.attr.src_path_bits; |
| @@ -1613,21 +1775,13 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, | |||
| 1613 | ah = ib_create_ah(pd, &attr); | 1775 | ah = ib_create_ah(pd, &attr); |
| 1614 | if (IS_ERR(ah)) { | 1776 | if (IS_ERR(ah)) { |
| 1615 | ret = PTR_ERR(ah); | 1777 | ret = PTR_ERR(ah); |
| 1616 | goto err_up; | 1778 | goto err; |
| 1617 | } | ||
| 1618 | |||
| 1619 | ah->uobject = uobj; | ||
| 1620 | |||
| 1621 | retry: | ||
| 1622 | if (!idr_pre_get(&ib_uverbs_ah_idr, GFP_KERNEL)) { | ||
| 1623 | ret = -ENOMEM; | ||
| 1624 | goto err_destroy; | ||
| 1625 | } | 1779 | } |
| 1626 | 1780 | ||
| 1627 | ret = idr_get_new(&ib_uverbs_ah_idr, ah, &uobj->id); | 1781 | ah->uobject = uobj; |
| 1782 | uobj->object = ah; | ||
| 1628 | 1783 | ||
| 1629 | if (ret == -EAGAIN) | 1784 | ret = idr_add_uobj(&ib_uverbs_ah_idr, uobj); |
| 1630 | goto retry; | ||
| 1631 | if (ret) | 1785 | if (ret) |
| 1632 | goto err_destroy; | 1786 | goto err_destroy; |
| 1633 | 1787 | ||
| @@ -1636,27 +1790,29 @@ retry: | |||
| 1636 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 1790 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
| 1637 | &resp, sizeof resp)) { | 1791 | &resp, sizeof resp)) { |
| 1638 | ret = -EFAULT; | 1792 | ret = -EFAULT; |
| 1639 | goto err_idr; | 1793 | goto err_copy; |
| 1640 | } | 1794 | } |
| 1641 | 1795 | ||
| 1796 | put_pd_read(pd); | ||
| 1797 | |||
| 1642 | mutex_lock(&file->mutex); | 1798 | mutex_lock(&file->mutex); |
| 1643 | list_add_tail(&uobj->list, &file->ucontext->ah_list); | 1799 | list_add_tail(&uobj->list, &file->ucontext->ah_list); |
| 1644 | mutex_unlock(&file->mutex); | 1800 | mutex_unlock(&file->mutex); |
| 1645 | 1801 | ||
| 1646 | mutex_unlock(&ib_uverbs_idr_mutex); | 1802 | uobj->live = 1; |
| 1803 | |||
| 1804 | up_write(&uobj->mutex); | ||
| 1647 | 1805 | ||
| 1648 | return in_len; | 1806 | return in_len; |
| 1649 | 1807 | ||
| 1650 | err_idr: | 1808 | err_copy: |
| 1651 | idr_remove(&ib_uverbs_ah_idr, uobj->id); | 1809 | idr_remove_uobj(&ib_uverbs_ah_idr, uobj); |
| 1652 | 1810 | ||
| 1653 | err_destroy: | 1811 | err_destroy: |
| 1654 | ib_destroy_ah(ah); | 1812 | ib_destroy_ah(ah); |
| 1655 | 1813 | ||
| 1656 | err_up: | 1814 | err: |
| 1657 | mutex_unlock(&ib_uverbs_idr_mutex); | 1815 | put_uobj_write(uobj); |
| 1658 | |||
| 1659 | kfree(uobj); | ||
| 1660 | return ret; | 1816 | return ret; |
| 1661 | } | 1817 | } |
| 1662 | 1818 | ||
| @@ -1666,35 +1822,34 @@ ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file, | |||
| 1666 | struct ib_uverbs_destroy_ah cmd; | 1822 | struct ib_uverbs_destroy_ah cmd; |
| 1667 | struct ib_ah *ah; | 1823 | struct ib_ah *ah; |
| 1668 | struct ib_uobject *uobj; | 1824 | struct ib_uobject *uobj; |
| 1669 | int ret = -EINVAL; | 1825 | int ret; |
| 1670 | 1826 | ||
| 1671 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 1827 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| 1672 | return -EFAULT; | 1828 | return -EFAULT; |
| 1673 | 1829 | ||
| 1674 | mutex_lock(&ib_uverbs_idr_mutex); | 1830 | uobj = idr_write_uobj(&ib_uverbs_ah_idr, cmd.ah_handle, file->ucontext); |
| 1831 | if (!uobj) | ||
| 1832 | return -EINVAL; | ||
| 1833 | ah = uobj->object; | ||
| 1675 | 1834 | ||
| 1676 | ah = idr_find(&ib_uverbs_ah_idr, cmd.ah_handle); | 1835 | ret = ib_destroy_ah(ah); |
| 1677 | if (!ah || ah->uobject->context != file->ucontext) | 1836 | if (!ret) |
| 1678 | goto out; | 1837 | uobj->live = 0; |
| 1679 | 1838 | ||
| 1680 | uobj = ah->uobject; | 1839 | put_uobj_write(uobj); |
| 1681 | 1840 | ||
| 1682 | ret = ib_destroy_ah(ah); | ||
| 1683 | if (ret) | 1841 | if (ret) |
| 1684 | goto out; | 1842 | return ret; |
| 1685 | 1843 | ||
| 1686 | idr_remove(&ib_uverbs_ah_idr, cmd.ah_handle); | 1844 | idr_remove_uobj(&ib_uverbs_ah_idr, uobj); |
| 1687 | 1845 | ||
| 1688 | mutex_lock(&file->mutex); | 1846 | mutex_lock(&file->mutex); |
| 1689 | list_del(&uobj->list); | 1847 | list_del(&uobj->list); |
| 1690 | mutex_unlock(&file->mutex); | 1848 | mutex_unlock(&file->mutex); |
| 1691 | 1849 | ||
| 1692 | kfree(uobj); | 1850 | put_uobj(uobj); |
| 1693 | 1851 | ||
| 1694 | out: | 1852 | return in_len; |
| 1695 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 1696 | |||
| 1697 | return ret ? ret : in_len; | ||
| 1698 | } | 1853 | } |
| 1699 | 1854 | ||
| 1700 | ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, | 1855 | ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, |
| @@ -1703,47 +1858,43 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, | |||
| 1703 | { | 1858 | { |
| 1704 | struct ib_uverbs_attach_mcast cmd; | 1859 | struct ib_uverbs_attach_mcast cmd; |
| 1705 | struct ib_qp *qp; | 1860 | struct ib_qp *qp; |
| 1706 | struct ib_uqp_object *uobj; | 1861 | struct ib_uqp_object *obj; |
| 1707 | struct ib_uverbs_mcast_entry *mcast; | 1862 | struct ib_uverbs_mcast_entry *mcast; |
| 1708 | int ret = -EINVAL; | 1863 | int ret; |
| 1709 | 1864 | ||
| 1710 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 1865 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| 1711 | return -EFAULT; | 1866 | return -EFAULT; |
| 1712 | 1867 | ||
| 1713 | mutex_lock(&ib_uverbs_idr_mutex); | 1868 | qp = idr_read_qp(cmd.qp_handle, file->ucontext); |
| 1714 | 1869 | if (!qp) | |
| 1715 | qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); | 1870 | return -EINVAL; |
| 1716 | if (!qp || qp->uobject->context != file->ucontext) | ||
| 1717 | goto out; | ||
| 1718 | 1871 | ||
| 1719 | uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); | 1872 | obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); |
| 1720 | 1873 | ||
| 1721 | list_for_each_entry(mcast, &uobj->mcast_list, list) | 1874 | list_for_each_entry(mcast, &obj->mcast_list, list) |
| 1722 | if (cmd.mlid == mcast->lid && | 1875 | if (cmd.mlid == mcast->lid && |
| 1723 | !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) { | 1876 | !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) { |
| 1724 | ret = 0; | 1877 | ret = 0; |
| 1725 | goto out; | 1878 | goto out_put; |
| 1726 | } | 1879 | } |
| 1727 | 1880 | ||
| 1728 | mcast = kmalloc(sizeof *mcast, GFP_KERNEL); | 1881 | mcast = kmalloc(sizeof *mcast, GFP_KERNEL); |
| 1729 | if (!mcast) { | 1882 | if (!mcast) { |
| 1730 | ret = -ENOMEM; | 1883 | ret = -ENOMEM; |
| 1731 | goto out; | 1884 | goto out_put; |
| 1732 | } | 1885 | } |
| 1733 | 1886 | ||
| 1734 | mcast->lid = cmd.mlid; | 1887 | mcast->lid = cmd.mlid; |
| 1735 | memcpy(mcast->gid.raw, cmd.gid, sizeof mcast->gid.raw); | 1888 | memcpy(mcast->gid.raw, cmd.gid, sizeof mcast->gid.raw); |
| 1736 | 1889 | ||
| 1737 | ret = ib_attach_mcast(qp, &mcast->gid, cmd.mlid); | 1890 | ret = ib_attach_mcast(qp, &mcast->gid, cmd.mlid); |
| 1738 | if (!ret) { | 1891 | if (!ret) |
| 1739 | uobj = container_of(qp->uobject, struct ib_uqp_object, | 1892 | list_add_tail(&mcast->list, &obj->mcast_list); |
| 1740 | uevent.uobject); | 1893 | else |
| 1741 | list_add_tail(&mcast->list, &uobj->mcast_list); | ||
| 1742 | } else | ||
| 1743 | kfree(mcast); | 1894 | kfree(mcast); |
| 1744 | 1895 | ||
| 1745 | out: | 1896 | out_put: |
| 1746 | mutex_unlock(&ib_uverbs_idr_mutex); | 1897 | put_qp_read(qp); |
| 1747 | 1898 | ||
| 1748 | return ret ? ret : in_len; | 1899 | return ret ? ret : in_len; |
| 1749 | } | 1900 | } |
| @@ -1753,7 +1904,7 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file, | |||
| 1753 | int out_len) | 1904 | int out_len) |
| 1754 | { | 1905 | { |
| 1755 | struct ib_uverbs_detach_mcast cmd; | 1906 | struct ib_uverbs_detach_mcast cmd; |
| 1756 | struct ib_uqp_object *uobj; | 1907 | struct ib_uqp_object *obj; |
| 1757 | struct ib_qp *qp; | 1908 | struct ib_qp *qp; |
| 1758 | struct ib_uverbs_mcast_entry *mcast; | 1909 | struct ib_uverbs_mcast_entry *mcast; |
| 1759 | int ret = -EINVAL; | 1910 | int ret = -EINVAL; |
| @@ -1761,19 +1912,17 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file, | |||
| 1761 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 1912 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| 1762 | return -EFAULT; | 1913 | return -EFAULT; |
| 1763 | 1914 | ||
| 1764 | mutex_lock(&ib_uverbs_idr_mutex); | 1915 | qp = idr_read_qp(cmd.qp_handle, file->ucontext); |
| 1765 | 1916 | if (!qp) | |
| 1766 | qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); | 1917 | return -EINVAL; |
| 1767 | if (!qp || qp->uobject->context != file->ucontext) | ||
| 1768 | goto out; | ||
| 1769 | 1918 | ||
| 1770 | ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); | 1919 | ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); |
| 1771 | if (ret) | 1920 | if (ret) |
| 1772 | goto out; | 1921 | goto out_put; |
| 1773 | 1922 | ||
| 1774 | uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); | 1923 | obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); |
| 1775 | 1924 | ||
| 1776 | list_for_each_entry(mcast, &uobj->mcast_list, list) | 1925 | list_for_each_entry(mcast, &obj->mcast_list, list) |
| 1777 | if (cmd.mlid == mcast->lid && | 1926 | if (cmd.mlid == mcast->lid && |
| 1778 | !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) { | 1927 | !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) { |
| 1779 | list_del(&mcast->list); | 1928 | list_del(&mcast->list); |
| @@ -1781,8 +1930,8 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file, | |||
| 1781 | break; | 1930 | break; |
| 1782 | } | 1931 | } |
| 1783 | 1932 | ||
| 1784 | out: | 1933 | out_put: |
| 1785 | mutex_unlock(&ib_uverbs_idr_mutex); | 1934 | put_qp_read(qp); |
| 1786 | 1935 | ||
| 1787 | return ret ? ret : in_len; | 1936 | return ret ? ret : in_len; |
| 1788 | } | 1937 | } |
| @@ -1794,7 +1943,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, | |||
| 1794 | struct ib_uverbs_create_srq cmd; | 1943 | struct ib_uverbs_create_srq cmd; |
| 1795 | struct ib_uverbs_create_srq_resp resp; | 1944 | struct ib_uverbs_create_srq_resp resp; |
| 1796 | struct ib_udata udata; | 1945 | struct ib_udata udata; |
| 1797 | struct ib_uevent_object *uobj; | 1946 | struct ib_uevent_object *obj; |
| 1798 | struct ib_pd *pd; | 1947 | struct ib_pd *pd; |
| 1799 | struct ib_srq *srq; | 1948 | struct ib_srq *srq; |
| 1800 | struct ib_srq_init_attr attr; | 1949 | struct ib_srq_init_attr attr; |
| @@ -1810,17 +1959,17 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, | |||
| 1810 | (unsigned long) cmd.response + sizeof resp, | 1959 | (unsigned long) cmd.response + sizeof resp, |
| 1811 | in_len - sizeof cmd, out_len - sizeof resp); | 1960 | in_len - sizeof cmd, out_len - sizeof resp); |
| 1812 | 1961 | ||
| 1813 | uobj = kmalloc(sizeof *uobj, GFP_KERNEL); | 1962 | obj = kmalloc(sizeof *obj, GFP_KERNEL); |
| 1814 | if (!uobj) | 1963 | if (!obj) |
| 1815 | return -ENOMEM; | 1964 | return -ENOMEM; |
| 1816 | 1965 | ||
| 1817 | mutex_lock(&ib_uverbs_idr_mutex); | 1966 | init_uobj(&obj->uobject, 0, file->ucontext); |
| 1967 | down_write(&obj->uobject.mutex); | ||
| 1818 | 1968 | ||
| 1819 | pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); | 1969 | pd = idr_read_pd(cmd.pd_handle, file->ucontext); |
| 1820 | 1970 | if (!pd) { | |
| 1821 | if (!pd || pd->uobject->context != file->ucontext) { | ||
| 1822 | ret = -EINVAL; | 1971 | ret = -EINVAL; |
| 1823 | goto err_up; | 1972 | goto err; |
| 1824 | } | 1973 | } |
| 1825 | 1974 | ||
| 1826 | attr.event_handler = ib_uverbs_srq_event_handler; | 1975 | attr.event_handler = ib_uverbs_srq_event_handler; |
| @@ -1829,69 +1978,59 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, | |||
| 1829 | attr.attr.max_sge = cmd.max_sge; | 1978 | attr.attr.max_sge = cmd.max_sge; |
| 1830 | attr.attr.srq_limit = cmd.srq_limit; | 1979 | attr.attr.srq_limit = cmd.srq_limit; |
| 1831 | 1980 | ||
| 1832 | uobj->uobject.user_handle = cmd.user_handle; | 1981 | obj->events_reported = 0; |
| 1833 | uobj->uobject.context = file->ucontext; | 1982 | INIT_LIST_HEAD(&obj->event_list); |
| 1834 | uobj->events_reported = 0; | ||
| 1835 | INIT_LIST_HEAD(&uobj->event_list); | ||
| 1836 | 1983 | ||
| 1837 | srq = pd->device->create_srq(pd, &attr, &udata); | 1984 | srq = pd->device->create_srq(pd, &attr, &udata); |
| 1838 | if (IS_ERR(srq)) { | 1985 | if (IS_ERR(srq)) { |
| 1839 | ret = PTR_ERR(srq); | 1986 | ret = PTR_ERR(srq); |
| 1840 | goto err_up; | 1987 | goto err; |
| 1841 | } | 1988 | } |
| 1842 | 1989 | ||
| 1843 | srq->device = pd->device; | 1990 | srq->device = pd->device; |
| 1844 | srq->pd = pd; | 1991 | srq->pd = pd; |
| 1845 | srq->uobject = &uobj->uobject; | 1992 | srq->uobject = &obj->uobject; |
| 1846 | srq->event_handler = attr.event_handler; | 1993 | srq->event_handler = attr.event_handler; |
| 1847 | srq->srq_context = attr.srq_context; | 1994 | srq->srq_context = attr.srq_context; |
| 1848 | atomic_inc(&pd->usecnt); | 1995 | atomic_inc(&pd->usecnt); |
| 1849 | atomic_set(&srq->usecnt, 0); | 1996 | atomic_set(&srq->usecnt, 0); |
| 1850 | 1997 | ||
| 1851 | memset(&resp, 0, sizeof resp); | 1998 | obj->uobject.object = srq; |
| 1852 | 1999 | ret = idr_add_uobj(&ib_uverbs_srq_idr, &obj->uobject); | |
| 1853 | retry: | ||
| 1854 | if (!idr_pre_get(&ib_uverbs_srq_idr, GFP_KERNEL)) { | ||
| 1855 | ret = -ENOMEM; | ||
| 1856 | goto err_destroy; | ||
| 1857 | } | ||
| 1858 | |||
| 1859 | ret = idr_get_new(&ib_uverbs_srq_idr, srq, &uobj->uobject.id); | ||
| 1860 | |||
| 1861 | if (ret == -EAGAIN) | ||
| 1862 | goto retry; | ||
| 1863 | if (ret) | 2000 | if (ret) |
| 1864 | goto err_destroy; | 2001 | goto err_destroy; |
| 1865 | 2002 | ||
| 1866 | resp.srq_handle = uobj->uobject.id; | 2003 | memset(&resp, 0, sizeof resp); |
| 2004 | resp.srq_handle = obj->uobject.id; | ||
| 1867 | resp.max_wr = attr.attr.max_wr; | 2005 | resp.max_wr = attr.attr.max_wr; |
| 1868 | resp.max_sge = attr.attr.max_sge; | 2006 | resp.max_sge = attr.attr.max_sge; |
| 1869 | 2007 | ||
| 1870 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 2008 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
| 1871 | &resp, sizeof resp)) { | 2009 | &resp, sizeof resp)) { |
| 1872 | ret = -EFAULT; | 2010 | ret = -EFAULT; |
| 1873 | goto err_idr; | 2011 | goto err_copy; |
| 1874 | } | 2012 | } |
| 1875 | 2013 | ||
| 2014 | put_pd_read(pd); | ||
| 2015 | |||
| 1876 | mutex_lock(&file->mutex); | 2016 | mutex_lock(&file->mutex); |
| 1877 | list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list); | 2017 | list_add_tail(&obj->uobject.list, &file->ucontext->srq_list); |
| 1878 | mutex_unlock(&file->mutex); | 2018 | mutex_unlock(&file->mutex); |
| 1879 | 2019 | ||
| 1880 | mutex_unlock(&ib_uverbs_idr_mutex); | 2020 | obj->uobject.live = 1; |
| 2021 | |||
| 2022 | up_write(&obj->uobject.mutex); | ||
| 1881 | 2023 | ||
| 1882 | return in_len; | 2024 | return in_len; |
| 1883 | 2025 | ||
| 1884 | err_idr: | 2026 | err_copy: |
| 1885 | idr_remove(&ib_uverbs_srq_idr, uobj->uobject.id); | 2027 | idr_remove_uobj(&ib_uverbs_srq_idr, &obj->uobject); |
| 1886 | 2028 | ||
| 1887 | err_destroy: | 2029 | err_destroy: |
| 1888 | ib_destroy_srq(srq); | 2030 | ib_destroy_srq(srq); |
| 1889 | atomic_dec(&pd->usecnt); | ||
| 1890 | |||
| 1891 | err_up: | ||
| 1892 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 1893 | 2031 | ||
| 1894 | kfree(uobj); | 2032 | err: |
| 2033 | put_uobj_write(&obj->uobject); | ||
| 1895 | return ret; | 2034 | return ret; |
| 1896 | } | 2035 | } |
| 1897 | 2036 | ||
| @@ -1907,21 +2046,16 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file, | |||
| 1907 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 2046 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| 1908 | return -EFAULT; | 2047 | return -EFAULT; |
| 1909 | 2048 | ||
| 1910 | mutex_lock(&ib_uverbs_idr_mutex); | 2049 | srq = idr_read_srq(cmd.srq_handle, file->ucontext); |
| 1911 | 2050 | if (!srq) | |
| 1912 | srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); | 2051 | return -EINVAL; |
| 1913 | if (!srq || srq->uobject->context != file->ucontext) { | ||
| 1914 | ret = -EINVAL; | ||
| 1915 | goto out; | ||
| 1916 | } | ||
| 1917 | 2052 | ||
| 1918 | attr.max_wr = cmd.max_wr; | 2053 | attr.max_wr = cmd.max_wr; |
| 1919 | attr.srq_limit = cmd.srq_limit; | 2054 | attr.srq_limit = cmd.srq_limit; |
| 1920 | 2055 | ||
| 1921 | ret = ib_modify_srq(srq, &attr, cmd.attr_mask); | 2056 | ret = ib_modify_srq(srq, &attr, cmd.attr_mask); |
| 1922 | 2057 | ||
| 1923 | out: | 2058 | put_srq_read(srq); |
| 1924 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 1925 | 2059 | ||
| 1926 | return ret ? ret : in_len; | 2060 | return ret ? ret : in_len; |
| 1927 | } | 2061 | } |
| @@ -1942,18 +2076,16 @@ ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file, | |||
| 1942 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 2076 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| 1943 | return -EFAULT; | 2077 | return -EFAULT; |
| 1944 | 2078 | ||
| 1945 | mutex_lock(&ib_uverbs_idr_mutex); | 2079 | srq = idr_read_srq(cmd.srq_handle, file->ucontext); |
| 2080 | if (!srq) | ||
| 2081 | return -EINVAL; | ||
| 1946 | 2082 | ||
| 1947 | srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); | 2083 | ret = ib_query_srq(srq, &attr); |
| 1948 | if (srq && srq->uobject->context == file->ucontext) | ||
| 1949 | ret = ib_query_srq(srq, &attr); | ||
| 1950 | else | ||
| 1951 | ret = -EINVAL; | ||
| 1952 | 2084 | ||
| 1953 | mutex_unlock(&ib_uverbs_idr_mutex); | 2085 | put_srq_read(srq); |
| 1954 | 2086 | ||
| 1955 | if (ret) | 2087 | if (ret) |
| 1956 | goto out; | 2088 | return ret; |
| 1957 | 2089 | ||
| 1958 | memset(&resp, 0, sizeof resp); | 2090 | memset(&resp, 0, sizeof resp); |
| 1959 | 2091 | ||
| @@ -1963,10 +2095,9 @@ ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file, | |||
| 1963 | 2095 | ||
| 1964 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 2096 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
| 1965 | &resp, sizeof resp)) | 2097 | &resp, sizeof resp)) |
| 1966 | ret = -EFAULT; | 2098 | return -EFAULT; |
| 1967 | 2099 | ||
| 1968 | out: | 2100 | return in_len; |
| 1969 | return ret ? ret : in_len; | ||
| 1970 | } | 2101 | } |
| 1971 | 2102 | ||
| 1972 | ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, | 2103 | ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, |
| @@ -1975,45 +2106,45 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, | |||
| 1975 | { | 2106 | { |
| 1976 | struct ib_uverbs_destroy_srq cmd; | 2107 | struct ib_uverbs_destroy_srq cmd; |
| 1977 | struct ib_uverbs_destroy_srq_resp resp; | 2108 | struct ib_uverbs_destroy_srq_resp resp; |
| 2109 | struct ib_uobject *uobj; | ||
| 1978 | struct ib_srq *srq; | 2110 | struct ib_srq *srq; |
| 1979 | struct ib_uevent_object *uobj; | 2111 | struct ib_uevent_object *obj; |
| 1980 | int ret = -EINVAL; | 2112 | int ret = -EINVAL; |
| 1981 | 2113 | ||
| 1982 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 2114 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| 1983 | return -EFAULT; | 2115 | return -EFAULT; |
| 1984 | 2116 | ||
| 1985 | mutex_lock(&ib_uverbs_idr_mutex); | 2117 | uobj = idr_write_uobj(&ib_uverbs_srq_idr, cmd.srq_handle, file->ucontext); |
| 1986 | 2118 | if (!uobj) | |
| 1987 | memset(&resp, 0, sizeof resp); | 2119 | return -EINVAL; |
| 2120 | srq = uobj->object; | ||
| 2121 | obj = container_of(uobj, struct ib_uevent_object, uobject); | ||
| 1988 | 2122 | ||
| 1989 | srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); | 2123 | ret = ib_destroy_srq(srq); |
| 1990 | if (!srq || srq->uobject->context != file->ucontext) | 2124 | if (!ret) |
| 1991 | goto out; | 2125 | uobj->live = 0; |
| 1992 | 2126 | ||
| 1993 | uobj = container_of(srq->uobject, struct ib_uevent_object, uobject); | 2127 | put_uobj_write(uobj); |
| 1994 | 2128 | ||
| 1995 | ret = ib_destroy_srq(srq); | ||
| 1996 | if (ret) | 2129 | if (ret) |
| 1997 | goto out; | 2130 | return ret; |
| 1998 | 2131 | ||
| 1999 | idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle); | 2132 | idr_remove_uobj(&ib_uverbs_srq_idr, uobj); |
| 2000 | 2133 | ||
| 2001 | mutex_lock(&file->mutex); | 2134 | mutex_lock(&file->mutex); |
| 2002 | list_del(&uobj->uobject.list); | 2135 | list_del(&uobj->list); |
| 2003 | mutex_unlock(&file->mutex); | 2136 | mutex_unlock(&file->mutex); |
| 2004 | 2137 | ||
| 2005 | ib_uverbs_release_uevent(file, uobj); | 2138 | ib_uverbs_release_uevent(file, obj); |
| 2006 | 2139 | ||
| 2007 | resp.events_reported = uobj->events_reported; | 2140 | memset(&resp, 0, sizeof resp); |
| 2141 | resp.events_reported = obj->events_reported; | ||
| 2008 | 2142 | ||
| 2009 | kfree(uobj); | 2143 | put_uobj(uobj); |
| 2010 | 2144 | ||
| 2011 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 2145 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
| 2012 | &resp, sizeof resp)) | 2146 | &resp, sizeof resp)) |
| 2013 | ret = -EFAULT; | 2147 | ret = -EFAULT; |
| 2014 | 2148 | ||
| 2015 | out: | ||
| 2016 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 2017 | |||
| 2018 | return ret ? ret : in_len; | 2149 | return ret ? ret : in_len; |
| 2019 | } | 2150 | } |
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index ff092a0a94da..5ec2d49e9bb6 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c | |||
| @@ -66,7 +66,7 @@ enum { | |||
| 66 | 66 | ||
| 67 | static struct class *uverbs_class; | 67 | static struct class *uverbs_class; |
| 68 | 68 | ||
| 69 | DEFINE_MUTEX(ib_uverbs_idr_mutex); | 69 | DEFINE_SPINLOCK(ib_uverbs_idr_lock); |
| 70 | DEFINE_IDR(ib_uverbs_pd_idr); | 70 | DEFINE_IDR(ib_uverbs_pd_idr); |
| 71 | DEFINE_IDR(ib_uverbs_mr_idr); | 71 | DEFINE_IDR(ib_uverbs_mr_idr); |
| 72 | DEFINE_IDR(ib_uverbs_mw_idr); | 72 | DEFINE_IDR(ib_uverbs_mw_idr); |
| @@ -183,21 +183,21 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, | |||
| 183 | if (!context) | 183 | if (!context) |
| 184 | return 0; | 184 | return 0; |
| 185 | 185 | ||
| 186 | mutex_lock(&ib_uverbs_idr_mutex); | ||
| 187 | |||
| 188 | list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) { | 186 | list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) { |
| 189 | struct ib_ah *ah = idr_find(&ib_uverbs_ah_idr, uobj->id); | 187 | struct ib_ah *ah = uobj->object; |
| 190 | idr_remove(&ib_uverbs_ah_idr, uobj->id); | 188 | |
| 189 | idr_remove_uobj(&ib_uverbs_ah_idr, uobj); | ||
| 191 | ib_destroy_ah(ah); | 190 | ib_destroy_ah(ah); |
| 192 | list_del(&uobj->list); | 191 | list_del(&uobj->list); |
| 193 | kfree(uobj); | 192 | kfree(uobj); |
| 194 | } | 193 | } |
| 195 | 194 | ||
| 196 | list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { | 195 | list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { |
| 197 | struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); | 196 | struct ib_qp *qp = uobj->object; |
| 198 | struct ib_uqp_object *uqp = | 197 | struct ib_uqp_object *uqp = |
| 199 | container_of(uobj, struct ib_uqp_object, uevent.uobject); | 198 | container_of(uobj, struct ib_uqp_object, uevent.uobject); |
| 200 | idr_remove(&ib_uverbs_qp_idr, uobj->id); | 199 | |
| 200 | idr_remove_uobj(&ib_uverbs_qp_idr, uobj); | ||
| 201 | ib_uverbs_detach_umcast(qp, uqp); | 201 | ib_uverbs_detach_umcast(qp, uqp); |
| 202 | ib_destroy_qp(qp); | 202 | ib_destroy_qp(qp); |
| 203 | list_del(&uobj->list); | 203 | list_del(&uobj->list); |
| @@ -206,11 +206,12 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, | |||
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { | 208 | list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { |
| 209 | struct ib_cq *cq = idr_find(&ib_uverbs_cq_idr, uobj->id); | 209 | struct ib_cq *cq = uobj->object; |
| 210 | struct ib_uverbs_event_file *ev_file = cq->cq_context; | 210 | struct ib_uverbs_event_file *ev_file = cq->cq_context; |
| 211 | struct ib_ucq_object *ucq = | 211 | struct ib_ucq_object *ucq = |
| 212 | container_of(uobj, struct ib_ucq_object, uobject); | 212 | container_of(uobj, struct ib_ucq_object, uobject); |
| 213 | idr_remove(&ib_uverbs_cq_idr, uobj->id); | 213 | |
| 214 | idr_remove_uobj(&ib_uverbs_cq_idr, uobj); | ||
| 214 | ib_destroy_cq(cq); | 215 | ib_destroy_cq(cq); |
| 215 | list_del(&uobj->list); | 216 | list_del(&uobj->list); |
| 216 | ib_uverbs_release_ucq(file, ev_file, ucq); | 217 | ib_uverbs_release_ucq(file, ev_file, ucq); |
| @@ -218,10 +219,11 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, | |||
| 218 | } | 219 | } |
| 219 | 220 | ||
| 220 | list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { | 221 | list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { |
| 221 | struct ib_srq *srq = idr_find(&ib_uverbs_srq_idr, uobj->id); | 222 | struct ib_srq *srq = uobj->object; |
| 222 | struct ib_uevent_object *uevent = | 223 | struct ib_uevent_object *uevent = |
| 223 | container_of(uobj, struct ib_uevent_object, uobject); | 224 | container_of(uobj, struct ib_uevent_object, uobject); |
| 224 | idr_remove(&ib_uverbs_srq_idr, uobj->id); | 225 | |
| 226 | idr_remove_uobj(&ib_uverbs_srq_idr, uobj); | ||
| 225 | ib_destroy_srq(srq); | 227 | ib_destroy_srq(srq); |
| 226 | list_del(&uobj->list); | 228 | list_del(&uobj->list); |
| 227 | ib_uverbs_release_uevent(file, uevent); | 229 | ib_uverbs_release_uevent(file, uevent); |
| @@ -231,11 +233,11 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, | |||
| 231 | /* XXX Free MWs */ | 233 | /* XXX Free MWs */ |
| 232 | 234 | ||
| 233 | list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) { | 235 | list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) { |
| 234 | struct ib_mr *mr = idr_find(&ib_uverbs_mr_idr, uobj->id); | 236 | struct ib_mr *mr = uobj->object; |
| 235 | struct ib_device *mrdev = mr->device; | 237 | struct ib_device *mrdev = mr->device; |
| 236 | struct ib_umem_object *memobj; | 238 | struct ib_umem_object *memobj; |
| 237 | 239 | ||
| 238 | idr_remove(&ib_uverbs_mr_idr, uobj->id); | 240 | idr_remove_uobj(&ib_uverbs_mr_idr, uobj); |
| 239 | ib_dereg_mr(mr); | 241 | ib_dereg_mr(mr); |
| 240 | 242 | ||
| 241 | memobj = container_of(uobj, struct ib_umem_object, uobject); | 243 | memobj = container_of(uobj, struct ib_umem_object, uobject); |
| @@ -246,15 +248,14 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, | |||
| 246 | } | 248 | } |
| 247 | 249 | ||
| 248 | list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) { | 250 | list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) { |
| 249 | struct ib_pd *pd = idr_find(&ib_uverbs_pd_idr, uobj->id); | 251 | struct ib_pd *pd = uobj->object; |
| 250 | idr_remove(&ib_uverbs_pd_idr, uobj->id); | 252 | |
| 253 | idr_remove_uobj(&ib_uverbs_pd_idr, uobj); | ||
| 251 | ib_dealloc_pd(pd); | 254 | ib_dealloc_pd(pd); |
| 252 | list_del(&uobj->list); | 255 | list_del(&uobj->list); |
| 253 | kfree(uobj); | 256 | kfree(uobj); |
| 254 | } | 257 | } |
| 255 | 258 | ||
| 256 | mutex_unlock(&ib_uverbs_idr_mutex); | ||
| 257 | |||
| 258 | return context->device->dealloc_ucontext(context); | 259 | return context->device->dealloc_ucontext(context); |
| 259 | } | 260 | } |
| 260 | 261 | ||
diff --git a/drivers/infiniband/core/uverbs_marshall.c b/drivers/infiniband/core/uverbs_marshall.c new file mode 100644 index 000000000000..ce46b13ae02b --- /dev/null +++ b/drivers/infiniband/core/uverbs_marshall.c | |||
| @@ -0,0 +1,138 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2005 Intel Corporation. All rights reserved. | ||
| 3 | * | ||
| 4 | * This software is available to you under a choice of one of two | ||
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
| 6 | * General Public License (GPL) Version 2, available from the file | ||
| 7 | * COPYING in the main directory of this source tree, or the | ||
| 8 | * OpenIB.org BSD license below: | ||
| 9 | * | ||
| 10 | * Redistribution and use in source and binary forms, with or | ||
| 11 | * without modification, are permitted provided that the following | ||
| 12 | * conditions are met: | ||
| 13 | * | ||
| 14 | * - Redistributions of source code must retain the above | ||
| 15 | * copyright notice, this list of conditions and the following | ||
| 16 | * disclaimer. | ||
| 17 | * | ||
| 18 | * - Redistributions in binary form must reproduce the above | ||
| 19 | * copyright notice, this list of conditions and the following | ||
| 20 | * disclaimer in the documentation and/or other materials | ||
| 21 | * provided with the distribution. | ||
| 22 | * | ||
| 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
| 27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
| 28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
| 29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 30 | * SOFTWARE. | ||
| 31 | */ | ||
| 32 | |||
| 33 | #include <rdma/ib_marshall.h> | ||
| 34 | |||
| 35 | static void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst, | ||
| 36 | struct ib_ah_attr *src) | ||
| 37 | { | ||
| 38 | memcpy(dst->grh.dgid, src->grh.dgid.raw, sizeof src->grh.dgid); | ||
| 39 | dst->grh.flow_label = src->grh.flow_label; | ||
| 40 | dst->grh.sgid_index = src->grh.sgid_index; | ||
| 41 | dst->grh.hop_limit = src->grh.hop_limit; | ||
| 42 | dst->grh.traffic_class = src->grh.traffic_class; | ||
| 43 | dst->dlid = src->dlid; | ||
| 44 | dst->sl = src->sl; | ||
| 45 | dst->src_path_bits = src->src_path_bits; | ||
| 46 | dst->static_rate = src->static_rate; | ||
| 47 | dst->is_global = src->ah_flags & IB_AH_GRH ? 1 : 0; | ||
| 48 | dst->port_num = src->port_num; | ||
| 49 | } | ||
| 50 | |||
| 51 | void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst, | ||
| 52 | struct ib_qp_attr *src) | ||
| 53 | { | ||
| 54 | dst->cur_qp_state = src->cur_qp_state; | ||
| 55 | dst->path_mtu = src->path_mtu; | ||
| 56 | dst->path_mig_state = src->path_mig_state; | ||
| 57 | dst->qkey = src->qkey; | ||
| 58 | dst->rq_psn = src->rq_psn; | ||
| 59 | dst->sq_psn = src->sq_psn; | ||
| 60 | dst->dest_qp_num = src->dest_qp_num; | ||
| 61 | dst->qp_access_flags = src->qp_access_flags; | ||
| 62 | |||
| 63 | dst->max_send_wr = src->cap.max_send_wr; | ||
| 64 | dst->max_recv_wr = src->cap.max_recv_wr; | ||
| 65 | dst->max_send_sge = src->cap.max_send_sge; | ||
| 66 | dst->max_recv_sge = src->cap.max_recv_sge; | ||
| 67 | dst->max_inline_data = src->cap.max_inline_data; | ||
| 68 | |||
| 69 | ib_copy_ah_attr_to_user(&dst->ah_attr, &src->ah_attr); | ||
| 70 | ib_copy_ah_attr_to_user(&dst->alt_ah_attr, &src->alt_ah_attr); | ||
| 71 | |||
| 72 | dst->pkey_index = src->pkey_index; | ||
| 73 | dst->alt_pkey_index = src->alt_pkey_index; | ||
| 74 | dst->en_sqd_async_notify = src->en_sqd_async_notify; | ||
| 75 | dst->sq_draining = src->sq_draining; | ||
| 76 | dst->max_rd_atomic = src->max_rd_atomic; | ||
| 77 | dst->max_dest_rd_atomic = src->max_dest_rd_atomic; | ||
| 78 | dst->min_rnr_timer = src->min_rnr_timer; | ||
| 79 | dst->port_num = src->port_num; | ||
| 80 | dst->timeout = src->timeout; | ||
| 81 | dst->retry_cnt = src->retry_cnt; | ||
| 82 | dst->rnr_retry = src->rnr_retry; | ||
| 83 | dst->alt_port_num = src->alt_port_num; | ||
| 84 | dst->alt_timeout = src->alt_timeout; | ||
| 85 | } | ||
| 86 | EXPORT_SYMBOL(ib_copy_qp_attr_to_user); | ||
| 87 | |||
| 88 | void ib_copy_path_rec_to_user(struct ib_user_path_rec *dst, | ||
| 89 | struct ib_sa_path_rec *src) | ||
| 90 | { | ||
| 91 | memcpy(dst->dgid, src->dgid.raw, sizeof src->dgid); | ||
| 92 | memcpy(dst->sgid, src->sgid.raw, sizeof src->sgid); | ||
| 93 | |||
| 94 | dst->dlid = src->dlid; | ||
| 95 | dst->slid = src->slid; | ||
| 96 | dst->raw_traffic = src->raw_traffic; | ||
| 97 | dst->flow_label = src->flow_label; | ||
| 98 | dst->hop_limit = src->hop_limit; | ||
| 99 | dst->traffic_class = src->traffic_class; | ||
| 100 | dst->reversible = src->reversible; | ||
| 101 | dst->numb_path = src->numb_path; | ||
| 102 | dst->pkey = src->pkey; | ||
| 103 | dst->sl = src->sl; | ||
| 104 | dst->mtu_selector = src->mtu_selector; | ||
| 105 | dst->mtu = src->mtu; | ||
| 106 | dst->rate_selector = src->rate_selector; | ||
| 107 | dst->rate = src->rate; | ||
| 108 | dst->packet_life_time = src->packet_life_time; | ||
| 109 | dst->preference = src->preference; | ||
| 110 | dst->packet_life_time_selector = src->packet_life_time_selector; | ||
| 111 | } | ||
| 112 | EXPORT_SYMBOL(ib_copy_path_rec_to_user); | ||
| 113 | |||
| 114 | void ib_copy_path_rec_from_user(struct ib_sa_path_rec *dst, | ||
| 115 | struct ib_user_path_rec *src) | ||
| 116 | { | ||
| 117 | memcpy(dst->dgid.raw, src->dgid, sizeof dst->dgid); | ||
| 118 | memcpy(dst->sgid.raw, src->sgid, sizeof dst->sgid); | ||
| 119 | |||
| 120 | dst->dlid = src->dlid; | ||
| 121 | dst->slid = src->slid; | ||
| 122 | dst->raw_traffic = src->raw_traffic; | ||
| 123 | dst->flow_label = src->flow_label; | ||
| 124 | dst->hop_limit = src->hop_limit; | ||
| 125 | dst->traffic_class = src->traffic_class; | ||
| 126 | dst->reversible = src->reversible; | ||
| 127 | dst->numb_path = src->numb_path; | ||
| 128 | dst->pkey = src->pkey; | ||
| 129 | dst->sl = src->sl; | ||
| 130 | dst->mtu_selector = src->mtu_selector; | ||
| 131 | dst->mtu = src->mtu; | ||
| 132 | dst->rate_selector = src->rate_selector; | ||
| 133 | dst->rate = src->rate; | ||
| 134 | dst->packet_life_time = src->packet_life_time; | ||
| 135 | dst->preference = src->preference; | ||
| 136 | dst->packet_life_time_selector = src->packet_life_time_selector; | ||
| 137 | } | ||
| 138 | EXPORT_SYMBOL(ib_copy_path_rec_from_user); | ||
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index b78e7dc69330..468999c38803 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c | |||
| @@ -125,35 +125,47 @@ struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) | |||
| 125 | } | 125 | } |
| 126 | EXPORT_SYMBOL(ib_create_ah); | 126 | EXPORT_SYMBOL(ib_create_ah); |
| 127 | 127 | ||
| 128 | struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc, | 128 | int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, struct ib_wc *wc, |
| 129 | struct ib_grh *grh, u8 port_num) | 129 | struct ib_grh *grh, struct ib_ah_attr *ah_attr) |
| 130 | { | 130 | { |
| 131 | struct ib_ah_attr ah_attr; | ||
| 132 | u32 flow_class; | 131 | u32 flow_class; |
| 133 | u16 gid_index; | 132 | u16 gid_index; |
| 134 | int ret; | 133 | int ret; |
| 135 | 134 | ||
| 136 | memset(&ah_attr, 0, sizeof ah_attr); | 135 | memset(ah_attr, 0, sizeof *ah_attr); |
| 137 | ah_attr.dlid = wc->slid; | 136 | ah_attr->dlid = wc->slid; |
| 138 | ah_attr.sl = wc->sl; | 137 | ah_attr->sl = wc->sl; |
| 139 | ah_attr.src_path_bits = wc->dlid_path_bits; | 138 | ah_attr->src_path_bits = wc->dlid_path_bits; |
| 140 | ah_attr.port_num = port_num; | 139 | ah_attr->port_num = port_num; |
| 141 | 140 | ||
| 142 | if (wc->wc_flags & IB_WC_GRH) { | 141 | if (wc->wc_flags & IB_WC_GRH) { |
| 143 | ah_attr.ah_flags = IB_AH_GRH; | 142 | ah_attr->ah_flags = IB_AH_GRH; |
| 144 | ah_attr.grh.dgid = grh->sgid; | 143 | ah_attr->grh.dgid = grh->sgid; |
| 145 | 144 | ||
| 146 | ret = ib_find_cached_gid(pd->device, &grh->dgid, &port_num, | 145 | ret = ib_find_cached_gid(device, &grh->dgid, &port_num, |
| 147 | &gid_index); | 146 | &gid_index); |
| 148 | if (ret) | 147 | if (ret) |
| 149 | return ERR_PTR(ret); | 148 | return ret; |
| 150 | 149 | ||
| 151 | ah_attr.grh.sgid_index = (u8) gid_index; | 150 | ah_attr->grh.sgid_index = (u8) gid_index; |
| 152 | flow_class = be32_to_cpu(grh->version_tclass_flow); | 151 | flow_class = be32_to_cpu(grh->version_tclass_flow); |
| 153 | ah_attr.grh.flow_label = flow_class & 0xFFFFF; | 152 | ah_attr->grh.flow_label = flow_class & 0xFFFFF; |
| 154 | ah_attr.grh.traffic_class = (flow_class >> 20) & 0xFF; | 153 | ah_attr->grh.hop_limit = grh->hop_limit; |
| 155 | ah_attr.grh.hop_limit = grh->hop_limit; | 154 | ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF; |
| 156 | } | 155 | } |
| 156 | return 0; | ||
| 157 | } | ||
| 158 | EXPORT_SYMBOL(ib_init_ah_from_wc); | ||
| 159 | |||
| 160 | struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc, | ||
| 161 | struct ib_grh *grh, u8 port_num) | ||
| 162 | { | ||
| 163 | struct ib_ah_attr ah_attr; | ||
| 164 | int ret; | ||
| 165 | |||
| 166 | ret = ib_init_ah_from_wc(pd->device, port_num, wc, grh, &ah_attr); | ||
| 167 | if (ret) | ||
| 168 | return ERR_PTR(ret); | ||
| 157 | 169 | ||
| 158 | return ib_create_ah(pd, &ah_attr); | 170 | return ib_create_ah(pd, &ah_attr); |
| 159 | } | 171 | } |
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index f7f8391fe43f..1a9d0a2c33c3 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c | |||
| @@ -137,47 +137,11 @@ static int recv_subn_get_guidinfo(struct ib_smp *smp, | |||
| 137 | return reply(smp); | 137 | return reply(smp); |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | struct port_info { | ||
| 141 | __be64 mkey; | ||
| 142 | __be64 gid_prefix; | ||
| 143 | __be16 lid; | ||
| 144 | __be16 sm_lid; | ||
| 145 | __be32 cap_mask; | ||
| 146 | __be16 diag_code; | ||
| 147 | __be16 mkey_lease_period; | ||
| 148 | u8 local_port_num; | ||
| 149 | u8 link_width_enabled; | ||
| 150 | u8 link_width_supported; | ||
| 151 | u8 link_width_active; | ||
| 152 | u8 linkspeed_portstate; /* 4 bits, 4 bits */ | ||
| 153 | u8 portphysstate_linkdown; /* 4 bits, 4 bits */ | ||
| 154 | u8 mkeyprot_resv_lmc; /* 2 bits, 3, 3 */ | ||
| 155 | u8 linkspeedactive_enabled; /* 4 bits, 4 bits */ | ||
| 156 | u8 neighbormtu_mastersmsl; /* 4 bits, 4 bits */ | ||
| 157 | u8 vlcap_inittype; /* 4 bits, 4 bits */ | ||
| 158 | u8 vl_high_limit; | ||
| 159 | u8 vl_arb_high_cap; | ||
| 160 | u8 vl_arb_low_cap; | ||
| 161 | u8 inittypereply_mtucap; /* 4 bits, 4 bits */ | ||
| 162 | u8 vlstallcnt_hoqlife; /* 3 bits, 5 bits */ | ||
| 163 | u8 operationalvl_pei_peo_fpi_fpo; /* 4 bits, 1, 1, 1, 1 */ | ||
| 164 | __be16 mkey_violations; | ||
| 165 | __be16 pkey_violations; | ||
| 166 | __be16 qkey_violations; | ||
| 167 | u8 guid_cap; | ||
| 168 | u8 clientrereg_resv_subnetto; /* 1 bit, 2 bits, 5 */ | ||
| 169 | u8 resv_resptimevalue; /* 3 bits, 5 bits */ | ||
| 170 | u8 localphyerrors_overrunerrors; /* 4 bits, 4 bits */ | ||
| 171 | __be16 max_credit_hint; | ||
| 172 | u8 resv; | ||
| 173 | u8 link_roundtrip_latency[3]; | ||
| 174 | } __attribute__ ((packed)); | ||
| 175 | |||
| 176 | static int recv_subn_get_portinfo(struct ib_smp *smp, | 140 | static int recv_subn_get_portinfo(struct ib_smp *smp, |
| 177 | struct ib_device *ibdev, u8 port) | 141 | struct ib_device *ibdev, u8 port) |
| 178 | { | 142 | { |
| 179 | struct ipath_ibdev *dev; | 143 | struct ipath_ibdev *dev; |
| 180 | struct port_info *pip = (struct port_info *)smp->data; | 144 | struct ib_port_info *pip = (struct ib_port_info *)smp->data; |
| 181 | u16 lid; | 145 | u16 lid; |
| 182 | u8 ibcstat; | 146 | u8 ibcstat; |
| 183 | u8 mtu; | 147 | u8 mtu; |
| @@ -312,7 +276,7 @@ static int recv_subn_set_guidinfo(struct ib_smp *smp, | |||
| 312 | static int recv_subn_set_portinfo(struct ib_smp *smp, | 276 | static int recv_subn_set_portinfo(struct ib_smp *smp, |
| 313 | struct ib_device *ibdev, u8 port) | 277 | struct ib_device *ibdev, u8 port) |
| 314 | { | 278 | { |
| 315 | struct port_info *pip = (struct port_info *)smp->data; | 279 | struct ib_port_info *pip = (struct ib_port_info *)smp->data; |
| 316 | struct ib_event event; | 280 | struct ib_event event; |
| 317 | struct ipath_ibdev *dev; | 281 | struct ipath_ibdev *dev; |
| 318 | u32 flags; | 282 | u32 flags; |
| @@ -445,7 +409,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, | |||
| 445 | 409 | ||
| 446 | if (pip->clientrereg_resv_subnetto & 0x80) { | 410 | if (pip->clientrereg_resv_subnetto & 0x80) { |
| 447 | clientrereg = 1; | 411 | clientrereg = 1; |
| 448 | event.event = IB_EVENT_LID_CHANGE; | 412 | event.event = IB_EVENT_CLIENT_REREGISTER; |
| 449 | ib_dispatch_event(&event); | 413 | ib_dispatch_event(&event); |
| 450 | } | 414 | } |
| 451 | 415 | ||
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index 798e13e14faf..d0f7731802c9 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c | |||
| @@ -174,7 +174,6 @@ enum { | |||
| 174 | 174 | ||
| 175 | struct mthca_cmd_context { | 175 | struct mthca_cmd_context { |
| 176 | struct completion done; | 176 | struct completion done; |
| 177 | struct timer_list timer; | ||
| 178 | int result; | 177 | int result; |
| 179 | int next; | 178 | int next; |
| 180 | u64 out_param; | 179 | u64 out_param; |
| @@ -362,15 +361,6 @@ void mthca_cmd_event(struct mthca_dev *dev, | |||
| 362 | complete(&context->done); | 361 | complete(&context->done); |
| 363 | } | 362 | } |
| 364 | 363 | ||
| 365 | static void event_timeout(unsigned long context_ptr) | ||
| 366 | { | ||
| 367 | struct mthca_cmd_context *context = | ||
| 368 | (struct mthca_cmd_context *) context_ptr; | ||
| 369 | |||
| 370 | context->result = -EBUSY; | ||
| 371 | complete(&context->done); | ||
| 372 | } | ||
| 373 | |||
| 374 | static int mthca_cmd_wait(struct mthca_dev *dev, | 364 | static int mthca_cmd_wait(struct mthca_dev *dev, |
| 375 | u64 in_param, | 365 | u64 in_param, |
| 376 | u64 *out_param, | 366 | u64 *out_param, |
| @@ -401,11 +391,10 @@ static int mthca_cmd_wait(struct mthca_dev *dev, | |||
| 401 | if (err) | 391 | if (err) |
| 402 | goto out; | 392 | goto out; |
| 403 | 393 | ||
| 404 | context->timer.expires = jiffies + timeout; | 394 | if (!wait_for_completion_timeout(&context->done, timeout)) { |
| 405 | add_timer(&context->timer); | 395 | err = -EBUSY; |
| 406 | 396 | goto out; | |
| 407 | wait_for_completion(&context->done); | 397 | } |
| 408 | del_timer_sync(&context->timer); | ||
| 409 | 398 | ||
| 410 | err = context->result; | 399 | err = context->result; |
| 411 | if (err) | 400 | if (err) |
| @@ -535,10 +524,6 @@ int mthca_cmd_use_events(struct mthca_dev *dev) | |||
| 535 | for (i = 0; i < dev->cmd.max_cmds; ++i) { | 524 | for (i = 0; i < dev->cmd.max_cmds; ++i) { |
| 536 | dev->cmd.context[i].token = i; | 525 | dev->cmd.context[i].token = i; |
| 537 | dev->cmd.context[i].next = i + 1; | 526 | dev->cmd.context[i].next = i + 1; |
| 538 | init_timer(&dev->cmd.context[i].timer); | ||
| 539 | dev->cmd.context[i].timer.data = | ||
| 540 | (unsigned long) &dev->cmd.context[i]; | ||
| 541 | dev->cmd.context[i].timer.function = event_timeout; | ||
| 542 | } | 527 | } |
| 543 | 528 | ||
| 544 | dev->cmd.context[dev->cmd.max_cmds - 1].next = -1; | 529 | dev->cmd.context[dev->cmd.max_cmds - 1].next = -1; |
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index 205854e9c662..3e27a084257e 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c | |||
| @@ -540,8 +540,17 @@ static inline int mthca_poll_one(struct mthca_dev *dev, | |||
| 540 | entry->wr_id = srq->wrid[wqe_index]; | 540 | entry->wr_id = srq->wrid[wqe_index]; |
| 541 | mthca_free_srq_wqe(srq, wqe); | 541 | mthca_free_srq_wqe(srq, wqe); |
| 542 | } else { | 542 | } else { |
| 543 | s32 wqe; | ||
| 543 | wq = &(*cur_qp)->rq; | 544 | wq = &(*cur_qp)->rq; |
| 544 | wqe_index = be32_to_cpu(cqe->wqe) >> wq->wqe_shift; | 545 | wqe = be32_to_cpu(cqe->wqe); |
| 546 | wqe_index = wqe >> wq->wqe_shift; | ||
| 547 | /* | ||
| 548 | * WQE addr == base - 1 might be reported in receive completion | ||
| 549 | * with error instead of (rq size - 1) by Sinai FW 1.0.800 and | ||
| 550 | * Arbel FW 5.1.400. This bug should be fixed in later FW revs. | ||
| 551 | */ | ||
| 552 | if (unlikely(wqe_index < 0)) | ||
| 553 | wqe_index = wq->max - 1; | ||
| 545 | entry->wr_id = (*cur_qp)->wrid[wqe_index]; | 554 | entry->wr_id = (*cur_qp)->wrid[wqe_index]; |
| 546 | } | 555 | } |
| 547 | 556 | ||
| @@ -813,6 +822,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent, | |||
| 813 | spin_lock_init(&cq->lock); | 822 | spin_lock_init(&cq->lock); |
| 814 | cq->refcount = 1; | 823 | cq->refcount = 1; |
| 815 | init_waitqueue_head(&cq->wait); | 824 | init_waitqueue_head(&cq->wait); |
| 825 | mutex_init(&cq->mutex); | ||
| 816 | 826 | ||
| 817 | memset(cq_context, 0, sizeof *cq_context); | 827 | memset(cq_context, 0, sizeof *cq_context); |
| 818 | cq_context->flags = cpu_to_be32(MTHCA_CQ_STATUS_OK | | 828 | cq_context->flags = cpu_to_be32(MTHCA_CQ_STATUS_OK | |
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index 99f109c3815d..d536217e700e 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c | |||
| @@ -695,10 +695,6 @@ static void mthca_unmap_reg(struct mthca_dev *dev, unsigned long offset, | |||
| 695 | 695 | ||
| 696 | static int __devinit mthca_map_eq_regs(struct mthca_dev *dev) | 696 | static int __devinit mthca_map_eq_regs(struct mthca_dev *dev) |
| 697 | { | 697 | { |
| 698 | unsigned long mthca_base; | ||
| 699 | |||
| 700 | mthca_base = pci_resource_start(dev->pdev, 0); | ||
| 701 | |||
| 702 | if (mthca_is_memfree(dev)) { | 698 | if (mthca_is_memfree(dev)) { |
| 703 | /* | 699 | /* |
| 704 | * We assume that the EQ arm and EQ set CI registers | 700 | * We assume that the EQ arm and EQ set CI registers |
diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c index 4730863ece9a..d9bc030bcccc 100644 --- a/drivers/infiniband/hw/mthca/mthca_mad.c +++ b/drivers/infiniband/hw/mthca/mthca_mad.c | |||
| @@ -114,14 +114,22 @@ static void smp_snoop(struct ib_device *ibdev, | |||
| 114 | mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && | 114 | mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && |
| 115 | mad->mad_hdr.method == IB_MGMT_METHOD_SET) { | 115 | mad->mad_hdr.method == IB_MGMT_METHOD_SET) { |
| 116 | if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) { | 116 | if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) { |
| 117 | struct ib_port_info *pinfo = | ||
| 118 | (struct ib_port_info *) ((struct ib_smp *) mad)->data; | ||
| 119 | |||
| 117 | mthca_update_rate(to_mdev(ibdev), port_num); | 120 | mthca_update_rate(to_mdev(ibdev), port_num); |
| 118 | update_sm_ah(to_mdev(ibdev), port_num, | 121 | update_sm_ah(to_mdev(ibdev), port_num, |
| 119 | be16_to_cpup((__be16 *) (mad->data + 58)), | 122 | be16_to_cpu(pinfo->lid), |
| 120 | (*(u8 *) (mad->data + 76)) & 0xf); | 123 | pinfo->neighbormtu_mastersmsl & 0xf); |
| 121 | 124 | ||
| 122 | event.device = ibdev; | 125 | event.device = ibdev; |
| 123 | event.event = IB_EVENT_LID_CHANGE; | ||
| 124 | event.element.port_num = port_num; | 126 | event.element.port_num = port_num; |
| 127 | |||
| 128 | if(pinfo->clientrereg_resv_subnetto & 0x80) | ||
| 129 | event.event = IB_EVENT_CLIENT_REREGISTER; | ||
| 130 | else | ||
| 131 | event.event = IB_EVENT_LID_CHANGE; | ||
| 132 | |||
| 125 | ib_dispatch_event(&event); | 133 | ib_dispatch_event(&event); |
| 126 | } | 134 | } |
| 127 | 135 | ||
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index a2eae8a30167..230ae21db8fd 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c | |||
| @@ -115,6 +115,16 @@ static int mthca_query_device(struct ib_device *ibdev, | |||
| 115 | props->max_mcast_qp_attach = MTHCA_QP_PER_MGM; | 115 | props->max_mcast_qp_attach = MTHCA_QP_PER_MGM; |
| 116 | props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * | 116 | props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * |
| 117 | props->max_mcast_grp; | 117 | props->max_mcast_grp; |
| 118 | /* | ||
| 119 | * If Sinai memory key optimization is being used, then only | ||
| 120 | * the 8-bit key portion will change. For other HCAs, the | ||
| 121 | * unused index bits will also be used for FMR remapping. | ||
| 122 | */ | ||
| 123 | if (mdev->mthca_flags & MTHCA_FLAG_SINAI_OPT) | ||
| 124 | props->max_map_per_fmr = 255; | ||
| 125 | else | ||
| 126 | props->max_map_per_fmr = | ||
| 127 | (1 << (32 - long_log2(mdev->limits.num_mpts))) - 1; | ||
| 118 | 128 | ||
| 119 | err = 0; | 129 | err = 0; |
| 120 | out: | 130 | out: |
| @@ -783,18 +793,24 @@ static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *uda | |||
| 783 | if (entries < 1 || entries > dev->limits.max_cqes) | 793 | if (entries < 1 || entries > dev->limits.max_cqes) |
| 784 | return -EINVAL; | 794 | return -EINVAL; |
| 785 | 795 | ||
| 796 | mutex_lock(&cq->mutex); | ||
| 797 | |||
| 786 | entries = roundup_pow_of_two(entries + 1); | 798 | entries = roundup_pow_of_two(entries + 1); |
| 787 | if (entries == ibcq->cqe + 1) | 799 | if (entries == ibcq->cqe + 1) { |
| 788 | return 0; | 800 | ret = 0; |
| 801 | goto out; | ||
| 802 | } | ||
| 789 | 803 | ||
| 790 | if (cq->is_kernel) { | 804 | if (cq->is_kernel) { |
| 791 | ret = mthca_alloc_resize_buf(dev, cq, entries); | 805 | ret = mthca_alloc_resize_buf(dev, cq, entries); |
| 792 | if (ret) | 806 | if (ret) |
| 793 | return ret; | 807 | goto out; |
| 794 | lkey = cq->resize_buf->buf.mr.ibmr.lkey; | 808 | lkey = cq->resize_buf->buf.mr.ibmr.lkey; |
| 795 | } else { | 809 | } else { |
| 796 | if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) | 810 | if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) { |
| 797 | return -EFAULT; | 811 | ret = -EFAULT; |
| 812 | goto out; | ||
| 813 | } | ||
| 798 | lkey = ucmd.lkey; | 814 | lkey = ucmd.lkey; |
| 799 | } | 815 | } |
| 800 | 816 | ||
| @@ -811,7 +827,7 @@ static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *uda | |||
| 811 | cq->resize_buf = NULL; | 827 | cq->resize_buf = NULL; |
| 812 | spin_unlock_irq(&cq->lock); | 828 | spin_unlock_irq(&cq->lock); |
| 813 | } | 829 | } |
| 814 | return ret; | 830 | goto out; |
| 815 | } | 831 | } |
| 816 | 832 | ||
| 817 | if (cq->is_kernel) { | 833 | if (cq->is_kernel) { |
| @@ -838,7 +854,10 @@ static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *uda | |||
| 838 | } else | 854 | } else |
| 839 | ibcq->cqe = entries - 1; | 855 | ibcq->cqe = entries - 1; |
| 840 | 856 | ||
| 841 | return 0; | 857 | out: |
| 858 | mutex_unlock(&cq->mutex); | ||
| 859 | |||
| 860 | return ret; | ||
| 842 | } | 861 | } |
| 843 | 862 | ||
| 844 | static int mthca_destroy_cq(struct ib_cq *cq) | 863 | static int mthca_destroy_cq(struct ib_cq *cq) |
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index 179a8f610d0f..8de2887ba15c 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h | |||
| @@ -214,6 +214,7 @@ struct mthca_cq { | |||
| 214 | int arm_sn; | 214 | int arm_sn; |
| 215 | 215 | ||
| 216 | wait_queue_head_t wait; | 216 | wait_queue_head_t wait; |
| 217 | struct mutex mutex; | ||
| 217 | }; | 218 | }; |
| 218 | 219 | ||
| 219 | struct mthca_srq { | 220 | struct mthca_srq { |
| @@ -237,6 +238,7 @@ struct mthca_srq { | |||
| 237 | struct mthca_mr mr; | 238 | struct mthca_mr mr; |
| 238 | 239 | ||
| 239 | wait_queue_head_t wait; | 240 | wait_queue_head_t wait; |
| 241 | struct mutex mutex; | ||
| 240 | }; | 242 | }; |
| 241 | 243 | ||
| 242 | struct mthca_wq { | 244 | struct mthca_wq { |
| @@ -278,6 +280,7 @@ struct mthca_qp { | |||
| 278 | union mthca_buf queue; | 280 | union mthca_buf queue; |
| 279 | 281 | ||
| 280 | wait_queue_head_t wait; | 282 | wait_queue_head_t wait; |
| 283 | struct mutex mutex; | ||
| 281 | }; | 284 | }; |
| 282 | 285 | ||
| 283 | struct mthca_sqp { | 286 | struct mthca_sqp { |
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 07c13be07a4a..16c387d8170c 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c | |||
| @@ -534,7 +534,9 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) | |||
| 534 | struct mthca_qp_context *qp_context; | 534 | struct mthca_qp_context *qp_context; |
| 535 | u32 sqd_event = 0; | 535 | u32 sqd_event = 0; |
| 536 | u8 status; | 536 | u8 status; |
| 537 | int err; | 537 | int err = -EINVAL; |
| 538 | |||
| 539 | mutex_lock(&qp->mutex); | ||
| 538 | 540 | ||
| 539 | if (attr_mask & IB_QP_CUR_STATE) { | 541 | if (attr_mask & IB_QP_CUR_STATE) { |
| 540 | cur_state = attr->cur_qp_state; | 542 | cur_state = attr->cur_qp_state; |
| @@ -553,39 +555,41 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) | |||
| 553 | "%d->%d with attr 0x%08x\n", | 555 | "%d->%d with attr 0x%08x\n", |
| 554 | qp->transport, cur_state, new_state, | 556 | qp->transport, cur_state, new_state, |
| 555 | attr_mask); | 557 | attr_mask); |
| 556 | return -EINVAL; | 558 | goto out; |
| 557 | } | 559 | } |
| 558 | 560 | ||
| 559 | if ((attr_mask & IB_QP_PKEY_INDEX) && | 561 | if ((attr_mask & IB_QP_PKEY_INDEX) && |
| 560 | attr->pkey_index >= dev->limits.pkey_table_len) { | 562 | attr->pkey_index >= dev->limits.pkey_table_len) { |
| 561 | mthca_dbg(dev, "P_Key index (%u) too large. max is %d\n", | 563 | mthca_dbg(dev, "P_Key index (%u) too large. max is %d\n", |
| 562 | attr->pkey_index, dev->limits.pkey_table_len-1); | 564 | attr->pkey_index, dev->limits.pkey_table_len-1); |
| 563 | return -EINVAL; | 565 | goto out; |
| 564 | } | 566 | } |
| 565 | 567 | ||
| 566 | if ((attr_mask & IB_QP_PORT) && | 568 | if ((attr_mask & IB_QP_PORT) && |
| 567 | (attr->port_num == 0 || attr->port_num > dev->limits.num_ports)) { | 569 | (attr->port_num == 0 || attr->port_num > dev->limits.num_ports)) { |
| 568 | mthca_dbg(dev, "Port number (%u) is invalid\n", attr->port_num); | 570 | mthca_dbg(dev, "Port number (%u) is invalid\n", attr->port_num); |
| 569 | return -EINVAL; | 571 | goto out; |
| 570 | } | 572 | } |
| 571 | 573 | ||
| 572 | if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && | 574 | if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && |
| 573 | attr->max_rd_atomic > dev->limits.max_qp_init_rdma) { | 575 | attr->max_rd_atomic > dev->limits.max_qp_init_rdma) { |
| 574 | mthca_dbg(dev, "Max rdma_atomic as initiator %u too large (max is %d)\n", | 576 | mthca_dbg(dev, "Max rdma_atomic as initiator %u too large (max is %d)\n", |
| 575 | attr->max_rd_atomic, dev->limits.max_qp_init_rdma); | 577 | attr->max_rd_atomic, dev->limits.max_qp_init_rdma); |
| 576 | return -EINVAL; | 578 | goto out; |
| 577 | } | 579 | } |
| 578 | 580 | ||
| 579 | if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && | 581 | if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && |
| 580 | attr->max_dest_rd_atomic > 1 << dev->qp_table.rdb_shift) { | 582 | attr->max_dest_rd_atomic > 1 << dev->qp_table.rdb_shift) { |
| 581 | mthca_dbg(dev, "Max rdma_atomic as responder %u too large (max %d)\n", | 583 | mthca_dbg(dev, "Max rdma_atomic as responder %u too large (max %d)\n", |
| 582 | attr->max_dest_rd_atomic, 1 << dev->qp_table.rdb_shift); | 584 | attr->max_dest_rd_atomic, 1 << dev->qp_table.rdb_shift); |
| 583 | return -EINVAL; | 585 | goto out; |
| 584 | } | 586 | } |
| 585 | 587 | ||
| 586 | mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); | 588 | mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); |
| 587 | if (IS_ERR(mailbox)) | 589 | if (IS_ERR(mailbox)) { |
| 588 | return PTR_ERR(mailbox); | 590 | err = PTR_ERR(mailbox); |
| 591 | goto out; | ||
| 592 | } | ||
| 589 | qp_param = mailbox->buf; | 593 | qp_param = mailbox->buf; |
| 590 | qp_context = &qp_param->context; | 594 | qp_context = &qp_param->context; |
| 591 | memset(qp_param, 0, sizeof *qp_param); | 595 | memset(qp_param, 0, sizeof *qp_param); |
| @@ -618,7 +622,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) | |||
| 618 | if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_2048) { | 622 | if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_2048) { |
| 619 | mthca_dbg(dev, "path MTU (%u) is invalid\n", | 623 | mthca_dbg(dev, "path MTU (%u) is invalid\n", |
| 620 | attr->path_mtu); | 624 | attr->path_mtu); |
| 621 | return -EINVAL; | 625 | goto out_mailbox; |
| 622 | } | 626 | } |
| 623 | qp_context->mtu_msgmax = (attr->path_mtu << 5) | 31; | 627 | qp_context->mtu_msgmax = (attr->path_mtu << 5) | 31; |
| 624 | } | 628 | } |
| @@ -672,7 +676,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) | |||
| 672 | if (attr_mask & IB_QP_AV) { | 676 | if (attr_mask & IB_QP_AV) { |
| 673 | if (mthca_path_set(dev, &attr->ah_attr, &qp_context->pri_path, | 677 | if (mthca_path_set(dev, &attr->ah_attr, &qp_context->pri_path, |
| 674 | attr_mask & IB_QP_PORT ? attr->port_num : qp->port)) | 678 | attr_mask & IB_QP_PORT ? attr->port_num : qp->port)) |
| 675 | return -EINVAL; | 679 | goto out_mailbox; |
| 676 | 680 | ||
| 677 | qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH); | 681 | qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH); |
| 678 | } | 682 | } |
| @@ -686,18 +690,18 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) | |||
| 686 | if (attr->alt_pkey_index >= dev->limits.pkey_table_len) { | 690 | if (attr->alt_pkey_index >= dev->limits.pkey_table_len) { |
| 687 | mthca_dbg(dev, "Alternate P_Key index (%u) too large. max is %d\n", | 691 | mthca_dbg(dev, "Alternate P_Key index (%u) too large. max is %d\n", |
| 688 | attr->alt_pkey_index, dev->limits.pkey_table_len-1); | 692 | attr->alt_pkey_index, dev->limits.pkey_table_len-1); |
| 689 | return -EINVAL; | 693 | goto out_mailbox; |
| 690 | } | 694 | } |
| 691 | 695 | ||
| 692 | if (attr->alt_port_num == 0 || attr->alt_port_num > dev->limits.num_ports) { | 696 | if (attr->alt_port_num == 0 || attr->alt_port_num > dev->limits.num_ports) { |
| 693 | mthca_dbg(dev, "Alternate port number (%u) is invalid\n", | 697 | mthca_dbg(dev, "Alternate port number (%u) is invalid\n", |
| 694 | attr->alt_port_num); | 698 | attr->alt_port_num); |
| 695 | return -EINVAL; | 699 | goto out_mailbox; |
| 696 | } | 700 | } |
| 697 | 701 | ||
| 698 | if (mthca_path_set(dev, &attr->alt_ah_attr, &qp_context->alt_path, | 702 | if (mthca_path_set(dev, &attr->alt_ah_attr, &qp_context->alt_path, |
| 699 | attr->alt_ah_attr.port_num)) | 703 | attr->alt_ah_attr.port_num)) |
| 700 | return -EINVAL; | 704 | goto out_mailbox; |
| 701 | 705 | ||
| 702 | qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index | | 706 | qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index | |
| 703 | attr->alt_port_num << 24); | 707 | attr->alt_port_num << 24); |
| @@ -793,12 +797,12 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) | |||
| 793 | err = mthca_MODIFY_QP(dev, cur_state, new_state, qp->qpn, 0, | 797 | err = mthca_MODIFY_QP(dev, cur_state, new_state, qp->qpn, 0, |
| 794 | mailbox, sqd_event, &status); | 798 | mailbox, sqd_event, &status); |
| 795 | if (err) | 799 | if (err) |
| 796 | goto out; | 800 | goto out_mailbox; |
| 797 | if (status) { | 801 | if (status) { |
| 798 | mthca_warn(dev, "modify QP %d->%d returned status %02x.\n", | 802 | mthca_warn(dev, "modify QP %d->%d returned status %02x.\n", |
| 799 | cur_state, new_state, status); | 803 | cur_state, new_state, status); |
| 800 | err = -EINVAL; | 804 | err = -EINVAL; |
| 801 | goto out; | 805 | goto out_mailbox; |
| 802 | } | 806 | } |
| 803 | 807 | ||
| 804 | qp->state = new_state; | 808 | qp->state = new_state; |
| @@ -853,8 +857,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) | |||
| 853 | } | 857 | } |
| 854 | } | 858 | } |
| 855 | 859 | ||
| 856 | out: | 860 | out_mailbox: |
| 857 | mthca_free_mailbox(dev, mailbox); | 861 | mthca_free_mailbox(dev, mailbox); |
| 862 | |||
| 863 | out: | ||
| 864 | mutex_unlock(&qp->mutex); | ||
| 858 | return err; | 865 | return err; |
| 859 | } | 866 | } |
| 860 | 867 | ||
| @@ -1100,6 +1107,7 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev, | |||
| 1100 | 1107 | ||
| 1101 | qp->refcount = 1; | 1108 | qp->refcount = 1; |
| 1102 | init_waitqueue_head(&qp->wait); | 1109 | init_waitqueue_head(&qp->wait); |
| 1110 | mutex_init(&qp->mutex); | ||
| 1103 | qp->state = IB_QPS_RESET; | 1111 | qp->state = IB_QPS_RESET; |
| 1104 | qp->atomic_rd_en = 0; | 1112 | qp->atomic_rd_en = 0; |
| 1105 | qp->resp_depth = 0; | 1113 | qp->resp_depth = 0; |
diff --git a/drivers/infiniband/hw/mthca/mthca_reset.c b/drivers/infiniband/hw/mthca/mthca_reset.c index df5e494a9d38..f4fddd5327f5 100644 --- a/drivers/infiniband/hw/mthca/mthca_reset.c +++ b/drivers/infiniband/hw/mthca/mthca_reset.c | |||
| @@ -49,6 +49,12 @@ int mthca_reset(struct mthca_dev *mdev) | |||
| 49 | u32 *hca_header = NULL; | 49 | u32 *hca_header = NULL; |
| 50 | u32 *bridge_header = NULL; | 50 | u32 *bridge_header = NULL; |
| 51 | struct pci_dev *bridge = NULL; | 51 | struct pci_dev *bridge = NULL; |
| 52 | int bridge_pcix_cap = 0; | ||
| 53 | int hca_pcie_cap = 0; | ||
| 54 | int hca_pcix_cap = 0; | ||
| 55 | |||
| 56 | u16 devctl; | ||
| 57 | u16 linkctl; | ||
| 52 | 58 | ||
| 53 | #define MTHCA_RESET_OFFSET 0xf0010 | 59 | #define MTHCA_RESET_OFFSET 0xf0010 |
| 54 | #define MTHCA_RESET_VALUE swab32(1) | 60 | #define MTHCA_RESET_VALUE swab32(1) |
| @@ -110,6 +116,9 @@ int mthca_reset(struct mthca_dev *mdev) | |||
| 110 | } | 116 | } |
| 111 | } | 117 | } |
| 112 | 118 | ||
| 119 | hca_pcix_cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX); | ||
| 120 | hca_pcie_cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP); | ||
| 121 | |||
| 113 | if (bridge) { | 122 | if (bridge) { |
| 114 | bridge_header = kmalloc(256, GFP_KERNEL); | 123 | bridge_header = kmalloc(256, GFP_KERNEL); |
| 115 | if (!bridge_header) { | 124 | if (!bridge_header) { |
| @@ -129,6 +138,13 @@ int mthca_reset(struct mthca_dev *mdev) | |||
| 129 | goto out; | 138 | goto out; |
| 130 | } | 139 | } |
| 131 | } | 140 | } |
| 141 | bridge_pcix_cap = pci_find_capability(bridge, PCI_CAP_ID_PCIX); | ||
| 142 | if (!bridge_pcix_cap) { | ||
| 143 | err = -ENODEV; | ||
| 144 | mthca_err(mdev, "Couldn't locate HCA bridge " | ||
| 145 | "PCI-X capability, aborting.\n"); | ||
| 146 | goto out; | ||
| 147 | } | ||
| 132 | } | 148 | } |
| 133 | 149 | ||
| 134 | /* actually hit reset */ | 150 | /* actually hit reset */ |
| @@ -178,6 +194,20 @@ int mthca_reset(struct mthca_dev *mdev) | |||
| 178 | good: | 194 | good: |
| 179 | /* Now restore the PCI headers */ | 195 | /* Now restore the PCI headers */ |
| 180 | if (bridge) { | 196 | if (bridge) { |
| 197 | if (pci_write_config_dword(bridge, bridge_pcix_cap + 0x8, | ||
| 198 | bridge_header[(bridge_pcix_cap + 0x8) / 4])) { | ||
| 199 | err = -ENODEV; | ||
| 200 | mthca_err(mdev, "Couldn't restore HCA bridge Upstream " | ||
| 201 | "split transaction control, aborting.\n"); | ||
| 202 | goto out; | ||
| 203 | } | ||
| 204 | if (pci_write_config_dword(bridge, bridge_pcix_cap + 0xc, | ||
| 205 | bridge_header[(bridge_pcix_cap + 0xc) / 4])) { | ||
| 206 | err = -ENODEV; | ||
| 207 | mthca_err(mdev, "Couldn't restore HCA bridge Downstream " | ||
| 208 | "split transaction control, aborting.\n"); | ||
| 209 | goto out; | ||
| 210 | } | ||
| 181 | /* | 211 | /* |
| 182 | * Bridge control register is at 0x3e, so we'll | 212 | * Bridge control register is at 0x3e, so we'll |
| 183 | * naturally restore it last in this loop. | 213 | * naturally restore it last in this loop. |
| @@ -203,6 +233,35 @@ good: | |||
| 203 | } | 233 | } |
| 204 | } | 234 | } |
| 205 | 235 | ||
| 236 | if (hca_pcix_cap) { | ||
| 237 | if (pci_write_config_dword(mdev->pdev, hca_pcix_cap, | ||
| 238 | hca_header[hca_pcix_cap / 4])) { | ||
| 239 | err = -ENODEV; | ||
| 240 | mthca_err(mdev, "Couldn't restore HCA PCI-X " | ||
| 241 | "command register, aborting.\n"); | ||
| 242 | goto out; | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | if (hca_pcie_cap) { | ||
| 247 | devctl = hca_header[(hca_pcie_cap + PCI_EXP_DEVCTL) / 4]; | ||
| 248 | if (pci_write_config_word(mdev->pdev, hca_pcie_cap + PCI_EXP_DEVCTL, | ||
| 249 | devctl)) { | ||
| 250 | err = -ENODEV; | ||
| 251 | mthca_err(mdev, "Couldn't restore HCA PCI Express " | ||
| 252 | "Device Control register, aborting.\n"); | ||
| 253 | goto out; | ||
| 254 | } | ||
| 255 | linkctl = hca_header[(hca_pcie_cap + PCI_EXP_LNKCTL) / 4]; | ||
| 256 | if (pci_write_config_word(mdev->pdev, hca_pcie_cap + PCI_EXP_LNKCTL, | ||
| 257 | linkctl)) { | ||
| 258 | err = -ENODEV; | ||
| 259 | mthca_err(mdev, "Couldn't restore HCA PCI Express " | ||
| 260 | "Link control register, aborting.\n"); | ||
| 261 | goto out; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 206 | for (i = 0; i < 16; ++i) { | 265 | for (i = 0; i < 16; ++i) { |
| 207 | if (i * 4 == PCI_COMMAND) | 266 | if (i * 4 == PCI_COMMAND) |
| 208 | continue; | 267 | continue; |
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index b292fefa3b41..fab417c5cf43 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c | |||
| @@ -243,6 +243,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, | |||
| 243 | spin_lock_init(&srq->lock); | 243 | spin_lock_init(&srq->lock); |
| 244 | srq->refcount = 1; | 244 | srq->refcount = 1; |
| 245 | init_waitqueue_head(&srq->wait); | 245 | init_waitqueue_head(&srq->wait); |
| 246 | mutex_init(&srq->mutex); | ||
| 246 | 247 | ||
| 247 | if (mthca_is_memfree(dev)) | 248 | if (mthca_is_memfree(dev)) |
| 248 | mthca_arbel_init_srq_context(dev, pd, srq, mailbox->buf); | 249 | mthca_arbel_init_srq_context(dev, pd, srq, mailbox->buf); |
| @@ -371,7 +372,11 @@ int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, | |||
| 371 | if (attr_mask & IB_SRQ_LIMIT) { | 372 | if (attr_mask & IB_SRQ_LIMIT) { |
| 372 | if (attr->srq_limit > srq->max) | 373 | if (attr->srq_limit > srq->max) |
| 373 | return -EINVAL; | 374 | return -EINVAL; |
| 375 | |||
| 376 | mutex_lock(&srq->mutex); | ||
| 374 | ret = mthca_ARM_SRQ(dev, srq->srqn, attr->srq_limit, &status); | 377 | ret = mthca_ARM_SRQ(dev, srq->srqn, attr->srq_limit, &status); |
| 378 | mutex_unlock(&srq->mutex); | ||
| 379 | |||
| 375 | if (ret) | 380 | if (ret) |
| 376 | return ret; | 381 | return ret; |
| 377 | if (status) | 382 | if (status) |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 12a1e0572ef2..491d2afaf5b4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h | |||
| @@ -272,8 +272,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port); | |||
| 272 | void ipoib_dev_cleanup(struct net_device *dev); | 272 | void ipoib_dev_cleanup(struct net_device *dev); |
| 273 | 273 | ||
| 274 | void ipoib_mcast_join_task(void *dev_ptr); | 274 | void ipoib_mcast_join_task(void *dev_ptr); |
| 275 | void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid, | 275 | void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb); |
| 276 | struct sk_buff *skb); | ||
| 277 | 276 | ||
| 278 | void ipoib_mcast_restart_task(void *dev_ptr); | 277 | void ipoib_mcast_restart_task(void *dev_ptr); |
| 279 | int ipoib_mcast_start_thread(struct net_device *dev); | 278 | int ipoib_mcast_start_thread(struct net_device *dev); |
| @@ -369,15 +368,26 @@ extern int ipoib_debug_level; | |||
| 369 | #endif /* CONFIG_INFINIBAND_IPOIB_DEBUG_DATA */ | 368 | #endif /* CONFIG_INFINIBAND_IPOIB_DEBUG_DATA */ |
| 370 | 369 | ||
| 371 | 370 | ||
| 372 | #define IPOIB_GID_FMT "%x:%x:%x:%x:%x:%x:%x:%x" | 371 | #define IPOIB_GID_FMT "%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:" \ |
| 373 | 372 | "%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x" | |
| 374 | #define IPOIB_GID_ARG(gid) be16_to_cpup((__be16 *) ((gid).raw + 0)), \ | 373 | |
| 375 | be16_to_cpup((__be16 *) ((gid).raw + 2)), \ | 374 | #define IPOIB_GID_RAW_ARG(gid) ((u8 *)(gid))[0], \ |
| 376 | be16_to_cpup((__be16 *) ((gid).raw + 4)), \ | 375 | ((u8 *)(gid))[1], \ |
| 377 | be16_to_cpup((__be16 *) ((gid).raw + 6)), \ | 376 | ((u8 *)(gid))[2], \ |
| 378 | be16_to_cpup((__be16 *) ((gid).raw + 8)), \ | 377 | ((u8 *)(gid))[3], \ |
| 379 | be16_to_cpup((__be16 *) ((gid).raw + 10)), \ | 378 | ((u8 *)(gid))[4], \ |
| 380 | be16_to_cpup((__be16 *) ((gid).raw + 12)), \ | 379 | ((u8 *)(gid))[5], \ |
| 381 | be16_to_cpup((__be16 *) ((gid).raw + 14)) | 380 | ((u8 *)(gid))[6], \ |
| 381 | ((u8 *)(gid))[7], \ | ||
| 382 | ((u8 *)(gid))[8], \ | ||
| 383 | ((u8 *)(gid))[9], \ | ||
| 384 | ((u8 *)(gid))[10],\ | ||
| 385 | ((u8 *)(gid))[11],\ | ||
| 386 | ((u8 *)(gid))[12],\ | ||
| 387 | ((u8 *)(gid))[13],\ | ||
| 388 | ((u8 *)(gid))[14],\ | ||
| 389 | ((u8 *)(gid))[15] | ||
| 390 | |||
| 391 | #define IPOIB_GID_ARG(gid) IPOIB_GID_RAW_ARG((gid).raw) | ||
| 382 | 392 | ||
| 383 | #endif /* _IPOIB_H */ | 393 | #endif /* _IPOIB_H */ |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 8406839b91cf..5033666b1481 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c | |||
| @@ -84,15 +84,9 @@ void ipoib_free_ah(struct kref *kref) | |||
| 84 | 84 | ||
| 85 | unsigned long flags; | 85 | unsigned long flags; |
| 86 | 86 | ||
| 87 | if ((int) priv->tx_tail - (int) ah->last_send >= 0) { | 87 | spin_lock_irqsave(&priv->lock, flags); |
| 88 | ipoib_dbg(priv, "Freeing ah %p\n", ah->ah); | 88 | list_add_tail(&ah->list, &priv->dead_ahs); |
| 89 | ib_destroy_ah(ah->ah); | 89 | spin_unlock_irqrestore(&priv->lock, flags); |
| 90 | kfree(ah); | ||
| 91 | } else { | ||
| 92 | spin_lock_irqsave(&priv->lock, flags); | ||
| 93 | list_add_tail(&ah->list, &priv->dead_ahs); | ||
| 94 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 95 | } | ||
| 96 | } | 90 | } |
| 97 | 91 | ||
| 98 | static int ipoib_ib_post_receive(struct net_device *dev, int id) | 92 | static int ipoib_ib_post_receive(struct net_device *dev, int id) |
| @@ -377,19 +371,16 @@ static void __ipoib_reap_ah(struct net_device *dev) | |||
| 377 | struct ipoib_ah *ah, *tah; | 371 | struct ipoib_ah *ah, *tah; |
| 378 | LIST_HEAD(remove_list); | 372 | LIST_HEAD(remove_list); |
| 379 | 373 | ||
| 380 | spin_lock_irq(&priv->lock); | 374 | spin_lock_irq(&priv->tx_lock); |
| 375 | spin_lock(&priv->lock); | ||
| 381 | list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list) | 376 | list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list) |
| 382 | if ((int) priv->tx_tail - (int) ah->last_send >= 0) { | 377 | if ((int) priv->tx_tail - (int) ah->last_send >= 0) { |
| 383 | list_del(&ah->list); | 378 | list_del(&ah->list); |
| 384 | list_add_tail(&ah->list, &remove_list); | 379 | ib_destroy_ah(ah->ah); |
| 380 | kfree(ah); | ||
| 385 | } | 381 | } |
| 386 | spin_unlock_irq(&priv->lock); | 382 | spin_unlock(&priv->lock); |
| 387 | 383 | spin_unlock_irq(&priv->tx_lock); | |
| 388 | list_for_each_entry_safe(ah, tah, &remove_list, list) { | ||
| 389 | ipoib_dbg(priv, "Reaping ah %p\n", ah->ah); | ||
| 390 | ib_destroy_ah(ah->ah); | ||
| 391 | kfree(ah); | ||
| 392 | } | ||
| 393 | } | 384 | } |
| 394 | 385 | ||
| 395 | void ipoib_reap_ah(void *dev_ptr) | 386 | void ipoib_reap_ah(void *dev_ptr) |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index cb078a7d0bf5..1c6ea1c682a5 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c | |||
| @@ -185,8 +185,7 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu) | |||
| 185 | return 0; | 185 | return 0; |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | static struct ipoib_path *__path_find(struct net_device *dev, | 188 | static struct ipoib_path *__path_find(struct net_device *dev, void *gid) |
| 189 | union ib_gid *gid) | ||
| 190 | { | 189 | { |
| 191 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 190 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
| 192 | struct rb_node *n = priv->path_tree.rb_node; | 191 | struct rb_node *n = priv->path_tree.rb_node; |
| @@ -196,7 +195,7 @@ static struct ipoib_path *__path_find(struct net_device *dev, | |||
| 196 | while (n) { | 195 | while (n) { |
| 197 | path = rb_entry(n, struct ipoib_path, rb_node); | 196 | path = rb_entry(n, struct ipoib_path, rb_node); |
| 198 | 197 | ||
| 199 | ret = memcmp(gid->raw, path->pathrec.dgid.raw, | 198 | ret = memcmp(gid, path->pathrec.dgid.raw, |
| 200 | sizeof (union ib_gid)); | 199 | sizeof (union ib_gid)); |
| 201 | 200 | ||
| 202 | if (ret < 0) | 201 | if (ret < 0) |
| @@ -424,8 +423,7 @@ static void path_rec_completion(int status, | |||
| 424 | } | 423 | } |
| 425 | } | 424 | } |
| 426 | 425 | ||
| 427 | static struct ipoib_path *path_rec_create(struct net_device *dev, | 426 | static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid) |
| 428 | union ib_gid *gid) | ||
| 429 | { | 427 | { |
| 430 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 428 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
| 431 | struct ipoib_path *path; | 429 | struct ipoib_path *path; |
| @@ -440,7 +438,7 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, | |||
| 440 | 438 | ||
| 441 | INIT_LIST_HEAD(&path->neigh_list); | 439 | INIT_LIST_HEAD(&path->neigh_list); |
| 442 | 440 | ||
| 443 | memcpy(path->pathrec.dgid.raw, gid->raw, sizeof (union ib_gid)); | 441 | memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid)); |
| 444 | path->pathrec.sgid = priv->local_gid; | 442 | path->pathrec.sgid = priv->local_gid; |
| 445 | path->pathrec.pkey = cpu_to_be16(priv->pkey); | 443 | path->pathrec.pkey = cpu_to_be16(priv->pkey); |
| 446 | path->pathrec.numb_path = 1; | 444 | path->pathrec.numb_path = 1; |
| @@ -498,10 +496,9 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) | |||
| 498 | */ | 496 | */ |
| 499 | spin_lock(&priv->lock); | 497 | spin_lock(&priv->lock); |
| 500 | 498 | ||
| 501 | path = __path_find(dev, (union ib_gid *) (skb->dst->neighbour->ha + 4)); | 499 | path = __path_find(dev, skb->dst->neighbour->ha + 4); |
| 502 | if (!path) { | 500 | if (!path) { |
| 503 | path = path_rec_create(dev, | 501 | path = path_rec_create(dev, skb->dst->neighbour->ha + 4); |
| 504 | (union ib_gid *) (skb->dst->neighbour->ha + 4)); | ||
| 505 | if (!path) | 502 | if (!path) |
| 506 | goto err_path; | 503 | goto err_path; |
| 507 | 504 | ||
| @@ -551,7 +548,7 @@ static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev) | |||
| 551 | /* Add in the P_Key for multicasts */ | 548 | /* Add in the P_Key for multicasts */ |
| 552 | skb->dst->neighbour->ha[8] = (priv->pkey >> 8) & 0xff; | 549 | skb->dst->neighbour->ha[8] = (priv->pkey >> 8) & 0xff; |
| 553 | skb->dst->neighbour->ha[9] = priv->pkey & 0xff; | 550 | skb->dst->neighbour->ha[9] = priv->pkey & 0xff; |
| 554 | ipoib_mcast_send(dev, (union ib_gid *) (skb->dst->neighbour->ha + 4), skb); | 551 | ipoib_mcast_send(dev, skb->dst->neighbour->ha + 4, skb); |
| 555 | } | 552 | } |
| 556 | 553 | ||
| 557 | static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, | 554 | static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, |
| @@ -566,10 +563,9 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, | |||
| 566 | */ | 563 | */ |
| 567 | spin_lock(&priv->lock); | 564 | spin_lock(&priv->lock); |
| 568 | 565 | ||
| 569 | path = __path_find(dev, (union ib_gid *) (phdr->hwaddr + 4)); | 566 | path = __path_find(dev, phdr->hwaddr + 4); |
| 570 | if (!path) { | 567 | if (!path) { |
| 571 | path = path_rec_create(dev, | 568 | path = path_rec_create(dev, phdr->hwaddr + 4); |
| 572 | (union ib_gid *) (phdr->hwaddr + 4)); | ||
| 573 | if (path) { | 569 | if (path) { |
| 574 | /* put pseudoheader back on for next time */ | 570 | /* put pseudoheader back on for next time */ |
| 575 | skb_push(skb, sizeof *phdr); | 571 | skb_push(skb, sizeof *phdr); |
| @@ -660,7 +656,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 660 | phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff; | 656 | phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff; |
| 661 | phdr->hwaddr[9] = priv->pkey & 0xff; | 657 | phdr->hwaddr[9] = priv->pkey & 0xff; |
| 662 | 658 | ||
| 663 | ipoib_mcast_send(dev, (union ib_gid *) (phdr->hwaddr + 4), skb); | 659 | ipoib_mcast_send(dev, phdr->hwaddr + 4, skb); |
| 664 | } else { | 660 | } else { |
| 665 | /* unicast GID -- should be ARP or RARP reply */ | 661 | /* unicast GID -- should be ARP or RARP reply */ |
| 666 | 662 | ||
| @@ -671,7 +667,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 671 | skb->dst ? "neigh" : "dst", | 667 | skb->dst ? "neigh" : "dst", |
| 672 | be16_to_cpup((__be16 *) skb->data), | 668 | be16_to_cpup((__be16 *) skb->data), |
| 673 | be32_to_cpup((__be32 *) phdr->hwaddr), | 669 | be32_to_cpup((__be32 *) phdr->hwaddr), |
| 674 | IPOIB_GID_ARG(*(union ib_gid *) (phdr->hwaddr + 4))); | 670 | IPOIB_GID_RAW_ARG(phdr->hwaddr + 4)); |
| 675 | dev_kfree_skb_any(skb); | 671 | dev_kfree_skb_any(skb); |
| 676 | ++priv->stats.tx_dropped; | 672 | ++priv->stats.tx_dropped; |
| 677 | goto out; | 673 | goto out; |
| @@ -754,7 +750,7 @@ static void ipoib_neigh_destructor(struct neighbour *n) | |||
| 754 | ipoib_dbg(priv, | 750 | ipoib_dbg(priv, |
| 755 | "neigh_destructor for %06x " IPOIB_GID_FMT "\n", | 751 | "neigh_destructor for %06x " IPOIB_GID_FMT "\n", |
| 756 | be32_to_cpup((__be32 *) n->ha), | 752 | be32_to_cpup((__be32 *) n->ha), |
| 757 | IPOIB_GID_ARG(*((union ib_gid *) (n->ha + 4)))); | 753 | IPOIB_GID_RAW_ARG(n->ha + 4)); |
| 758 | 754 | ||
| 759 | spin_lock_irqsave(&priv->lock, flags); | 755 | spin_lock_irqsave(&priv->lock, flags); |
| 760 | 756 | ||
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 1d917edcf9ba..216471fa01cc 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c | |||
| @@ -154,7 +154,7 @@ static struct ipoib_mcast *ipoib_mcast_alloc(struct net_device *dev, | |||
| 154 | return mcast; | 154 | return mcast; |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | static struct ipoib_mcast *__ipoib_mcast_find(struct net_device *dev, union ib_gid *mgid) | 157 | static struct ipoib_mcast *__ipoib_mcast_find(struct net_device *dev, void *mgid) |
| 158 | { | 158 | { |
| 159 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 159 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
| 160 | struct rb_node *n = priv->multicast_tree.rb_node; | 160 | struct rb_node *n = priv->multicast_tree.rb_node; |
| @@ -165,7 +165,7 @@ static struct ipoib_mcast *__ipoib_mcast_find(struct net_device *dev, union ib_g | |||
| 165 | 165 | ||
| 166 | mcast = rb_entry(n, struct ipoib_mcast, rb_node); | 166 | mcast = rb_entry(n, struct ipoib_mcast, rb_node); |
| 167 | 167 | ||
| 168 | ret = memcmp(mgid->raw, mcast->mcmember.mgid.raw, | 168 | ret = memcmp(mgid, mcast->mcmember.mgid.raw, |
| 169 | sizeof (union ib_gid)); | 169 | sizeof (union ib_gid)); |
| 170 | if (ret < 0) | 170 | if (ret < 0) |
| 171 | n = n->rb_left; | 171 | n = n->rb_left; |
| @@ -694,8 +694,7 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast) | |||
| 694 | return 0; | 694 | return 0; |
| 695 | } | 695 | } |
| 696 | 696 | ||
| 697 | void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid, | 697 | void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) |
| 698 | struct sk_buff *skb) | ||
| 699 | { | 698 | { |
| 700 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 699 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
| 701 | struct ipoib_mcast *mcast; | 700 | struct ipoib_mcast *mcast; |
| @@ -718,7 +717,7 @@ void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid, | |||
| 718 | if (!mcast) { | 717 | if (!mcast) { |
| 719 | /* Let's create a new send only group now */ | 718 | /* Let's create a new send only group now */ |
| 720 | ipoib_dbg_mcast(priv, "setting up send only multicast group for " | 719 | ipoib_dbg_mcast(priv, "setting up send only multicast group for " |
| 721 | IPOIB_GID_FMT "\n", IPOIB_GID_ARG(*mgid)); | 720 | IPOIB_GID_FMT "\n", IPOIB_GID_RAW_ARG(mgid)); |
| 722 | 721 | ||
| 723 | mcast = ipoib_mcast_alloc(dev, 0); | 722 | mcast = ipoib_mcast_alloc(dev, 0); |
| 724 | if (!mcast) { | 723 | if (!mcast) { |
| @@ -730,7 +729,7 @@ void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid, | |||
| 730 | } | 729 | } |
| 731 | 730 | ||
| 732 | set_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags); | 731 | set_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags); |
| 733 | mcast->mcmember.mgid = *mgid; | 732 | memcpy(mcast->mcmember.mgid.raw, mgid, sizeof (union ib_gid)); |
| 734 | __ipoib_mcast_add(dev, mcast); | 733 | __ipoib_mcast_add(dev, mcast); |
| 735 | list_add_tail(&mcast->list, &priv->multicast_list); | 734 | list_add_tail(&mcast->list, &priv->multicast_list); |
| 736 | } | 735 | } |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 1d49d1643c59..7b717c648f72 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c | |||
| @@ -255,7 +255,8 @@ void ipoib_event(struct ib_event_handler *handler, | |||
| 255 | record->event == IB_EVENT_PKEY_CHANGE || | 255 | record->event == IB_EVENT_PKEY_CHANGE || |
| 256 | record->event == IB_EVENT_PORT_ACTIVE || | 256 | record->event == IB_EVENT_PORT_ACTIVE || |
| 257 | record->event == IB_EVENT_LID_CHANGE || | 257 | record->event == IB_EVENT_LID_CHANGE || |
| 258 | record->event == IB_EVENT_SM_CHANGE) { | 258 | record->event == IB_EVENT_SM_CHANGE || |
| 259 | record->event == IB_EVENT_CLIENT_REREGISTER) { | ||
| 259 | ipoib_dbg(priv, "Port state change event\n"); | 260 | ipoib_dbg(priv, "Port state change event\n"); |
| 260 | queue_work(ipoib_workqueue, &priv->flush_task); | 261 | queue_work(ipoib_workqueue, &priv->flush_task); |
| 261 | } | 262 | } |
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 9cbdffa08dc2..4e22afef7206 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c | |||
| @@ -62,6 +62,13 @@ MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator " | |||
| 62 | "v" DRV_VERSION " (" DRV_RELDATE ")"); | 62 | "v" DRV_VERSION " (" DRV_RELDATE ")"); |
| 63 | MODULE_LICENSE("Dual BSD/GPL"); | 63 | MODULE_LICENSE("Dual BSD/GPL"); |
| 64 | 64 | ||
| 65 | static int srp_sg_tablesize = SRP_DEF_SG_TABLESIZE; | ||
| 66 | static int srp_max_iu_len; | ||
| 67 | |||
| 68 | module_param(srp_sg_tablesize, int, 0444); | ||
| 69 | MODULE_PARM_DESC(srp_sg_tablesize, | ||
| 70 | "Max number of gather/scatter entries per I/O (default is 12)"); | ||
| 71 | |||
| 65 | static int topspin_workarounds = 1; | 72 | static int topspin_workarounds = 1; |
| 66 | 73 | ||
| 67 | module_param(topspin_workarounds, int, 0444); | 74 | module_param(topspin_workarounds, int, 0444); |
| @@ -105,7 +112,8 @@ static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size, | |||
| 105 | if (!iu->buf) | 112 | if (!iu->buf) |
| 106 | goto out_free_iu; | 113 | goto out_free_iu; |
| 107 | 114 | ||
| 108 | iu->dma = dma_map_single(host->dev->dma_device, iu->buf, size, direction); | 115 | iu->dma = dma_map_single(host->dev->dev->dma_device, |
| 116 | iu->buf, size, direction); | ||
| 109 | if (dma_mapping_error(iu->dma)) | 117 | if (dma_mapping_error(iu->dma)) |
| 110 | goto out_free_buf; | 118 | goto out_free_buf; |
| 111 | 119 | ||
| @@ -127,7 +135,8 @@ static void srp_free_iu(struct srp_host *host, struct srp_iu *iu) | |||
| 127 | if (!iu) | 135 | if (!iu) |
| 128 | return; | 136 | return; |
| 129 | 137 | ||
| 130 | dma_unmap_single(host->dev->dma_device, iu->dma, iu->size, iu->direction); | 138 | dma_unmap_single(host->dev->dev->dma_device, |
| 139 | iu->dma, iu->size, iu->direction); | ||
| 131 | kfree(iu->buf); | 140 | kfree(iu->buf); |
| 132 | kfree(iu); | 141 | kfree(iu); |
| 133 | } | 142 | } |
| @@ -147,7 +156,7 @@ static int srp_init_qp(struct srp_target_port *target, | |||
| 147 | if (!attr) | 156 | if (!attr) |
| 148 | return -ENOMEM; | 157 | return -ENOMEM; |
| 149 | 158 | ||
| 150 | ret = ib_find_cached_pkey(target->srp_host->dev, | 159 | ret = ib_find_cached_pkey(target->srp_host->dev->dev, |
| 151 | target->srp_host->port, | 160 | target->srp_host->port, |
| 152 | be16_to_cpu(target->path.pkey), | 161 | be16_to_cpu(target->path.pkey), |
| 153 | &attr->pkey_index); | 162 | &attr->pkey_index); |
| @@ -179,7 +188,7 @@ static int srp_create_target_ib(struct srp_target_port *target) | |||
| 179 | if (!init_attr) | 188 | if (!init_attr) |
| 180 | return -ENOMEM; | 189 | return -ENOMEM; |
| 181 | 190 | ||
| 182 | target->cq = ib_create_cq(target->srp_host->dev, srp_completion, | 191 | target->cq = ib_create_cq(target->srp_host->dev->dev, srp_completion, |
| 183 | NULL, target, SRP_CQ_SIZE); | 192 | NULL, target, SRP_CQ_SIZE); |
| 184 | if (IS_ERR(target->cq)) { | 193 | if (IS_ERR(target->cq)) { |
| 185 | ret = PTR_ERR(target->cq); | 194 | ret = PTR_ERR(target->cq); |
| @@ -198,7 +207,7 @@ static int srp_create_target_ib(struct srp_target_port *target) | |||
| 198 | init_attr->send_cq = target->cq; | 207 | init_attr->send_cq = target->cq; |
| 199 | init_attr->recv_cq = target->cq; | 208 | init_attr->recv_cq = target->cq; |
| 200 | 209 | ||
| 201 | target->qp = ib_create_qp(target->srp_host->pd, init_attr); | 210 | target->qp = ib_create_qp(target->srp_host->dev->pd, init_attr); |
| 202 | if (IS_ERR(target->qp)) { | 211 | if (IS_ERR(target->qp)) { |
| 203 | ret = PTR_ERR(target->qp); | 212 | ret = PTR_ERR(target->qp); |
| 204 | ib_destroy_cq(target->cq); | 213 | ib_destroy_cq(target->cq); |
| @@ -250,7 +259,7 @@ static int srp_lookup_path(struct srp_target_port *target) | |||
| 250 | 259 | ||
| 251 | init_completion(&target->done); | 260 | init_completion(&target->done); |
| 252 | 261 | ||
| 253 | target->path_query_id = ib_sa_path_rec_get(target->srp_host->dev, | 262 | target->path_query_id = ib_sa_path_rec_get(target->srp_host->dev->dev, |
| 254 | target->srp_host->port, | 263 | target->srp_host->port, |
| 255 | &target->path, | 264 | &target->path, |
| 256 | IB_SA_PATH_REC_DGID | | 265 | IB_SA_PATH_REC_DGID | |
| @@ -309,10 +318,32 @@ static int srp_send_req(struct srp_target_port *target) | |||
| 309 | 318 | ||
| 310 | req->priv.opcode = SRP_LOGIN_REQ; | 319 | req->priv.opcode = SRP_LOGIN_REQ; |
| 311 | req->priv.tag = 0; | 320 | req->priv.tag = 0; |
| 312 | req->priv.req_it_iu_len = cpu_to_be32(SRP_MAX_IU_LEN); | 321 | req->priv.req_it_iu_len = cpu_to_be32(srp_max_iu_len); |
| 313 | req->priv.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | | 322 | req->priv.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | |
| 314 | SRP_BUF_FORMAT_INDIRECT); | 323 | SRP_BUF_FORMAT_INDIRECT); |
| 315 | memcpy(req->priv.initiator_port_id, target->srp_host->initiator_port_id, 16); | 324 | /* |
| 325 | * In the published SRP specification (draft rev. 16a), the | ||
| 326 | * port identifier format is 8 bytes of ID extension followed | ||
| 327 | * by 8 bytes of GUID. Older drafts put the two halves in the | ||
| 328 | * opposite order, so that the GUID comes first. | ||
| 329 | * | ||
| 330 | * Targets conforming to these obsolete drafts can be | ||
| 331 | * recognized by the I/O Class they report. | ||
| 332 | */ | ||
| 333 | if (target->io_class == SRP_REV10_IB_IO_CLASS) { | ||
| 334 | memcpy(req->priv.initiator_port_id, | ||
| 335 | target->srp_host->initiator_port_id + 8, 8); | ||
| 336 | memcpy(req->priv.initiator_port_id + 8, | ||
| 337 | target->srp_host->initiator_port_id, 8); | ||
| 338 | memcpy(req->priv.target_port_id, &target->ioc_guid, 8); | ||
| 339 | memcpy(req->priv.target_port_id + 8, &target->id_ext, 8); | ||
| 340 | } else { | ||
| 341 | memcpy(req->priv.initiator_port_id, | ||
| 342 | target->srp_host->initiator_port_id, 16); | ||
| 343 | memcpy(req->priv.target_port_id, &target->id_ext, 8); | ||
| 344 | memcpy(req->priv.target_port_id + 8, &target->ioc_guid, 8); | ||
| 345 | } | ||
| 346 | |||
| 316 | /* | 347 | /* |
| 317 | * Topspin/Cisco SRP targets will reject our login unless we | 348 | * Topspin/Cisco SRP targets will reject our login unless we |
| 318 | * zero out the first 8 bytes of our initiator port ID. The | 349 | * zero out the first 8 bytes of our initiator port ID. The |
| @@ -325,8 +356,6 @@ static int srp_send_req(struct srp_target_port *target) | |||
| 325 | (unsigned long long) be64_to_cpu(target->ioc_guid)); | 356 | (unsigned long long) be64_to_cpu(target->ioc_guid)); |
| 326 | memset(req->priv.initiator_port_id, 0, 8); | 357 | memset(req->priv.initiator_port_id, 0, 8); |
| 327 | } | 358 | } |
| 328 | memcpy(req->priv.target_port_id, &target->id_ext, 8); | ||
| 329 | memcpy(req->priv.target_port_id + 8, &target->ioc_guid, 8); | ||
| 330 | 359 | ||
| 331 | status = ib_send_cm_req(target->cm_id, &req->param); | 360 | status = ib_send_cm_req(target->cm_id, &req->param); |
| 332 | 361 | ||
| @@ -359,9 +388,9 @@ static void srp_remove_work(void *target_ptr) | |||
| 359 | target->state = SRP_TARGET_REMOVED; | 388 | target->state = SRP_TARGET_REMOVED; |
| 360 | spin_unlock_irq(target->scsi_host->host_lock); | 389 | spin_unlock_irq(target->scsi_host->host_lock); |
| 361 | 390 | ||
| 362 | mutex_lock(&target->srp_host->target_mutex); | 391 | spin_lock(&target->srp_host->target_lock); |
| 363 | list_del(&target->list); | 392 | list_del(&target->list); |
| 364 | mutex_unlock(&target->srp_host->target_mutex); | 393 | spin_unlock(&target->srp_host->target_lock); |
| 365 | 394 | ||
| 366 | scsi_remove_host(target->scsi_host); | 395 | scsi_remove_host(target->scsi_host); |
| 367 | ib_destroy_cm_id(target->cm_id); | 396 | ib_destroy_cm_id(target->cm_id); |
| @@ -421,6 +450,11 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, | |||
| 421 | scmnd->sc_data_direction != DMA_FROM_DEVICE)) | 450 | scmnd->sc_data_direction != DMA_FROM_DEVICE)) |
| 422 | return; | 451 | return; |
| 423 | 452 | ||
| 453 | if (req->fmr) { | ||
| 454 | ib_fmr_pool_unmap(req->fmr); | ||
| 455 | req->fmr = NULL; | ||
| 456 | } | ||
| 457 | |||
| 424 | /* | 458 | /* |
| 425 | * This handling of non-SG commands can be killed when the | 459 | * This handling of non-SG commands can be killed when the |
| 426 | * SCSI midlayer no longer generates non-SG commands. | 460 | * SCSI midlayer no longer generates non-SG commands. |
| @@ -433,18 +467,30 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, | |||
| 433 | scat = &req->fake_sg; | 467 | scat = &req->fake_sg; |
| 434 | } | 468 | } |
| 435 | 469 | ||
| 436 | dma_unmap_sg(target->srp_host->dev->dma_device, scat, nents, | 470 | dma_unmap_sg(target->srp_host->dev->dev->dma_device, scat, nents, |
| 437 | scmnd->sc_data_direction); | 471 | scmnd->sc_data_direction); |
| 438 | } | 472 | } |
| 439 | 473 | ||
| 474 | static void srp_remove_req(struct srp_target_port *target, struct srp_request *req) | ||
| 475 | { | ||
| 476 | srp_unmap_data(req->scmnd, target, req); | ||
| 477 | list_move_tail(&req->list, &target->free_reqs); | ||
| 478 | } | ||
| 479 | |||
| 480 | static void srp_reset_req(struct srp_target_port *target, struct srp_request *req) | ||
| 481 | { | ||
| 482 | req->scmnd->result = DID_RESET << 16; | ||
| 483 | req->scmnd->scsi_done(req->scmnd); | ||
| 484 | srp_remove_req(target, req); | ||
| 485 | } | ||
| 486 | |||
| 440 | static int srp_reconnect_target(struct srp_target_port *target) | 487 | static int srp_reconnect_target(struct srp_target_port *target) |
| 441 | { | 488 | { |
| 442 | struct ib_cm_id *new_cm_id; | 489 | struct ib_cm_id *new_cm_id; |
| 443 | struct ib_qp_attr qp_attr; | 490 | struct ib_qp_attr qp_attr; |
| 444 | struct srp_request *req; | 491 | struct srp_request *req, *tmp; |
| 445 | struct ib_wc wc; | 492 | struct ib_wc wc; |
| 446 | int ret; | 493 | int ret; |
| 447 | int i; | ||
| 448 | 494 | ||
| 449 | spin_lock_irq(target->scsi_host->host_lock); | 495 | spin_lock_irq(target->scsi_host->host_lock); |
| 450 | if (target->state != SRP_TARGET_LIVE) { | 496 | if (target->state != SRP_TARGET_LIVE) { |
| @@ -459,7 +505,7 @@ static int srp_reconnect_target(struct srp_target_port *target) | |||
| 459 | * Now get a new local CM ID so that we avoid confusing the | 505 | * Now get a new local CM ID so that we avoid confusing the |
| 460 | * target in case things are really fouled up. | 506 | * target in case things are really fouled up. |
| 461 | */ | 507 | */ |
| 462 | new_cm_id = ib_create_cm_id(target->srp_host->dev, | 508 | new_cm_id = ib_create_cm_id(target->srp_host->dev->dev, |
| 463 | srp_cm_handler, target); | 509 | srp_cm_handler, target); |
| 464 | if (IS_ERR(new_cm_id)) { | 510 | if (IS_ERR(new_cm_id)) { |
| 465 | ret = PTR_ERR(new_cm_id); | 511 | ret = PTR_ERR(new_cm_id); |
| @@ -480,19 +526,12 @@ static int srp_reconnect_target(struct srp_target_port *target) | |||
| 480 | while (ib_poll_cq(target->cq, 1, &wc) > 0) | 526 | while (ib_poll_cq(target->cq, 1, &wc) > 0) |
| 481 | ; /* nothing */ | 527 | ; /* nothing */ |
| 482 | 528 | ||
| 483 | list_for_each_entry(req, &target->req_queue, list) { | 529 | list_for_each_entry_safe(req, tmp, &target->req_queue, list) |
| 484 | req->scmnd->result = DID_RESET << 16; | 530 | srp_reset_req(target, req); |
| 485 | req->scmnd->scsi_done(req->scmnd); | ||
| 486 | srp_unmap_data(req->scmnd, target, req); | ||
| 487 | } | ||
| 488 | 531 | ||
| 489 | target->rx_head = 0; | 532 | target->rx_head = 0; |
| 490 | target->tx_head = 0; | 533 | target->tx_head = 0; |
| 491 | target->tx_tail = 0; | 534 | target->tx_tail = 0; |
| 492 | INIT_LIST_HEAD(&target->free_reqs); | ||
| 493 | INIT_LIST_HEAD(&target->req_queue); | ||
| 494 | for (i = 0; i < SRP_SQ_SIZE; ++i) | ||
| 495 | list_add_tail(&target->req_ring[i].list, &target->free_reqs); | ||
| 496 | 535 | ||
| 497 | ret = srp_connect_target(target); | 536 | ret = srp_connect_target(target); |
| 498 | if (ret) | 537 | if (ret) |
| @@ -528,14 +567,79 @@ err: | |||
| 528 | return ret; | 567 | return ret; |
| 529 | } | 568 | } |
| 530 | 569 | ||
| 570 | static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat, | ||
| 571 | int sg_cnt, struct srp_request *req, | ||
| 572 | struct srp_direct_buf *buf) | ||
| 573 | { | ||
| 574 | u64 io_addr = 0; | ||
| 575 | u64 *dma_pages; | ||
| 576 | u32 len; | ||
| 577 | int page_cnt; | ||
| 578 | int i, j; | ||
| 579 | int ret; | ||
| 580 | |||
| 581 | if (!dev->fmr_pool) | ||
| 582 | return -ENODEV; | ||
| 583 | |||
| 584 | len = page_cnt = 0; | ||
| 585 | for (i = 0; i < sg_cnt; ++i) { | ||
| 586 | if (sg_dma_address(&scat[i]) & ~dev->fmr_page_mask) { | ||
| 587 | if (i > 0) | ||
| 588 | return -EINVAL; | ||
| 589 | else | ||
| 590 | ++page_cnt; | ||
| 591 | } | ||
| 592 | if ((sg_dma_address(&scat[i]) + sg_dma_len(&scat[i])) & | ||
| 593 | ~dev->fmr_page_mask) { | ||
| 594 | if (i < sg_cnt - 1) | ||
| 595 | return -EINVAL; | ||
| 596 | else | ||
| 597 | ++page_cnt; | ||
| 598 | } | ||
| 599 | |||
| 600 | len += sg_dma_len(&scat[i]); | ||
| 601 | } | ||
| 602 | |||
| 603 | page_cnt += len >> dev->fmr_page_shift; | ||
| 604 | if (page_cnt > SRP_FMR_SIZE) | ||
| 605 | return -ENOMEM; | ||
| 606 | |||
| 607 | dma_pages = kmalloc(sizeof (u64) * page_cnt, GFP_ATOMIC); | ||
| 608 | if (!dma_pages) | ||
| 609 | return -ENOMEM; | ||
| 610 | |||
| 611 | page_cnt = 0; | ||
| 612 | for (i = 0; i < sg_cnt; ++i) | ||
| 613 | for (j = 0; j < sg_dma_len(&scat[i]); j += dev->fmr_page_size) | ||
| 614 | dma_pages[page_cnt++] = | ||
| 615 | (sg_dma_address(&scat[i]) & dev->fmr_page_mask) + j; | ||
| 616 | |||
| 617 | req->fmr = ib_fmr_pool_map_phys(dev->fmr_pool, | ||
| 618 | dma_pages, page_cnt, &io_addr); | ||
| 619 | if (IS_ERR(req->fmr)) { | ||
| 620 | ret = PTR_ERR(req->fmr); | ||
| 621 | goto out; | ||
| 622 | } | ||
| 623 | |||
| 624 | buf->va = cpu_to_be64(sg_dma_address(&scat[0]) & ~dev->fmr_page_mask); | ||
| 625 | buf->key = cpu_to_be32(req->fmr->fmr->rkey); | ||
| 626 | buf->len = cpu_to_be32(len); | ||
| 627 | |||
| 628 | ret = 0; | ||
| 629 | |||
| 630 | out: | ||
| 631 | kfree(dma_pages); | ||
| 632 | |||
| 633 | return ret; | ||
| 634 | } | ||
| 635 | |||
| 531 | static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, | 636 | static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, |
| 532 | struct srp_request *req) | 637 | struct srp_request *req) |
| 533 | { | 638 | { |
| 534 | struct scatterlist *scat; | 639 | struct scatterlist *scat; |
| 535 | struct srp_cmd *cmd = req->cmd->buf; | 640 | struct srp_cmd *cmd = req->cmd->buf; |
| 536 | int len, nents, count; | 641 | int len, nents, count; |
| 537 | int i; | 642 | u8 fmt = SRP_DATA_DESC_DIRECT; |
| 538 | u8 fmt; | ||
| 539 | 643 | ||
| 540 | if (!scmnd->request_buffer || scmnd->sc_data_direction == DMA_NONE) | 644 | if (!scmnd->request_buffer || scmnd->sc_data_direction == DMA_NONE) |
| 541 | return sizeof (struct srp_cmd); | 645 | return sizeof (struct srp_cmd); |
| @@ -560,53 +664,63 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, | |||
| 560 | sg_init_one(scat, scmnd->request_buffer, scmnd->request_bufflen); | 664 | sg_init_one(scat, scmnd->request_buffer, scmnd->request_bufflen); |
| 561 | } | 665 | } |
| 562 | 666 | ||
| 563 | count = dma_map_sg(target->srp_host->dev->dma_device, scat, nents, | 667 | count = dma_map_sg(target->srp_host->dev->dev->dma_device, |
| 564 | scmnd->sc_data_direction); | 668 | scat, nents, scmnd->sc_data_direction); |
| 669 | |||
| 670 | fmt = SRP_DATA_DESC_DIRECT; | ||
| 671 | len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf); | ||
| 565 | 672 | ||
| 566 | if (count == 1) { | 673 | if (count == 1) { |
| 674 | /* | ||
| 675 | * The midlayer only generated a single gather/scatter | ||
| 676 | * entry, or DMA mapping coalesced everything to a | ||
| 677 | * single entry. So a direct descriptor along with | ||
| 678 | * the DMA MR suffices. | ||
| 679 | */ | ||
| 567 | struct srp_direct_buf *buf = (void *) cmd->add_data; | 680 | struct srp_direct_buf *buf = (void *) cmd->add_data; |
| 568 | 681 | ||
| 569 | fmt = SRP_DATA_DESC_DIRECT; | ||
| 570 | |||
| 571 | buf->va = cpu_to_be64(sg_dma_address(scat)); | 682 | buf->va = cpu_to_be64(sg_dma_address(scat)); |
| 572 | buf->key = cpu_to_be32(target->srp_host->mr->rkey); | 683 | buf->key = cpu_to_be32(target->srp_host->dev->mr->rkey); |
| 573 | buf->len = cpu_to_be32(sg_dma_len(scat)); | 684 | buf->len = cpu_to_be32(sg_dma_len(scat)); |
| 574 | 685 | } else if (srp_map_fmr(target->srp_host->dev, scat, count, req, | |
| 575 | len = sizeof (struct srp_cmd) + | 686 | (void *) cmd->add_data)) { |
| 576 | sizeof (struct srp_direct_buf); | 687 | /* |
| 577 | } else { | 688 | * FMR mapping failed, and the scatterlist has more |
| 689 | * than one entry. Generate an indirect memory | ||
| 690 | * descriptor. | ||
| 691 | */ | ||
| 578 | struct srp_indirect_buf *buf = (void *) cmd->add_data; | 692 | struct srp_indirect_buf *buf = (void *) cmd->add_data; |
| 579 | u32 datalen = 0; | 693 | u32 datalen = 0; |
| 694 | int i; | ||
| 580 | 695 | ||
| 581 | fmt = SRP_DATA_DESC_INDIRECT; | 696 | fmt = SRP_DATA_DESC_INDIRECT; |
| 697 | len = sizeof (struct srp_cmd) + | ||
| 698 | sizeof (struct srp_indirect_buf) + | ||
| 699 | count * sizeof (struct srp_direct_buf); | ||
| 700 | |||
| 701 | for (i = 0; i < count; ++i) { | ||
| 702 | buf->desc_list[i].va = | ||
| 703 | cpu_to_be64(sg_dma_address(&scat[i])); | ||
| 704 | buf->desc_list[i].key = | ||
| 705 | cpu_to_be32(target->srp_host->dev->mr->rkey); | ||
| 706 | buf->desc_list[i].len = | ||
| 707 | cpu_to_be32(sg_dma_len(&scat[i])); | ||
| 708 | datalen += sg_dma_len(&scat[i]); | ||
| 709 | } | ||
| 582 | 710 | ||
| 583 | if (scmnd->sc_data_direction == DMA_TO_DEVICE) | 711 | if (scmnd->sc_data_direction == DMA_TO_DEVICE) |
| 584 | cmd->data_out_desc_cnt = count; | 712 | cmd->data_out_desc_cnt = count; |
| 585 | else | 713 | else |
| 586 | cmd->data_in_desc_cnt = count; | 714 | cmd->data_in_desc_cnt = count; |
| 587 | 715 | ||
| 588 | buf->table_desc.va = cpu_to_be64(req->cmd->dma + | 716 | buf->table_desc.va = |
| 589 | sizeof *cmd + | 717 | cpu_to_be64(req->cmd->dma + sizeof *cmd + sizeof *buf); |
| 590 | sizeof *buf); | ||
| 591 | buf->table_desc.key = | 718 | buf->table_desc.key = |
| 592 | cpu_to_be32(target->srp_host->mr->rkey); | 719 | cpu_to_be32(target->srp_host->dev->mr->rkey); |
| 593 | buf->table_desc.len = | 720 | buf->table_desc.len = |
| 594 | cpu_to_be32(count * sizeof (struct srp_direct_buf)); | 721 | cpu_to_be32(count * sizeof (struct srp_direct_buf)); |
| 595 | 722 | ||
| 596 | for (i = 0; i < count; ++i) { | ||
| 597 | buf->desc_list[i].va = cpu_to_be64(sg_dma_address(&scat[i])); | ||
| 598 | buf->desc_list[i].key = | ||
| 599 | cpu_to_be32(target->srp_host->mr->rkey); | ||
| 600 | buf->desc_list[i].len = cpu_to_be32(sg_dma_len(&scat[i])); | ||
| 601 | |||
| 602 | datalen += sg_dma_len(&scat[i]); | ||
| 603 | } | ||
| 604 | |||
| 605 | buf->len = cpu_to_be32(datalen); | 723 | buf->len = cpu_to_be32(datalen); |
| 606 | |||
| 607 | len = sizeof (struct srp_cmd) + | ||
| 608 | sizeof (struct srp_indirect_buf) + | ||
| 609 | count * sizeof (struct srp_direct_buf); | ||
| 610 | } | 724 | } |
| 611 | 725 | ||
| 612 | if (scmnd->sc_data_direction == DMA_TO_DEVICE) | 726 | if (scmnd->sc_data_direction == DMA_TO_DEVICE) |
| @@ -617,12 +731,6 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, | |||
| 617 | return len; | 731 | return len; |
| 618 | } | 732 | } |
| 619 | 733 | ||
| 620 | static void srp_remove_req(struct srp_target_port *target, struct srp_request *req) | ||
| 621 | { | ||
| 622 | srp_unmap_data(req->scmnd, target, req); | ||
| 623 | list_move_tail(&req->list, &target->free_reqs); | ||
| 624 | } | ||
| 625 | |||
| 626 | static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) | 734 | static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) |
| 627 | { | 735 | { |
| 628 | struct srp_request *req; | 736 | struct srp_request *req; |
| @@ -689,7 +797,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) | |||
| 689 | 797 | ||
| 690 | iu = target->rx_ring[wc->wr_id & ~SRP_OP_RECV]; | 798 | iu = target->rx_ring[wc->wr_id & ~SRP_OP_RECV]; |
| 691 | 799 | ||
| 692 | dma_sync_single_for_cpu(target->srp_host->dev->dma_device, iu->dma, | 800 | dma_sync_single_for_cpu(target->srp_host->dev->dev->dma_device, iu->dma, |
| 693 | target->max_ti_iu_len, DMA_FROM_DEVICE); | 801 | target->max_ti_iu_len, DMA_FROM_DEVICE); |
| 694 | 802 | ||
| 695 | opcode = *(u8 *) iu->buf; | 803 | opcode = *(u8 *) iu->buf; |
| @@ -726,7 +834,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) | |||
| 726 | break; | 834 | break; |
| 727 | } | 835 | } |
| 728 | 836 | ||
| 729 | dma_sync_single_for_device(target->srp_host->dev->dma_device, iu->dma, | 837 | dma_sync_single_for_device(target->srp_host->dev->dev->dma_device, iu->dma, |
| 730 | target->max_ti_iu_len, DMA_FROM_DEVICE); | 838 | target->max_ti_iu_len, DMA_FROM_DEVICE); |
| 731 | } | 839 | } |
| 732 | 840 | ||
| @@ -770,7 +878,7 @@ static int __srp_post_recv(struct srp_target_port *target) | |||
| 770 | 878 | ||
| 771 | list.addr = iu->dma; | 879 | list.addr = iu->dma; |
| 772 | list.length = iu->size; | 880 | list.length = iu->size; |
| 773 | list.lkey = target->srp_host->mr->lkey; | 881 | list.lkey = target->srp_host->dev->mr->lkey; |
| 774 | 882 | ||
| 775 | wr.next = NULL; | 883 | wr.next = NULL; |
| 776 | wr.sg_list = &list; | 884 | wr.sg_list = &list; |
| @@ -805,12 +913,8 @@ static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target) | |||
| 805 | if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE) | 913 | if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE) |
| 806 | return NULL; | 914 | return NULL; |
| 807 | 915 | ||
| 808 | if (unlikely(target->req_lim < 1)) { | 916 | if (unlikely(target->req_lim < 1)) |
| 809 | if (printk_ratelimit()) | 917 | ++target->zero_req_lim; |
| 810 | printk(KERN_DEBUG PFX "Target has req_lim %d\n", | ||
| 811 | target->req_lim); | ||
| 812 | return NULL; | ||
| 813 | } | ||
| 814 | 918 | ||
| 815 | return target->tx_ring[target->tx_head & SRP_SQ_SIZE]; | 919 | return target->tx_ring[target->tx_head & SRP_SQ_SIZE]; |
| 816 | } | 920 | } |
| @@ -828,7 +932,7 @@ static int __srp_post_send(struct srp_target_port *target, | |||
| 828 | 932 | ||
| 829 | list.addr = iu->dma; | 933 | list.addr = iu->dma; |
| 830 | list.length = len; | 934 | list.length = len; |
| 831 | list.lkey = target->srp_host->mr->lkey; | 935 | list.lkey = target->srp_host->dev->mr->lkey; |
| 832 | 936 | ||
| 833 | wr.next = NULL; | 937 | wr.next = NULL; |
| 834 | wr.wr_id = target->tx_head & SRP_SQ_SIZE; | 938 | wr.wr_id = target->tx_head & SRP_SQ_SIZE; |
| @@ -870,8 +974,8 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, | |||
| 870 | if (!iu) | 974 | if (!iu) |
| 871 | goto err; | 975 | goto err; |
| 872 | 976 | ||
| 873 | dma_sync_single_for_cpu(target->srp_host->dev->dma_device, iu->dma, | 977 | dma_sync_single_for_cpu(target->srp_host->dev->dev->dma_device, iu->dma, |
| 874 | SRP_MAX_IU_LEN, DMA_TO_DEVICE); | 978 | srp_max_iu_len, DMA_TO_DEVICE); |
| 875 | 979 | ||
| 876 | req = list_entry(target->free_reqs.next, struct srp_request, list); | 980 | req = list_entry(target->free_reqs.next, struct srp_request, list); |
| 877 | 981 | ||
| @@ -903,8 +1007,8 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, | |||
| 903 | goto err_unmap; | 1007 | goto err_unmap; |
| 904 | } | 1008 | } |
| 905 | 1009 | ||
| 906 | dma_sync_single_for_device(target->srp_host->dev->dma_device, iu->dma, | 1010 | dma_sync_single_for_device(target->srp_host->dev->dev->dma_device, iu->dma, |
| 907 | SRP_MAX_IU_LEN, DMA_TO_DEVICE); | 1011 | srp_max_iu_len, DMA_TO_DEVICE); |
| 908 | 1012 | ||
| 909 | if (__srp_post_send(target, iu, len)) { | 1013 | if (__srp_post_send(target, iu, len)) { |
| 910 | printk(KERN_ERR PFX "Send failed\n"); | 1014 | printk(KERN_ERR PFX "Send failed\n"); |
| @@ -936,7 +1040,7 @@ static int srp_alloc_iu_bufs(struct srp_target_port *target) | |||
| 936 | 1040 | ||
| 937 | for (i = 0; i < SRP_SQ_SIZE + 1; ++i) { | 1041 | for (i = 0; i < SRP_SQ_SIZE + 1; ++i) { |
| 938 | target->tx_ring[i] = srp_alloc_iu(target->srp_host, | 1042 | target->tx_ring[i] = srp_alloc_iu(target->srp_host, |
| 939 | SRP_MAX_IU_LEN, | 1043 | srp_max_iu_len, |
| 940 | GFP_KERNEL, DMA_TO_DEVICE); | 1044 | GFP_KERNEL, DMA_TO_DEVICE); |
| 941 | if (!target->tx_ring[i]) | 1045 | if (!target->tx_ring[i]) |
| 942 | goto err; | 1046 | goto err; |
| @@ -1107,11 +1211,10 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) | |||
| 1107 | srp_cm_rej_handler(cm_id, event, target); | 1211 | srp_cm_rej_handler(cm_id, event, target); |
| 1108 | break; | 1212 | break; |
| 1109 | 1213 | ||
| 1110 | case IB_CM_MRA_RECEIVED: | 1214 | case IB_CM_DREQ_RECEIVED: |
| 1111 | printk(KERN_ERR PFX "MRA received\n"); | 1215 | printk(KERN_WARNING PFX "DREQ received - connection closed\n"); |
| 1112 | break; | 1216 | if (ib_send_cm_drep(cm_id, NULL, 0)) |
| 1113 | 1217 | printk(KERN_ERR PFX "Sending CM DREP failed\n"); | |
| 1114 | case IB_CM_DREP_RECEIVED: | ||
| 1115 | break; | 1218 | break; |
| 1116 | 1219 | ||
| 1117 | case IB_CM_TIMEWAIT_EXIT: | 1220 | case IB_CM_TIMEWAIT_EXIT: |
| @@ -1121,6 +1224,11 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) | |||
| 1121 | target->status = 0; | 1224 | target->status = 0; |
| 1122 | break; | 1225 | break; |
| 1123 | 1226 | ||
| 1227 | case IB_CM_MRA_RECEIVED: | ||
| 1228 | case IB_CM_DREQ_ERROR: | ||
| 1229 | case IB_CM_DREP_RECEIVED: | ||
| 1230 | break; | ||
| 1231 | |||
| 1124 | default: | 1232 | default: |
| 1125 | printk(KERN_WARNING PFX "Unhandled CM event %d\n", event->event); | 1233 | printk(KERN_WARNING PFX "Unhandled CM event %d\n", event->event); |
| 1126 | break; | 1234 | break; |
| @@ -1239,11 +1347,8 @@ static int srp_reset_device(struct scsi_cmnd *scmnd) | |||
| 1239 | spin_lock_irq(target->scsi_host->host_lock); | 1347 | spin_lock_irq(target->scsi_host->host_lock); |
| 1240 | 1348 | ||
| 1241 | list_for_each_entry_safe(req, tmp, &target->req_queue, list) | 1349 | list_for_each_entry_safe(req, tmp, &target->req_queue, list) |
| 1242 | if (req->scmnd->device == scmnd->device) { | 1350 | if (req->scmnd->device == scmnd->device) |
| 1243 | req->scmnd->result = DID_RESET << 16; | 1351 | srp_reset_req(target, req); |
| 1244 | req->scmnd->scsi_done(req->scmnd); | ||
| 1245 | srp_remove_req(target, req); | ||
| 1246 | } | ||
| 1247 | 1352 | ||
| 1248 | spin_unlock_irq(target->scsi_host->host_lock); | 1353 | spin_unlock_irq(target->scsi_host->host_lock); |
| 1249 | 1354 | ||
| @@ -1329,11 +1434,23 @@ static ssize_t show_dgid(struct class_device *cdev, char *buf) | |||
| 1329 | be16_to_cpu(((__be16 *) target->path.dgid.raw)[7])); | 1434 | be16_to_cpu(((__be16 *) target->path.dgid.raw)[7])); |
| 1330 | } | 1435 | } |
| 1331 | 1436 | ||
| 1437 | static ssize_t show_zero_req_lim(struct class_device *cdev, char *buf) | ||
| 1438 | { | ||
| 1439 | struct srp_target_port *target = host_to_target(class_to_shost(cdev)); | ||
| 1440 | |||
| 1441 | if (target->state == SRP_TARGET_DEAD || | ||
| 1442 | target->state == SRP_TARGET_REMOVED) | ||
| 1443 | return -ENODEV; | ||
| 1444 | |||
| 1445 | return sprintf(buf, "%d\n", target->zero_req_lim); | ||
| 1446 | } | ||
| 1447 | |||
| 1332 | static CLASS_DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL); | 1448 | static CLASS_DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL); |
| 1333 | static CLASS_DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL); | 1449 | static CLASS_DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL); |
| 1334 | static CLASS_DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL); | 1450 | static CLASS_DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL); |
| 1335 | static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); | 1451 | static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); |
| 1336 | static CLASS_DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL); | 1452 | static CLASS_DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL); |
| 1453 | static CLASS_DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL); | ||
| 1337 | 1454 | ||
| 1338 | static struct class_device_attribute *srp_host_attrs[] = { | 1455 | static struct class_device_attribute *srp_host_attrs[] = { |
| 1339 | &class_device_attr_id_ext, | 1456 | &class_device_attr_id_ext, |
| @@ -1341,6 +1458,7 @@ static struct class_device_attribute *srp_host_attrs[] = { | |||
| 1341 | &class_device_attr_service_id, | 1458 | &class_device_attr_service_id, |
| 1342 | &class_device_attr_pkey, | 1459 | &class_device_attr_pkey, |
| 1343 | &class_device_attr_dgid, | 1460 | &class_device_attr_dgid, |
| 1461 | &class_device_attr_zero_req_lim, | ||
| 1344 | NULL | 1462 | NULL |
| 1345 | }; | 1463 | }; |
| 1346 | 1464 | ||
| @@ -1354,7 +1472,6 @@ static struct scsi_host_template srp_template = { | |||
| 1354 | .eh_host_reset_handler = srp_reset_host, | 1472 | .eh_host_reset_handler = srp_reset_host, |
| 1355 | .can_queue = SRP_SQ_SIZE, | 1473 | .can_queue = SRP_SQ_SIZE, |
| 1356 | .this_id = -1, | 1474 | .this_id = -1, |
| 1357 | .sg_tablesize = SRP_MAX_INDIRECT, | ||
| 1358 | .cmd_per_lun = SRP_SQ_SIZE, | 1475 | .cmd_per_lun = SRP_SQ_SIZE, |
| 1359 | .use_clustering = ENABLE_CLUSTERING, | 1476 | .use_clustering = ENABLE_CLUSTERING, |
| 1360 | .shost_attrs = srp_host_attrs | 1477 | .shost_attrs = srp_host_attrs |
| @@ -1365,18 +1482,17 @@ static int srp_add_target(struct srp_host *host, struct srp_target_port *target) | |||
| 1365 | sprintf(target->target_name, "SRP.T10:%016llX", | 1482 | sprintf(target->target_name, "SRP.T10:%016llX", |
| 1366 | (unsigned long long) be64_to_cpu(target->id_ext)); | 1483 | (unsigned long long) be64_to_cpu(target->id_ext)); |
| 1367 | 1484 | ||
| 1368 | if (scsi_add_host(target->scsi_host, host->dev->dma_device)) | 1485 | if (scsi_add_host(target->scsi_host, host->dev->dev->dma_device)) |
| 1369 | return -ENODEV; | 1486 | return -ENODEV; |
| 1370 | 1487 | ||
| 1371 | mutex_lock(&host->target_mutex); | 1488 | spin_lock(&host->target_lock); |
| 1372 | list_add_tail(&target->list, &host->target_list); | 1489 | list_add_tail(&target->list, &host->target_list); |
| 1373 | mutex_unlock(&host->target_mutex); | 1490 | spin_unlock(&host->target_lock); |
| 1374 | 1491 | ||
| 1375 | target->state = SRP_TARGET_LIVE; | 1492 | target->state = SRP_TARGET_LIVE; |
| 1376 | 1493 | ||
| 1377 | /* XXX: are we supposed to have a definition of SCAN_WILD_CARD ?? */ | ||
| 1378 | scsi_scan_target(&target->scsi_host->shost_gendev, | 1494 | scsi_scan_target(&target->scsi_host->shost_gendev, |
| 1379 | 0, target->scsi_id, ~0, 0); | 1495 | 0, target->scsi_id, SCAN_WILD_CARD, 0); |
| 1380 | 1496 | ||
| 1381 | return 0; | 1497 | return 0; |
| 1382 | } | 1498 | } |
| @@ -1410,6 +1526,8 @@ enum { | |||
| 1410 | SRP_OPT_PKEY = 1 << 3, | 1526 | SRP_OPT_PKEY = 1 << 3, |
| 1411 | SRP_OPT_SERVICE_ID = 1 << 4, | 1527 | SRP_OPT_SERVICE_ID = 1 << 4, |
| 1412 | SRP_OPT_MAX_SECT = 1 << 5, | 1528 | SRP_OPT_MAX_SECT = 1 << 5, |
| 1529 | SRP_OPT_MAX_CMD_PER_LUN = 1 << 6, | ||
| 1530 | SRP_OPT_IO_CLASS = 1 << 7, | ||
| 1413 | SRP_OPT_ALL = (SRP_OPT_ID_EXT | | 1531 | SRP_OPT_ALL = (SRP_OPT_ID_EXT | |
| 1414 | SRP_OPT_IOC_GUID | | 1532 | SRP_OPT_IOC_GUID | |
| 1415 | SRP_OPT_DGID | | 1533 | SRP_OPT_DGID | |
| @@ -1418,13 +1536,15 @@ enum { | |||
| 1418 | }; | 1536 | }; |
| 1419 | 1537 | ||
| 1420 | static match_table_t srp_opt_tokens = { | 1538 | static match_table_t srp_opt_tokens = { |
| 1421 | { SRP_OPT_ID_EXT, "id_ext=%s" }, | 1539 | { SRP_OPT_ID_EXT, "id_ext=%s" }, |
| 1422 | { SRP_OPT_IOC_GUID, "ioc_guid=%s" }, | 1540 | { SRP_OPT_IOC_GUID, "ioc_guid=%s" }, |
| 1423 | { SRP_OPT_DGID, "dgid=%s" }, | 1541 | { SRP_OPT_DGID, "dgid=%s" }, |
| 1424 | { SRP_OPT_PKEY, "pkey=%x" }, | 1542 | { SRP_OPT_PKEY, "pkey=%x" }, |
| 1425 | { SRP_OPT_SERVICE_ID, "service_id=%s" }, | 1543 | { SRP_OPT_SERVICE_ID, "service_id=%s" }, |
| 1426 | { SRP_OPT_MAX_SECT, "max_sect=%d" }, | 1544 | { SRP_OPT_MAX_SECT, "max_sect=%d" }, |
| 1427 | { SRP_OPT_ERR, NULL } | 1545 | { SRP_OPT_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" }, |
| 1546 | { SRP_OPT_IO_CLASS, "io_class=%x" }, | ||
| 1547 | { SRP_OPT_ERR, NULL } | ||
| 1428 | }; | 1548 | }; |
| 1429 | 1549 | ||
| 1430 | static int srp_parse_options(const char *buf, struct srp_target_port *target) | 1550 | static int srp_parse_options(const char *buf, struct srp_target_port *target) |
| @@ -1500,6 +1620,29 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) | |||
| 1500 | target->scsi_host->max_sectors = token; | 1620 | target->scsi_host->max_sectors = token; |
| 1501 | break; | 1621 | break; |
| 1502 | 1622 | ||
| 1623 | case SRP_OPT_MAX_CMD_PER_LUN: | ||
| 1624 | if (match_int(args, &token)) { | ||
| 1625 | printk(KERN_WARNING PFX "bad max cmd_per_lun parameter '%s'\n", p); | ||
| 1626 | goto out; | ||
| 1627 | } | ||
| 1628 | target->scsi_host->cmd_per_lun = min(token, SRP_SQ_SIZE); | ||
| 1629 | break; | ||
| 1630 | |||
| 1631 | case SRP_OPT_IO_CLASS: | ||
| 1632 | if (match_hex(args, &token)) { | ||
| 1633 | printk(KERN_WARNING PFX "bad IO class parameter '%s' \n", p); | ||
| 1634 | goto out; | ||
| 1635 | } | ||
| 1636 | if (token != SRP_REV10_IB_IO_CLASS && | ||
| 1637 | token != SRP_REV16A_IB_IO_CLASS) { | ||
| 1638 | printk(KERN_WARNING PFX "unknown IO class parameter value" | ||
| 1639 | " %x specified (use %x or %x).\n", | ||
| 1640 | token, SRP_REV10_IB_IO_CLASS, SRP_REV16A_IB_IO_CLASS); | ||
| 1641 | goto out; | ||
| 1642 | } | ||
| 1643 | target->io_class = token; | ||
| 1644 | break; | ||
| 1645 | |||
| 1503 | default: | 1646 | default: |
| 1504 | printk(KERN_WARNING PFX "unknown parameter or missing value " | 1647 | printk(KERN_WARNING PFX "unknown parameter or missing value " |
| 1505 | "'%s' in target creation request\n", p); | 1648 | "'%s' in target creation request\n", p); |
| @@ -1542,6 +1685,7 @@ static ssize_t srp_create_target(struct class_device *class_dev, | |||
| 1542 | target = host_to_target(target_host); | 1685 | target = host_to_target(target_host); |
| 1543 | memset(target, 0, sizeof *target); | 1686 | memset(target, 0, sizeof *target); |
| 1544 | 1687 | ||
| 1688 | target->io_class = SRP_REV16A_IB_IO_CLASS; | ||
| 1545 | target->scsi_host = target_host; | 1689 | target->scsi_host = target_host; |
| 1546 | target->srp_host = host; | 1690 | target->srp_host = host; |
| 1547 | 1691 | ||
| @@ -1558,7 +1702,7 @@ static ssize_t srp_create_target(struct class_device *class_dev, | |||
| 1558 | if (ret) | 1702 | if (ret) |
| 1559 | goto err; | 1703 | goto err; |
| 1560 | 1704 | ||
| 1561 | ib_get_cached_gid(host->dev, host->port, 0, &target->path.sgid); | 1705 | ib_get_cached_gid(host->dev->dev, host->port, 0, &target->path.sgid); |
| 1562 | 1706 | ||
| 1563 | printk(KERN_DEBUG PFX "new target: id_ext %016llx ioc_guid %016llx pkey %04x " | 1707 | printk(KERN_DEBUG PFX "new target: id_ext %016llx ioc_guid %016llx pkey %04x " |
| 1564 | "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", | 1708 | "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", |
| @@ -1579,7 +1723,7 @@ static ssize_t srp_create_target(struct class_device *class_dev, | |||
| 1579 | if (ret) | 1723 | if (ret) |
| 1580 | goto err; | 1724 | goto err; |
| 1581 | 1725 | ||
| 1582 | target->cm_id = ib_create_cm_id(host->dev, srp_cm_handler, target); | 1726 | target->cm_id = ib_create_cm_id(host->dev->dev, srp_cm_handler, target); |
| 1583 | if (IS_ERR(target->cm_id)) { | 1727 | if (IS_ERR(target->cm_id)) { |
| 1584 | ret = PTR_ERR(target->cm_id); | 1728 | ret = PTR_ERR(target->cm_id); |
| 1585 | goto err_free; | 1729 | goto err_free; |
| @@ -1619,7 +1763,7 @@ static ssize_t show_ibdev(struct class_device *class_dev, char *buf) | |||
| 1619 | struct srp_host *host = | 1763 | struct srp_host *host = |
| 1620 | container_of(class_dev, struct srp_host, class_dev); | 1764 | container_of(class_dev, struct srp_host, class_dev); |
| 1621 | 1765 | ||
| 1622 | return sprintf(buf, "%s\n", host->dev->name); | 1766 | return sprintf(buf, "%s\n", host->dev->dev->name); |
| 1623 | } | 1767 | } |
| 1624 | 1768 | ||
| 1625 | static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); | 1769 | static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); |
| @@ -1634,7 +1778,7 @@ static ssize_t show_port(struct class_device *class_dev, char *buf) | |||
| 1634 | 1778 | ||
| 1635 | static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL); | 1779 | static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL); |
| 1636 | 1780 | ||
| 1637 | static struct srp_host *srp_add_port(struct ib_device *device, u8 port) | 1781 | static struct srp_host *srp_add_port(struct srp_device *device, u8 port) |
| 1638 | { | 1782 | { |
| 1639 | struct srp_host *host; | 1783 | struct srp_host *host; |
| 1640 | 1784 | ||
| @@ -1643,32 +1787,21 @@ static struct srp_host *srp_add_port(struct ib_device *device, u8 port) | |||
| 1643 | return NULL; | 1787 | return NULL; |
| 1644 | 1788 | ||
| 1645 | INIT_LIST_HEAD(&host->target_list); | 1789 | INIT_LIST_HEAD(&host->target_list); |
| 1646 | mutex_init(&host->target_mutex); | 1790 | spin_lock_init(&host->target_lock); |
| 1647 | init_completion(&host->released); | 1791 | init_completion(&host->released); |
| 1648 | host->dev = device; | 1792 | host->dev = device; |
| 1649 | host->port = port; | 1793 | host->port = port; |
| 1650 | 1794 | ||
| 1651 | host->initiator_port_id[7] = port; | 1795 | host->initiator_port_id[7] = port; |
| 1652 | memcpy(host->initiator_port_id + 8, &device->node_guid, 8); | 1796 | memcpy(host->initiator_port_id + 8, &device->dev->node_guid, 8); |
| 1653 | |||
| 1654 | host->pd = ib_alloc_pd(device); | ||
| 1655 | if (IS_ERR(host->pd)) | ||
| 1656 | goto err_free; | ||
| 1657 | |||
| 1658 | host->mr = ib_get_dma_mr(host->pd, | ||
| 1659 | IB_ACCESS_LOCAL_WRITE | | ||
| 1660 | IB_ACCESS_REMOTE_READ | | ||
| 1661 | IB_ACCESS_REMOTE_WRITE); | ||
| 1662 | if (IS_ERR(host->mr)) | ||
| 1663 | goto err_pd; | ||
| 1664 | 1797 | ||
| 1665 | host->class_dev.class = &srp_class; | 1798 | host->class_dev.class = &srp_class; |
| 1666 | host->class_dev.dev = device->dma_device; | 1799 | host->class_dev.dev = device->dev->dma_device; |
| 1667 | snprintf(host->class_dev.class_id, BUS_ID_SIZE, "srp-%s-%d", | 1800 | snprintf(host->class_dev.class_id, BUS_ID_SIZE, "srp-%s-%d", |
| 1668 | device->name, port); | 1801 | device->dev->name, port); |
| 1669 | 1802 | ||
| 1670 | if (class_device_register(&host->class_dev)) | 1803 | if (class_device_register(&host->class_dev)) |
| 1671 | goto err_mr; | 1804 | goto free_host; |
| 1672 | if (class_device_create_file(&host->class_dev, &class_device_attr_add_target)) | 1805 | if (class_device_create_file(&host->class_dev, &class_device_attr_add_target)) |
| 1673 | goto err_class; | 1806 | goto err_class; |
| 1674 | if (class_device_create_file(&host->class_dev, &class_device_attr_ibdev)) | 1807 | if (class_device_create_file(&host->class_dev, &class_device_attr_ibdev)) |
| @@ -1681,13 +1814,7 @@ static struct srp_host *srp_add_port(struct ib_device *device, u8 port) | |||
| 1681 | err_class: | 1814 | err_class: |
| 1682 | class_device_unregister(&host->class_dev); | 1815 | class_device_unregister(&host->class_dev); |
| 1683 | 1816 | ||
| 1684 | err_mr: | 1817 | free_host: |
| 1685 | ib_dereg_mr(host->mr); | ||
| 1686 | |||
| 1687 | err_pd: | ||
| 1688 | ib_dealloc_pd(host->pd); | ||
| 1689 | |||
| 1690 | err_free: | ||
| 1691 | kfree(host); | 1818 | kfree(host); |
| 1692 | 1819 | ||
| 1693 | return NULL; | 1820 | return NULL; |
| @@ -1695,15 +1822,62 @@ err_free: | |||
| 1695 | 1822 | ||
| 1696 | static void srp_add_one(struct ib_device *device) | 1823 | static void srp_add_one(struct ib_device *device) |
| 1697 | { | 1824 | { |
| 1698 | struct list_head *dev_list; | 1825 | struct srp_device *srp_dev; |
| 1826 | struct ib_device_attr *dev_attr; | ||
| 1827 | struct ib_fmr_pool_param fmr_param; | ||
| 1699 | struct srp_host *host; | 1828 | struct srp_host *host; |
| 1700 | int s, e, p; | 1829 | int s, e, p; |
| 1701 | 1830 | ||
| 1702 | dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL); | 1831 | dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL); |
| 1703 | if (!dev_list) | 1832 | if (!dev_attr) |
| 1704 | return; | 1833 | return; |
| 1705 | 1834 | ||
| 1706 | INIT_LIST_HEAD(dev_list); | 1835 | if (ib_query_device(device, dev_attr)) { |
| 1836 | printk(KERN_WARNING PFX "Query device failed for %s\n", | ||
| 1837 | device->name); | ||
| 1838 | goto free_attr; | ||
| 1839 | } | ||
| 1840 | |||
| 1841 | srp_dev = kmalloc(sizeof *srp_dev, GFP_KERNEL); | ||
| 1842 | if (!srp_dev) | ||
| 1843 | goto free_attr; | ||
| 1844 | |||
| 1845 | /* | ||
| 1846 | * Use the smallest page size supported by the HCA, down to a | ||
| 1847 | * minimum of 512 bytes (which is the smallest sector that a | ||
| 1848 | * SCSI command will ever carry). | ||
| 1849 | */ | ||
| 1850 | srp_dev->fmr_page_shift = max(9, ffs(dev_attr->page_size_cap) - 1); | ||
| 1851 | srp_dev->fmr_page_size = 1 << srp_dev->fmr_page_shift; | ||
| 1852 | srp_dev->fmr_page_mask = ~((unsigned long) srp_dev->fmr_page_size - 1); | ||
| 1853 | |||
| 1854 | INIT_LIST_HEAD(&srp_dev->dev_list); | ||
| 1855 | |||
| 1856 | srp_dev->dev = device; | ||
| 1857 | srp_dev->pd = ib_alloc_pd(device); | ||
| 1858 | if (IS_ERR(srp_dev->pd)) | ||
| 1859 | goto free_dev; | ||
| 1860 | |||
| 1861 | srp_dev->mr = ib_get_dma_mr(srp_dev->pd, | ||
| 1862 | IB_ACCESS_LOCAL_WRITE | | ||
| 1863 | IB_ACCESS_REMOTE_READ | | ||
| 1864 | IB_ACCESS_REMOTE_WRITE); | ||
| 1865 | if (IS_ERR(srp_dev->mr)) | ||
| 1866 | goto err_pd; | ||
| 1867 | |||
| 1868 | memset(&fmr_param, 0, sizeof fmr_param); | ||
| 1869 | fmr_param.pool_size = SRP_FMR_POOL_SIZE; | ||
| 1870 | fmr_param.dirty_watermark = SRP_FMR_DIRTY_SIZE; | ||
| 1871 | fmr_param.cache = 1; | ||
| 1872 | fmr_param.max_pages_per_fmr = SRP_FMR_SIZE; | ||
| 1873 | fmr_param.page_shift = srp_dev->fmr_page_shift; | ||
| 1874 | fmr_param.access = (IB_ACCESS_LOCAL_WRITE | | ||
| 1875 | IB_ACCESS_REMOTE_WRITE | | ||
| 1876 | IB_ACCESS_REMOTE_READ); | ||
| 1877 | |||
| 1878 | srp_dev->fmr_pool = ib_create_fmr_pool(srp_dev->pd, &fmr_param); | ||
| 1879 | if (IS_ERR(srp_dev->fmr_pool)) | ||
| 1880 | srp_dev->fmr_pool = NULL; | ||
| 1707 | 1881 | ||
| 1708 | if (device->node_type == IB_NODE_SWITCH) { | 1882 | if (device->node_type == IB_NODE_SWITCH) { |
| 1709 | s = 0; | 1883 | s = 0; |
| @@ -1714,25 +1888,35 @@ static void srp_add_one(struct ib_device *device) | |||
| 1714 | } | 1888 | } |
| 1715 | 1889 | ||
| 1716 | for (p = s; p <= e; ++p) { | 1890 | for (p = s; p <= e; ++p) { |
| 1717 | host = srp_add_port(device, p); | 1891 | host = srp_add_port(srp_dev, p); |
| 1718 | if (host) | 1892 | if (host) |
| 1719 | list_add_tail(&host->list, dev_list); | 1893 | list_add_tail(&host->list, &srp_dev->dev_list); |
| 1720 | } | 1894 | } |
| 1721 | 1895 | ||
| 1722 | ib_set_client_data(device, &srp_client, dev_list); | 1896 | ib_set_client_data(device, &srp_client, srp_dev); |
| 1897 | |||
| 1898 | goto free_attr; | ||
| 1899 | |||
| 1900 | err_pd: | ||
| 1901 | ib_dealloc_pd(srp_dev->pd); | ||
| 1902 | |||
| 1903 | free_dev: | ||
| 1904 | kfree(srp_dev); | ||
| 1905 | |||
| 1906 | free_attr: | ||
| 1907 | kfree(dev_attr); | ||
| 1723 | } | 1908 | } |
| 1724 | 1909 | ||
| 1725 | static void srp_remove_one(struct ib_device *device) | 1910 | static void srp_remove_one(struct ib_device *device) |
| 1726 | { | 1911 | { |
| 1727 | struct list_head *dev_list; | 1912 | struct srp_device *srp_dev; |
| 1728 | struct srp_host *host, *tmp_host; | 1913 | struct srp_host *host, *tmp_host; |
| 1729 | LIST_HEAD(target_list); | 1914 | LIST_HEAD(target_list); |
| 1730 | struct srp_target_port *target, *tmp_target; | 1915 | struct srp_target_port *target, *tmp_target; |
| 1731 | unsigned long flags; | ||
| 1732 | 1916 | ||
| 1733 | dev_list = ib_get_client_data(device, &srp_client); | 1917 | srp_dev = ib_get_client_data(device, &srp_client); |
| 1734 | 1918 | ||
| 1735 | list_for_each_entry_safe(host, tmp_host, dev_list, list) { | 1919 | list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) { |
| 1736 | class_device_unregister(&host->class_dev); | 1920 | class_device_unregister(&host->class_dev); |
| 1737 | /* | 1921 | /* |
| 1738 | * Wait for the sysfs entry to go away, so that no new | 1922 | * Wait for the sysfs entry to go away, so that no new |
| @@ -1744,15 +1928,13 @@ static void srp_remove_one(struct ib_device *device) | |||
| 1744 | * Mark all target ports as removed, so we stop queueing | 1928 | * Mark all target ports as removed, so we stop queueing |
| 1745 | * commands and don't try to reconnect. | 1929 | * commands and don't try to reconnect. |
| 1746 | */ | 1930 | */ |
| 1747 | mutex_lock(&host->target_mutex); | 1931 | spin_lock(&host->target_lock); |
| 1748 | list_for_each_entry_safe(target, tmp_target, | 1932 | list_for_each_entry(target, &host->target_list, list) { |
| 1749 | &host->target_list, list) { | 1933 | spin_lock_irq(target->scsi_host->host_lock); |
| 1750 | spin_lock_irqsave(target->scsi_host->host_lock, flags); | 1934 | target->state = SRP_TARGET_REMOVED; |
| 1751 | if (target->state != SRP_TARGET_REMOVED) | 1935 | spin_unlock_irq(target->scsi_host->host_lock); |
| 1752 | target->state = SRP_TARGET_REMOVED; | ||
| 1753 | spin_unlock_irqrestore(target->scsi_host->host_lock, flags); | ||
| 1754 | } | 1936 | } |
| 1755 | mutex_unlock(&host->target_mutex); | 1937 | spin_unlock(&host->target_lock); |
| 1756 | 1938 | ||
| 1757 | /* | 1939 | /* |
| 1758 | * Wait for any reconnection tasks that may have | 1940 | * Wait for any reconnection tasks that may have |
| @@ -1770,18 +1952,26 @@ static void srp_remove_one(struct ib_device *device) | |||
| 1770 | scsi_host_put(target->scsi_host); | 1952 | scsi_host_put(target->scsi_host); |
| 1771 | } | 1953 | } |
| 1772 | 1954 | ||
| 1773 | ib_dereg_mr(host->mr); | ||
| 1774 | ib_dealloc_pd(host->pd); | ||
| 1775 | kfree(host); | 1955 | kfree(host); |
| 1776 | } | 1956 | } |
| 1777 | 1957 | ||
| 1778 | kfree(dev_list); | 1958 | if (srp_dev->fmr_pool) |
| 1959 | ib_destroy_fmr_pool(srp_dev->fmr_pool); | ||
| 1960 | ib_dereg_mr(srp_dev->mr); | ||
| 1961 | ib_dealloc_pd(srp_dev->pd); | ||
| 1962 | |||
| 1963 | kfree(srp_dev); | ||
| 1779 | } | 1964 | } |
| 1780 | 1965 | ||
| 1781 | static int __init srp_init_module(void) | 1966 | static int __init srp_init_module(void) |
| 1782 | { | 1967 | { |
| 1783 | int ret; | 1968 | int ret; |
| 1784 | 1969 | ||
| 1970 | srp_template.sg_tablesize = srp_sg_tablesize; | ||
| 1971 | srp_max_iu_len = (sizeof (struct srp_cmd) + | ||
| 1972 | sizeof (struct srp_indirect_buf) + | ||
| 1973 | srp_sg_tablesize * 16); | ||
| 1974 | |||
| 1785 | ret = class_register(&srp_class); | 1975 | ret = class_register(&srp_class); |
| 1786 | if (ret) { | 1976 | if (ret) { |
| 1787 | printk(KERN_ERR PFX "couldn't register class infiniband_srp\n"); | 1977 | printk(KERN_ERR PFX "couldn't register class infiniband_srp\n"); |
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index c5cd43aae860..5b581fb8eb0d 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #include <rdma/ib_verbs.h> | 46 | #include <rdma/ib_verbs.h> |
| 47 | #include <rdma/ib_sa.h> | 47 | #include <rdma/ib_sa.h> |
| 48 | #include <rdma/ib_cm.h> | 48 | #include <rdma/ib_cm.h> |
| 49 | #include <rdma/ib_fmr_pool.h> | ||
| 49 | 50 | ||
| 50 | enum { | 51 | enum { |
| 51 | SRP_PATH_REC_TIMEOUT_MS = 1000, | 52 | SRP_PATH_REC_TIMEOUT_MS = 1000, |
| @@ -55,20 +56,21 @@ enum { | |||
| 55 | SRP_DLID_REDIRECT = 2, | 56 | SRP_DLID_REDIRECT = 2, |
| 56 | 57 | ||
| 57 | SRP_MAX_LUN = 512, | 58 | SRP_MAX_LUN = 512, |
| 58 | SRP_MAX_IU_LEN = 256, | 59 | SRP_DEF_SG_TABLESIZE = 12, |
| 59 | 60 | ||
| 60 | SRP_RQ_SHIFT = 6, | 61 | SRP_RQ_SHIFT = 6, |
| 61 | SRP_RQ_SIZE = 1 << SRP_RQ_SHIFT, | 62 | SRP_RQ_SIZE = 1 << SRP_RQ_SHIFT, |
| 62 | SRP_SQ_SIZE = SRP_RQ_SIZE - 1, | 63 | SRP_SQ_SIZE = SRP_RQ_SIZE - 1, |
| 63 | SRP_CQ_SIZE = SRP_SQ_SIZE + SRP_RQ_SIZE, | 64 | SRP_CQ_SIZE = SRP_SQ_SIZE + SRP_RQ_SIZE, |
| 64 | 65 | ||
| 65 | SRP_TAG_TSK_MGMT = 1 << (SRP_RQ_SHIFT + 1) | 66 | SRP_TAG_TSK_MGMT = 1 << (SRP_RQ_SHIFT + 1), |
| 67 | |||
| 68 | SRP_FMR_SIZE = 256, | ||
| 69 | SRP_FMR_POOL_SIZE = 1024, | ||
| 70 | SRP_FMR_DIRTY_SIZE = SRP_FMR_POOL_SIZE / 4 | ||
| 66 | }; | 71 | }; |
| 67 | 72 | ||
| 68 | #define SRP_OP_RECV (1 << 31) | 73 | #define SRP_OP_RECV (1 << 31) |
| 69 | #define SRP_MAX_INDIRECT ((SRP_MAX_IU_LEN - \ | ||
| 70 | sizeof (struct srp_cmd) - \ | ||
| 71 | sizeof (struct srp_indirect_buf)) / 16) | ||
| 72 | 74 | ||
| 73 | enum srp_target_state { | 75 | enum srp_target_state { |
| 74 | SRP_TARGET_LIVE, | 76 | SRP_TARGET_LIVE, |
| @@ -77,15 +79,24 @@ enum srp_target_state { | |||
| 77 | SRP_TARGET_REMOVED | 79 | SRP_TARGET_REMOVED |
| 78 | }; | 80 | }; |
| 79 | 81 | ||
| 80 | struct srp_host { | 82 | struct srp_device { |
| 81 | u8 initiator_port_id[16]; | 83 | struct list_head dev_list; |
| 82 | struct ib_device *dev; | 84 | struct ib_device *dev; |
| 83 | u8 port; | ||
| 84 | struct ib_pd *pd; | 85 | struct ib_pd *pd; |
| 85 | struct ib_mr *mr; | 86 | struct ib_mr *mr; |
| 87 | struct ib_fmr_pool *fmr_pool; | ||
| 88 | int fmr_page_shift; | ||
| 89 | int fmr_page_size; | ||
| 90 | unsigned long fmr_page_mask; | ||
| 91 | }; | ||
| 92 | |||
| 93 | struct srp_host { | ||
| 94 | u8 initiator_port_id[16]; | ||
| 95 | struct srp_device *dev; | ||
| 96 | u8 port; | ||
| 86 | struct class_device class_dev; | 97 | struct class_device class_dev; |
| 87 | struct list_head target_list; | 98 | struct list_head target_list; |
| 88 | struct mutex target_mutex; | 99 | spinlock_t target_lock; |
| 89 | struct completion released; | 100 | struct completion released; |
| 90 | struct list_head list; | 101 | struct list_head list; |
| 91 | }; | 102 | }; |
| @@ -95,6 +106,7 @@ struct srp_request { | |||
| 95 | struct scsi_cmnd *scmnd; | 106 | struct scsi_cmnd *scmnd; |
| 96 | struct srp_iu *cmd; | 107 | struct srp_iu *cmd; |
| 97 | struct srp_iu *tsk_mgmt; | 108 | struct srp_iu *tsk_mgmt; |
| 109 | struct ib_pool_fmr *fmr; | ||
| 98 | /* | 110 | /* |
| 99 | * Fake scatterlist used when scmnd->use_sg==0. Can be killed | 111 | * Fake scatterlist used when scmnd->use_sg==0. Can be killed |
| 100 | * when the SCSI midlayer no longer generates non-SG commands. | 112 | * when the SCSI midlayer no longer generates non-SG commands. |
| @@ -110,6 +122,7 @@ struct srp_target_port { | |||
| 110 | __be64 id_ext; | 122 | __be64 id_ext; |
| 111 | __be64 ioc_guid; | 123 | __be64 ioc_guid; |
| 112 | __be64 service_id; | 124 | __be64 service_id; |
| 125 | u16 io_class; | ||
| 113 | struct srp_host *srp_host; | 126 | struct srp_host *srp_host; |
| 114 | struct Scsi_Host *scsi_host; | 127 | struct Scsi_Host *scsi_host; |
| 115 | char target_name[32]; | 128 | char target_name[32]; |
| @@ -126,6 +139,8 @@ struct srp_target_port { | |||
| 126 | int max_ti_iu_len; | 139 | int max_ti_iu_len; |
| 127 | s32 req_lim; | 140 | s32 req_lim; |
| 128 | 141 | ||
| 142 | int zero_req_lim; | ||
| 143 | |||
| 129 | unsigned rx_head; | 144 | unsigned rx_head; |
| 130 | struct srp_iu *rx_ring[SRP_RQ_SIZE]; | 145 | struct srp_iu *rx_ring[SRP_RQ_SIZE]; |
| 131 | 146 | ||
