1ec16227eSAndy Grover /* 2ec16227eSAndy Grover * Copyright (c) 2006 Oracle. All rights reserved. 3ec16227eSAndy Grover * 4ec16227eSAndy Grover * This software is available to you under a choice of one of two 5ec16227eSAndy Grover * licenses. You may choose to be licensed under the terms of the GNU 6ec16227eSAndy Grover * General Public License (GPL) Version 2, available from the file 7ec16227eSAndy Grover * COPYING in the main directory of this source tree, or the 8ec16227eSAndy Grover * OpenIB.org BSD license below: 9ec16227eSAndy Grover * 10ec16227eSAndy Grover * Redistribution and use in source and binary forms, with or 11ec16227eSAndy Grover * without modification, are permitted provided that the following 12ec16227eSAndy Grover * conditions are met: 13ec16227eSAndy Grover * 14ec16227eSAndy Grover * - Redistributions of source code must retain the above 15ec16227eSAndy Grover * copyright notice, this list of conditions and the following 16ec16227eSAndy Grover * disclaimer. 17ec16227eSAndy Grover * 18ec16227eSAndy Grover * - Redistributions in binary form must reproduce the above 19ec16227eSAndy Grover * copyright notice, this list of conditions and the following 20ec16227eSAndy Grover * disclaimer in the documentation and/or other materials 21ec16227eSAndy Grover * provided with the distribution. 22ec16227eSAndy Grover * 23ec16227eSAndy Grover * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24ec16227eSAndy Grover * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25ec16227eSAndy Grover * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26ec16227eSAndy Grover * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27ec16227eSAndy Grover * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28ec16227eSAndy Grover * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29ec16227eSAndy Grover * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30ec16227eSAndy Grover * SOFTWARE. 31ec16227eSAndy Grover * 32ec16227eSAndy Grover */ 33ec16227eSAndy Grover #include <linux/kernel.h> 34ec16227eSAndy Grover #include <linux/in.h> 35ec16227eSAndy Grover #include <linux/if.h> 36ec16227eSAndy Grover #include <linux/netdevice.h> 37ec16227eSAndy Grover #include <linux/inetdevice.h> 38ec16227eSAndy Grover #include <linux/if_arp.h> 39ec16227eSAndy Grover #include <linux/delay.h> 405a0e3ad6STejun Heo #include <linux/slab.h> 413a9a231dSPaul Gortmaker #include <linux/module.h> 42ec16227eSAndy Grover 430cb43965SSowmini Varadhan #include "rds_single_path.h" 44ec16227eSAndy Grover #include "rds.h" 45ec16227eSAndy Grover #include "ib.h" 46f6df683fSsantosh.shilimkar@oracle.com #include "ib_mr.h" 47ec16227eSAndy Grover 48*4f7bfb39SZhu Yanjun static unsigned int rds_ib_mr_1m_pool_size = RDS_MR_1M_POOL_SIZE; 49*4f7bfb39SZhu Yanjun static unsigned int rds_ib_mr_8k_pool_size = RDS_MR_8K_POOL_SIZE; 503ba23adeSAndy Grover unsigned int rds_ib_retry_count = RDS_IB_DEFAULT_RETRY_COUNT; 51ec16227eSAndy Grover 52f6df683fSsantosh.shilimkar@oracle.com module_param(rds_ib_mr_1m_pool_size, int, 0444); 53f6df683fSsantosh.shilimkar@oracle.com MODULE_PARM_DESC(rds_ib_mr_1m_pool_size, " Max number of 1M mr per HCA"); 54f6df683fSsantosh.shilimkar@oracle.com module_param(rds_ib_mr_8k_pool_size, int, 0444); 55f6df683fSsantosh.shilimkar@oracle.com MODULE_PARM_DESC(rds_ib_mr_8k_pool_size, " Max number of 8K mr per HCA"); 563ba23adeSAndy Grover module_param(rds_ib_retry_count, int, 0444); 573ba23adeSAndy Grover MODULE_PARM_DESC(rds_ib_retry_count, " Number of hw retries before reporting an error"); 58ec16227eSAndy Grover 59ea819867SZach Brown /* 60ea819867SZach Brown * we have a clumsy combination of RCU and a rwsem protecting this list 61ea819867SZach Brown * because it is used both in the get_mr fast path and while blocking in 62ea819867SZach Brown * the FMR flushing path. 63ea819867SZach Brown */ 64ea819867SZach Brown DECLARE_RWSEM(rds_ib_devices_lock); 65ec16227eSAndy Grover struct list_head rds_ib_devices; 66ec16227eSAndy Grover 67745cbccaSAndy Grover /* NOTE: if also grabbing ibdev lock, grab this first */ 68ec16227eSAndy Grover DEFINE_SPINLOCK(ib_nodev_conns_lock); 69ec16227eSAndy Grover LIST_HEAD(ib_nodev_conns); 70ec16227eSAndy Grover 71ff51bf84Sstephen hemminger static void rds_ib_nodev_connect(void) 72fc19de38SZach Brown { 73fc19de38SZach Brown struct rds_ib_connection *ic; 74fc19de38SZach Brown 75fc19de38SZach Brown spin_lock(&ib_nodev_conns_lock); 76fc19de38SZach Brown list_for_each_entry(ic, &ib_nodev_conns, ib_node) 77fc19de38SZach Brown rds_conn_connect_if_down(ic->conn); 78fc19de38SZach Brown spin_unlock(&ib_nodev_conns_lock); 79fc19de38SZach Brown } 80fc19de38SZach Brown 81ff51bf84Sstephen hemminger static void rds_ib_dev_shutdown(struct rds_ib_device *rds_ibdev) 82fc19de38SZach Brown { 83fc19de38SZach Brown struct rds_ib_connection *ic; 84fc19de38SZach Brown unsigned long flags; 85fc19de38SZach Brown 86fc19de38SZach Brown spin_lock_irqsave(&rds_ibdev->spinlock, flags); 87fc19de38SZach Brown list_for_each_entry(ic, &rds_ibdev->conn_list, ib_node) 88fc19de38SZach Brown rds_conn_drop(ic->conn); 89fc19de38SZach Brown spin_unlock_irqrestore(&rds_ibdev->spinlock, flags); 90fc19de38SZach Brown } 91fc19de38SZach Brown 923e0249f9SZach Brown /* 933e0249f9SZach Brown * rds_ib_destroy_mr_pool() blocks on a few things and mrs drop references 943e0249f9SZach Brown * from interrupt context so we push freing off into a work struct in krdsd. 953e0249f9SZach Brown */ 963e0249f9SZach Brown static void rds_ib_dev_free(struct work_struct *work) 973e0249f9SZach Brown { 983e0249f9SZach Brown struct rds_ib_ipaddr *i_ipaddr, *i_next; 993e0249f9SZach Brown struct rds_ib_device *rds_ibdev = container_of(work, 1003e0249f9SZach Brown struct rds_ib_device, free_work); 1013e0249f9SZach Brown 10206766513SSantosh Shilimkar if (rds_ibdev->mr_8k_pool) 10306766513SSantosh Shilimkar rds_ib_destroy_mr_pool(rds_ibdev->mr_8k_pool); 10406766513SSantosh Shilimkar if (rds_ibdev->mr_1m_pool) 10506766513SSantosh Shilimkar rds_ib_destroy_mr_pool(rds_ibdev->mr_1m_pool); 1063e0249f9SZach Brown if (rds_ibdev->pd) 1073e0249f9SZach Brown ib_dealloc_pd(rds_ibdev->pd); 1083e0249f9SZach Brown 1093e0249f9SZach Brown list_for_each_entry_safe(i_ipaddr, i_next, &rds_ibdev->ipaddr_list, list) { 1103e0249f9SZach Brown list_del(&i_ipaddr->list); 1113e0249f9SZach Brown kfree(i_ipaddr); 1123e0249f9SZach Brown } 1133e0249f9SZach Brown 114be2f76eaSSantosh Shilimkar kfree(rds_ibdev->vector_load); 115be2f76eaSSantosh Shilimkar 1163e0249f9SZach Brown kfree(rds_ibdev); 1173e0249f9SZach Brown } 1183e0249f9SZach Brown 1193e0249f9SZach Brown void rds_ib_dev_put(struct rds_ib_device *rds_ibdev) 1203e0249f9SZach Brown { 1213e0249f9SZach Brown BUG_ON(atomic_read(&rds_ibdev->refcount) <= 0); 1223e0249f9SZach Brown if (atomic_dec_and_test(&rds_ibdev->refcount)) 1233e0249f9SZach Brown queue_work(rds_wq, &rds_ibdev->free_work); 1243e0249f9SZach Brown } 1253e0249f9SZach Brown 126ff51bf84Sstephen hemminger static void rds_ib_add_one(struct ib_device *device) 127ec16227eSAndy Grover { 128ec16227eSAndy Grover struct rds_ib_device *rds_ibdev; 129ec16227eSAndy Grover 130ec16227eSAndy Grover /* Only handle IB (no iWARP) devices */ 131ec16227eSAndy Grover if (device->node_type != RDMA_NODE_IB_CA) 132ec16227eSAndy Grover return; 133ec16227eSAndy Grover 1343e0249f9SZach Brown rds_ibdev = kzalloc_node(sizeof(struct rds_ib_device), GFP_KERNEL, 1353e0249f9SZach Brown ibdev_to_node(device)); 136ec16227eSAndy Grover if (!rds_ibdev) 1370353261cSOr Gerlitz return; 138ec16227eSAndy Grover 139ec16227eSAndy Grover spin_lock_init(&rds_ibdev->spinlock); 1403e0249f9SZach Brown atomic_set(&rds_ibdev->refcount, 1); 1413e0249f9SZach Brown INIT_WORK(&rds_ibdev->free_work, rds_ib_dev_free); 142ec16227eSAndy Grover 1430353261cSOr Gerlitz rds_ibdev->max_wrs = device->attrs.max_qp_wr; 1440353261cSOr Gerlitz rds_ibdev->max_sge = min(device->attrs.max_sge, RDS_IB_MAX_SGE); 145ec16227eSAndy Grover 1462cb2912dSsantosh.shilimkar@oracle.com rds_ibdev->has_fr = (device->attrs.device_cap_flags & 1472cb2912dSsantosh.shilimkar@oracle.com IB_DEVICE_MEM_MGT_EXTENSIONS); 1482cb2912dSsantosh.shilimkar@oracle.com rds_ibdev->has_fmr = (device->alloc_fmr && device->dealloc_fmr && 1492cb2912dSsantosh.shilimkar@oracle.com device->map_phys_fmr && device->unmap_fmr); 1502cb2912dSsantosh.shilimkar@oracle.com rds_ibdev->use_fastreg = (rds_ibdev->has_fr && !rds_ibdev->has_fmr); 1512cb2912dSsantosh.shilimkar@oracle.com 1520353261cSOr Gerlitz rds_ibdev->fmr_max_remaps = device->attrs.max_map_per_fmr?: 32; 153f6df683fSsantosh.shilimkar@oracle.com rds_ibdev->max_1m_mrs = device->attrs.max_mr ? 1540353261cSOr Gerlitz min_t(unsigned int, (device->attrs.max_mr / 2), 155f6df683fSsantosh.shilimkar@oracle.com rds_ib_mr_1m_pool_size) : rds_ib_mr_1m_pool_size; 15606766513SSantosh Shilimkar 157f6df683fSsantosh.shilimkar@oracle.com rds_ibdev->max_8k_mrs = device->attrs.max_mr ? 1580353261cSOr Gerlitz min_t(unsigned int, ((device->attrs.max_mr / 2) * RDS_MR_8K_SCALE), 159f6df683fSsantosh.shilimkar@oracle.com rds_ib_mr_8k_pool_size) : rds_ib_mr_8k_pool_size; 160ec16227eSAndy Grover 1610353261cSOr Gerlitz rds_ibdev->max_initiator_depth = device->attrs.max_qp_init_rd_atom; 1620353261cSOr Gerlitz rds_ibdev->max_responder_resources = device->attrs.max_qp_rd_atom; 16340589e74SAndy Grover 164be2f76eaSSantosh Shilimkar rds_ibdev->vector_load = kzalloc(sizeof(int) * device->num_comp_vectors, 165be2f76eaSSantosh Shilimkar GFP_KERNEL); 166be2f76eaSSantosh Shilimkar if (!rds_ibdev->vector_load) { 167be2f76eaSSantosh Shilimkar pr_err("RDS/IB: %s failed to allocate vector memory\n", 168be2f76eaSSantosh Shilimkar __func__); 169be2f76eaSSantosh Shilimkar goto put_dev; 170be2f76eaSSantosh Shilimkar } 171be2f76eaSSantosh Shilimkar 172ec16227eSAndy Grover rds_ibdev->dev = device; 173ed082d36SChristoph Hellwig rds_ibdev->pd = ib_alloc_pd(device, 0); 1743e0249f9SZach Brown if (IS_ERR(rds_ibdev->pd)) { 1753e0249f9SZach Brown rds_ibdev->pd = NULL; 1763e0249f9SZach Brown goto put_dev; 1773e0249f9SZach Brown } 178ec16227eSAndy Grover 17906766513SSantosh Shilimkar rds_ibdev->mr_1m_pool = 18006766513SSantosh Shilimkar rds_ib_create_mr_pool(rds_ibdev, RDS_IB_MR_1M_POOL); 18106766513SSantosh Shilimkar if (IS_ERR(rds_ibdev->mr_1m_pool)) { 18206766513SSantosh Shilimkar rds_ibdev->mr_1m_pool = NULL; 1833e0249f9SZach Brown goto put_dev; 184ec16227eSAndy Grover } 185ec16227eSAndy Grover 18606766513SSantosh Shilimkar rds_ibdev->mr_8k_pool = 18706766513SSantosh Shilimkar rds_ib_create_mr_pool(rds_ibdev, RDS_IB_MR_8K_POOL); 18806766513SSantosh Shilimkar if (IS_ERR(rds_ibdev->mr_8k_pool)) { 18906766513SSantosh Shilimkar rds_ibdev->mr_8k_pool = NULL; 19006766513SSantosh Shilimkar goto put_dev; 19106766513SSantosh Shilimkar } 19206766513SSantosh Shilimkar 193f6df683fSsantosh.shilimkar@oracle.com rdsdebug("RDS/IB: max_mr = %d, max_wrs = %d, max_sge = %d, fmr_max_remaps = %d, max_1m_mrs = %d, max_8k_mrs = %d\n", 1940353261cSOr Gerlitz device->attrs.max_fmr, rds_ibdev->max_wrs, rds_ibdev->max_sge, 195f6df683fSsantosh.shilimkar@oracle.com rds_ibdev->fmr_max_remaps, rds_ibdev->max_1m_mrs, 196f6df683fSsantosh.shilimkar@oracle.com rds_ibdev->max_8k_mrs); 19706766513SSantosh Shilimkar 1982cb2912dSsantosh.shilimkar@oracle.com pr_info("RDS/IB: %s: %s supported and preferred\n", 1992cb2912dSsantosh.shilimkar@oracle.com device->name, 2002cb2912dSsantosh.shilimkar@oracle.com rds_ibdev->use_fastreg ? "FRMR" : "FMR"); 2012cb2912dSsantosh.shilimkar@oracle.com 202ec16227eSAndy Grover INIT_LIST_HEAD(&rds_ibdev->ipaddr_list); 203ec16227eSAndy Grover INIT_LIST_HEAD(&rds_ibdev->conn_list); 204ea819867SZach Brown 205ea819867SZach Brown down_write(&rds_ib_devices_lock); 206ea819867SZach Brown list_add_tail_rcu(&rds_ibdev->list, &rds_ib_devices); 207ea819867SZach Brown up_write(&rds_ib_devices_lock); 2083e0249f9SZach Brown atomic_inc(&rds_ibdev->refcount); 209ec16227eSAndy Grover 210ec16227eSAndy Grover ib_set_client_data(device, &rds_ib_client, rds_ibdev); 2113e0249f9SZach Brown atomic_inc(&rds_ibdev->refcount); 212ec16227eSAndy Grover 213fc19de38SZach Brown rds_ib_nodev_connect(); 214fc19de38SZach Brown 2153e0249f9SZach Brown put_dev: 2163e0249f9SZach Brown rds_ib_dev_put(rds_ibdev); 217ec16227eSAndy Grover } 218ec16227eSAndy Grover 2193e0249f9SZach Brown /* 2203e0249f9SZach Brown * New connections use this to find the device to associate with the 2213e0249f9SZach Brown * connection. It's not in the fast path so we're not concerned about the 2223e0249f9SZach Brown * performance of the IB call. (As of this writing, it uses an interrupt 2233e0249f9SZach Brown * blocking spinlock to serialize walking a per-device list of all registered 2243e0249f9SZach Brown * clients.) 2253e0249f9SZach Brown * 2263e0249f9SZach Brown * RCU is used to handle incoming connections racing with device teardown. 2273e0249f9SZach Brown * Rather than use a lock to serialize removal from the client_data and 2283e0249f9SZach Brown * getting a new reference, we use an RCU grace period. The destruction 2293e0249f9SZach Brown * path removes the device from client_data and then waits for all RCU 2303e0249f9SZach Brown * readers to finish. 2313e0249f9SZach Brown * 2323e0249f9SZach Brown * A new connection can get NULL from this if its arriving on a 2333e0249f9SZach Brown * device that is in the process of being removed. 2343e0249f9SZach Brown */ 2353e0249f9SZach Brown struct rds_ib_device *rds_ib_get_client_data(struct ib_device *device) 2363e0249f9SZach Brown { 2373e0249f9SZach Brown struct rds_ib_device *rds_ibdev; 2383e0249f9SZach Brown 2393e0249f9SZach Brown rcu_read_lock(); 2403e0249f9SZach Brown rds_ibdev = ib_get_client_data(device, &rds_ib_client); 2413e0249f9SZach Brown if (rds_ibdev) 2423e0249f9SZach Brown atomic_inc(&rds_ibdev->refcount); 2433e0249f9SZach Brown rcu_read_unlock(); 2443e0249f9SZach Brown return rds_ibdev; 2453e0249f9SZach Brown } 2463e0249f9SZach Brown 2473e0249f9SZach Brown /* 2483e0249f9SZach Brown * The IB stack is letting us know that a device is going away. This can 2493e0249f9SZach Brown * happen if the underlying HCA driver is removed or if PCI hotplug is removing 2503e0249f9SZach Brown * the pci function, for example. 2513e0249f9SZach Brown * 2523e0249f9SZach Brown * This can be called at any time and can be racing with any other RDS path. 2533e0249f9SZach Brown */ 2547c1eb45aSHaggai Eran static void rds_ib_remove_one(struct ib_device *device, void *client_data) 255ec16227eSAndy Grover { 2567c1eb45aSHaggai Eran struct rds_ib_device *rds_ibdev = client_data; 257ec16227eSAndy Grover 258ec16227eSAndy Grover if (!rds_ibdev) 259ec16227eSAndy Grover return; 260ec16227eSAndy Grover 261fc19de38SZach Brown rds_ib_dev_shutdown(rds_ibdev); 262ec16227eSAndy Grover 263ea819867SZach Brown /* stop connection attempts from getting a reference to this device. */ 2643e0249f9SZach Brown ib_set_client_data(device, &rds_ib_client, NULL); 265ea819867SZach Brown 266ea819867SZach Brown down_write(&rds_ib_devices_lock); 267ea819867SZach Brown list_del_rcu(&rds_ibdev->list); 268ea819867SZach Brown up_write(&rds_ib_devices_lock); 269ea819867SZach Brown 270ea819867SZach Brown /* 271ea819867SZach Brown * This synchronize rcu is waiting for readers of both the ib 272ea819867SZach Brown * client data and the devices list to finish before we drop 273ea819867SZach Brown * both of those references. 274ea819867SZach Brown */ 2753e0249f9SZach Brown synchronize_rcu(); 2763e0249f9SZach Brown rds_ib_dev_put(rds_ibdev); 2773e0249f9SZach Brown rds_ib_dev_put(rds_ibdev); 278ec16227eSAndy Grover } 279ec16227eSAndy Grover 280ec16227eSAndy Grover struct ib_client rds_ib_client = { 281ec16227eSAndy Grover .name = "rds_ib", 282ec16227eSAndy Grover .add = rds_ib_add_one, 283ec16227eSAndy Grover .remove = rds_ib_remove_one 284ec16227eSAndy Grover }; 285ec16227eSAndy Grover 286ec16227eSAndy Grover static int rds_ib_conn_info_visitor(struct rds_connection *conn, 287ec16227eSAndy Grover void *buffer) 288ec16227eSAndy Grover { 289ec16227eSAndy Grover struct rds_info_rdma_connection *iinfo = buffer; 290ec16227eSAndy Grover struct rds_ib_connection *ic; 291ec16227eSAndy Grover 292ec16227eSAndy Grover /* We will only ever look at IB transports */ 293ec16227eSAndy Grover if (conn->c_trans != &rds_ib_transport) 294ec16227eSAndy Grover return 0; 295ec16227eSAndy Grover 296ec16227eSAndy Grover iinfo->src_addr = conn->c_laddr; 297ec16227eSAndy Grover iinfo->dst_addr = conn->c_faddr; 298ec16227eSAndy Grover 299ec16227eSAndy Grover memset(&iinfo->src_gid, 0, sizeof(iinfo->src_gid)); 300ec16227eSAndy Grover memset(&iinfo->dst_gid, 0, sizeof(iinfo->dst_gid)); 301ec16227eSAndy Grover if (rds_conn_state(conn) == RDS_CONN_UP) { 302ec16227eSAndy Grover struct rds_ib_device *rds_ibdev; 303ec16227eSAndy Grover struct rdma_dev_addr *dev_addr; 304ec16227eSAndy Grover 305ec16227eSAndy Grover ic = conn->c_transport_data; 306ec16227eSAndy Grover dev_addr = &ic->i_cm_id->route.addr.dev_addr; 307ec16227eSAndy Grover 3086f8372b6SSean Hefty rdma_addr_get_sgid(dev_addr, (union ib_gid *) &iinfo->src_gid); 3096f8372b6SSean Hefty rdma_addr_get_dgid(dev_addr, (union ib_gid *) &iinfo->dst_gid); 310ec16227eSAndy Grover 3113e0249f9SZach Brown rds_ibdev = ic->rds_ibdev; 312ec16227eSAndy Grover iinfo->max_send_wr = ic->i_send_ring.w_nr; 313ec16227eSAndy Grover iinfo->max_recv_wr = ic->i_recv_ring.w_nr; 314ec16227eSAndy Grover iinfo->max_send_sge = rds_ibdev->max_sge; 315ec16227eSAndy Grover rds_ib_get_mr_info(rds_ibdev, iinfo); 316ec16227eSAndy Grover } 317ec16227eSAndy Grover return 1; 318ec16227eSAndy Grover } 319ec16227eSAndy Grover 320ec16227eSAndy Grover static void rds_ib_ic_info(struct socket *sock, unsigned int len, 321ec16227eSAndy Grover struct rds_info_iterator *iter, 322ec16227eSAndy Grover struct rds_info_lengths *lens) 323ec16227eSAndy Grover { 324ec16227eSAndy Grover rds_for_each_conn_info(sock, len, iter, lens, 325ec16227eSAndy Grover rds_ib_conn_info_visitor, 326ec16227eSAndy Grover sizeof(struct rds_info_rdma_connection)); 327ec16227eSAndy Grover } 328ec16227eSAndy Grover 329ec16227eSAndy Grover 330ec16227eSAndy Grover /* 331ec16227eSAndy Grover * Early RDS/IB was built to only bind to an address if there is an IPoIB 332ec16227eSAndy Grover * device with that address set. 333ec16227eSAndy Grover * 334ec16227eSAndy Grover * If it were me, I'd advocate for something more flexible. Sending and 335ec16227eSAndy Grover * receiving should be device-agnostic. Transports would try and maintain 336ec16227eSAndy Grover * connections between peers who have messages queued. Userspace would be 337ec16227eSAndy Grover * allowed to influence which paths have priority. We could call userspace 338ec16227eSAndy Grover * asserting this policy "routing". 339ec16227eSAndy Grover */ 340d5a8ac28SSowmini Varadhan static int rds_ib_laddr_check(struct net *net, __be32 addr) 341ec16227eSAndy Grover { 342ec16227eSAndy Grover int ret; 343ec16227eSAndy Grover struct rdma_cm_id *cm_id; 344ec16227eSAndy Grover struct sockaddr_in sin; 345ec16227eSAndy Grover 346ec16227eSAndy Grover /* Create a CMA ID and try to bind it. This catches both 347ec16227eSAndy Grover * IB and iWARP capable NICs. 348ec16227eSAndy Grover */ 349fa20105eSGuy Shapiro cm_id = rdma_create_id(&init_net, NULL, NULL, RDMA_PS_TCP, IB_QPT_RC); 35094713babSDan Carpenter if (IS_ERR(cm_id)) 35194713babSDan Carpenter return PTR_ERR(cm_id); 352ec16227eSAndy Grover 353ec16227eSAndy Grover memset(&sin, 0, sizeof(sin)); 354ec16227eSAndy Grover sin.sin_family = AF_INET; 355ec16227eSAndy Grover sin.sin_addr.s_addr = addr; 356ec16227eSAndy Grover 357ec16227eSAndy Grover /* rdma_bind_addr will only succeed for IB & iWARP devices */ 358ec16227eSAndy Grover ret = rdma_bind_addr(cm_id, (struct sockaddr *)&sin); 359ec16227eSAndy Grover /* due to this, we will claim to support iWARP devices unless we 360ec16227eSAndy Grover check node_type. */ 361c2349758SSasha Levin if (ret || !cm_id->device || 362c2349758SSasha Levin cm_id->device->node_type != RDMA_NODE_IB_CA) 363ec16227eSAndy Grover ret = -EADDRNOTAVAIL; 364ec16227eSAndy Grover 365ec16227eSAndy Grover rdsdebug("addr %pI4 ret %d node type %d\n", 366ec16227eSAndy Grover &addr, ret, 367ec16227eSAndy Grover cm_id->device ? cm_id->device->node_type : -1); 368ec16227eSAndy Grover 369ec16227eSAndy Grover rdma_destroy_id(cm_id); 370ec16227eSAndy Grover 371ec16227eSAndy Grover return ret; 372ec16227eSAndy Grover } 373ec16227eSAndy Grover 37424fa163aSZach Brown static void rds_ib_unregister_client(void) 37524fa163aSZach Brown { 37624fa163aSZach Brown ib_unregister_client(&rds_ib_client); 37724fa163aSZach Brown /* wait for rds_ib_dev_free() to complete */ 37824fa163aSZach Brown flush_workqueue(rds_wq); 37924fa163aSZach Brown } 38024fa163aSZach Brown 381ec16227eSAndy Grover void rds_ib_exit(void) 382ec16227eSAndy Grover { 383ec16227eSAndy Grover rds_info_deregister_func(RDS_INFO_IB_CONNECTIONS, rds_ib_ic_info); 38424fa163aSZach Brown rds_ib_unregister_client(); 3858aeb1ba6SZach Brown rds_ib_destroy_nodev_conns(); 386ec16227eSAndy Grover rds_ib_sysctl_exit(); 387ec16227eSAndy Grover rds_ib_recv_exit(); 388ec16227eSAndy Grover rds_trans_unregister(&rds_ib_transport); 389f6df683fSsantosh.shilimkar@oracle.com rds_ib_mr_exit(); 390ec16227eSAndy Grover } 391ec16227eSAndy Grover 392ec16227eSAndy Grover struct rds_transport rds_ib_transport = { 393ec16227eSAndy Grover .laddr_check = rds_ib_laddr_check, 394226f7a7dSSowmini Varadhan .xmit_path_complete = rds_ib_xmit_path_complete, 395ec16227eSAndy Grover .xmit = rds_ib_xmit, 396ec16227eSAndy Grover .xmit_rdma = rds_ib_xmit_rdma, 39715133f6eSAndy Grover .xmit_atomic = rds_ib_xmit_atomic, 3982da43c4aSSowmini Varadhan .recv_path = rds_ib_recv_path, 399ec16227eSAndy Grover .conn_alloc = rds_ib_conn_alloc, 400ec16227eSAndy Grover .conn_free = rds_ib_conn_free, 401b04e8554SSowmini Varadhan .conn_path_connect = rds_ib_conn_path_connect, 402226f7a7dSSowmini Varadhan .conn_path_shutdown = rds_ib_conn_path_shutdown, 403ec16227eSAndy Grover .inc_copy_to_user = rds_ib_inc_copy_to_user, 404ec16227eSAndy Grover .inc_free = rds_ib_inc_free, 405ec16227eSAndy Grover .cm_initiate_connect = rds_ib_cm_initiate_connect, 406ec16227eSAndy Grover .cm_handle_connect = rds_ib_cm_handle_connect, 407ec16227eSAndy Grover .cm_connect_complete = rds_ib_cm_connect_complete, 408ec16227eSAndy Grover .stats_info_copy = rds_ib_stats_info_copy, 409ec16227eSAndy Grover .exit = rds_ib_exit, 410ec16227eSAndy Grover .get_mr = rds_ib_get_mr, 411ec16227eSAndy Grover .sync_mr = rds_ib_sync_mr, 412ec16227eSAndy Grover .free_mr = rds_ib_free_mr, 413ec16227eSAndy Grover .flush_mrs = rds_ib_flush_mrs, 414ec16227eSAndy Grover .t_owner = THIS_MODULE, 415ec16227eSAndy Grover .t_name = "infiniband", 416335776bdSAndy Grover .t_type = RDS_TRANS_IB 417ec16227eSAndy Grover }; 418ec16227eSAndy Grover 419ef87b7eaSZach Brown int rds_ib_init(void) 420ec16227eSAndy Grover { 421ec16227eSAndy Grover int ret; 422ec16227eSAndy Grover 423ec16227eSAndy Grover INIT_LIST_HEAD(&rds_ib_devices); 424ec16227eSAndy Grover 425f6df683fSsantosh.shilimkar@oracle.com ret = rds_ib_mr_init(); 426515e079dSZach Brown if (ret) 427c534a107STejun Heo goto out; 428515e079dSZach Brown 429ad1d7dc0Ssantosh.shilimkar@oracle.com ret = ib_register_client(&rds_ib_client); 430ad1d7dc0Ssantosh.shilimkar@oracle.com if (ret) 431f6df683fSsantosh.shilimkar@oracle.com goto out_mr_exit; 432ad1d7dc0Ssantosh.shilimkar@oracle.com 433ec16227eSAndy Grover ret = rds_ib_sysctl_init(); 434ec16227eSAndy Grover if (ret) 435ec16227eSAndy Grover goto out_ibreg; 436ec16227eSAndy Grover 437ec16227eSAndy Grover ret = rds_ib_recv_init(); 438ec16227eSAndy Grover if (ret) 439ec16227eSAndy Grover goto out_sysctl; 440ec16227eSAndy Grover 441ec16227eSAndy Grover ret = rds_trans_register(&rds_ib_transport); 442ec16227eSAndy Grover if (ret) 443ec16227eSAndy Grover goto out_recv; 444ec16227eSAndy Grover 445ec16227eSAndy Grover rds_info_register_func(RDS_INFO_IB_CONNECTIONS, rds_ib_ic_info); 446ec16227eSAndy Grover 447ec16227eSAndy Grover goto out; 448ec16227eSAndy Grover 449ec16227eSAndy Grover out_recv: 450ec16227eSAndy Grover rds_ib_recv_exit(); 451ec16227eSAndy Grover out_sysctl: 452ec16227eSAndy Grover rds_ib_sysctl_exit(); 453ec16227eSAndy Grover out_ibreg: 45424fa163aSZach Brown rds_ib_unregister_client(); 455f6df683fSsantosh.shilimkar@oracle.com out_mr_exit: 456f6df683fSsantosh.shilimkar@oracle.com rds_ib_mr_exit(); 457ec16227eSAndy Grover out: 458ec16227eSAndy Grover return ret; 459ec16227eSAndy Grover } 460ec16227eSAndy Grover 461ec16227eSAndy Grover MODULE_LICENSE("GPL"); 462ec16227eSAndy Grover 463