18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2004 Topspin Communications. All rights reserved. 38c2ecf20Sopenharmony_ci * Copyright (c) 2005 Mellanox Technologies. All rights reserved. 48c2ecf20Sopenharmony_ci * Copyright (c) 2004 Voltaire, Inc. All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 78c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 138c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 148c2ecf20Sopenharmony_ci * conditions are met: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 178c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 188c2ecf20Sopenharmony_ci * disclaimer. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 218c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 228c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 238c2ecf20Sopenharmony_ci * provided with the distribution. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 328c2ecf20Sopenharmony_ci * SOFTWARE. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <linux/string.h> 368c2ecf20Sopenharmony_ci#include <linux/slab.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h> 398c2ecf20Sopenharmony_ci#include <rdma/ib_mad.h> 408c2ecf20Sopenharmony_ci#include <rdma/ib_smi.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include "mthca_dev.h" 438c2ecf20Sopenharmony_ci#include "mthca_cmd.h" 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cienum { 468c2ecf20Sopenharmony_ci MTHCA_VENDOR_CLASS1 = 0x9, 478c2ecf20Sopenharmony_ci MTHCA_VENDOR_CLASS2 = 0xa 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int mthca_update_rate(struct mthca_dev *dev, u8 port_num) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct ib_port_attr *tprops = NULL; 538c2ecf20Sopenharmony_ci int ret; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci tprops = kmalloc(sizeof *tprops, GFP_KERNEL); 568c2ecf20Sopenharmony_ci if (!tprops) 578c2ecf20Sopenharmony_ci return -ENOMEM; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci ret = ib_query_port(&dev->ib_dev, port_num, tprops); 608c2ecf20Sopenharmony_ci if (ret) { 618c2ecf20Sopenharmony_ci dev_warn(&dev->ib_dev.dev, 628c2ecf20Sopenharmony_ci "ib_query_port failed (%d) forport %d\n", ret, 638c2ecf20Sopenharmony_ci port_num); 648c2ecf20Sopenharmony_ci goto out; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci dev->rate[port_num - 1] = tprops->active_speed * 688c2ecf20Sopenharmony_ci ib_width_enum_to_int(tprops->active_width); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ciout: 718c2ecf20Sopenharmony_ci kfree(tprops); 728c2ecf20Sopenharmony_ci return ret; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic void update_sm_ah(struct mthca_dev *dev, 768c2ecf20Sopenharmony_ci u8 port_num, u16 lid, u8 sl) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct ib_ah *new_ah; 798c2ecf20Sopenharmony_ci struct rdma_ah_attr ah_attr; 808c2ecf20Sopenharmony_ci unsigned long flags; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (!dev->send_agent[port_num - 1][0]) 838c2ecf20Sopenharmony_ci return; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci memset(&ah_attr, 0, sizeof ah_attr); 868c2ecf20Sopenharmony_ci ah_attr.type = rdma_ah_find_type(&dev->ib_dev, port_num); 878c2ecf20Sopenharmony_ci rdma_ah_set_dlid(&ah_attr, lid); 888c2ecf20Sopenharmony_ci rdma_ah_set_sl(&ah_attr, sl); 898c2ecf20Sopenharmony_ci rdma_ah_set_port_num(&ah_attr, port_num); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci new_ah = rdma_create_ah(dev->send_agent[port_num - 1][0]->qp->pd, 928c2ecf20Sopenharmony_ci &ah_attr, 0); 938c2ecf20Sopenharmony_ci if (IS_ERR(new_ah)) 948c2ecf20Sopenharmony_ci return; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->sm_lock, flags); 978c2ecf20Sopenharmony_ci if (dev->sm_ah[port_num - 1]) 988c2ecf20Sopenharmony_ci rdma_destroy_ah(dev->sm_ah[port_num - 1], 0); 998c2ecf20Sopenharmony_ci dev->sm_ah[port_num - 1] = new_ah; 1008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->sm_lock, flags); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* 1048c2ecf20Sopenharmony_ci * Snoop SM MADs for port info and P_Key table sets, so we can 1058c2ecf20Sopenharmony_ci * synthesize LID change and P_Key change events. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_cistatic void smp_snoop(struct ib_device *ibdev, 1088c2ecf20Sopenharmony_ci u8 port_num, 1098c2ecf20Sopenharmony_ci const struct ib_mad *mad, 1108c2ecf20Sopenharmony_ci u16 prev_lid) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct ib_event event; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 1158c2ecf20Sopenharmony_ci mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 1168c2ecf20Sopenharmony_ci mad->mad_hdr.method == IB_MGMT_METHOD_SET) { 1178c2ecf20Sopenharmony_ci if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) { 1188c2ecf20Sopenharmony_ci struct ib_port_info *pinfo = 1198c2ecf20Sopenharmony_ci (struct ib_port_info *) ((struct ib_smp *) mad)->data; 1208c2ecf20Sopenharmony_ci u16 lid = be16_to_cpu(pinfo->lid); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci mthca_update_rate(to_mdev(ibdev), port_num); 1238c2ecf20Sopenharmony_ci update_sm_ah(to_mdev(ibdev), port_num, 1248c2ecf20Sopenharmony_ci be16_to_cpu(pinfo->sm_lid), 1258c2ecf20Sopenharmony_ci pinfo->neighbormtu_mastersmsl & 0xf); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci event.device = ibdev; 1288c2ecf20Sopenharmony_ci event.element.port_num = port_num; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (pinfo->clientrereg_resv_subnetto & 0x80) { 1318c2ecf20Sopenharmony_ci event.event = IB_EVENT_CLIENT_REREGISTER; 1328c2ecf20Sopenharmony_ci ib_dispatch_event(&event); 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (prev_lid != lid) { 1368c2ecf20Sopenharmony_ci event.event = IB_EVENT_LID_CHANGE; 1378c2ecf20Sopenharmony_ci ib_dispatch_event(&event); 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) { 1428c2ecf20Sopenharmony_ci event.device = ibdev; 1438c2ecf20Sopenharmony_ci event.event = IB_EVENT_PKEY_CHANGE; 1448c2ecf20Sopenharmony_ci event.element.port_num = port_num; 1458c2ecf20Sopenharmony_ci ib_dispatch_event(&event); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic void node_desc_override(struct ib_device *dev, 1518c2ecf20Sopenharmony_ci struct ib_mad *mad) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 1548c2ecf20Sopenharmony_ci mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 1558c2ecf20Sopenharmony_ci mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP && 1568c2ecf20Sopenharmony_ci mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) { 1578c2ecf20Sopenharmony_ci mutex_lock(&to_mdev(dev)->cap_mask_mutex); 1588c2ecf20Sopenharmony_ci memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 1598c2ecf20Sopenharmony_ci IB_DEVICE_NODE_DESC_MAX); 1608c2ecf20Sopenharmony_ci mutex_unlock(&to_mdev(dev)->cap_mask_mutex); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic void forward_trap(struct mthca_dev *dev, 1658c2ecf20Sopenharmony_ci u8 port_num, 1668c2ecf20Sopenharmony_ci const struct ib_mad *mad) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; 1698c2ecf20Sopenharmony_ci struct ib_mad_send_buf *send_buf; 1708c2ecf20Sopenharmony_ci struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; 1718c2ecf20Sopenharmony_ci int ret; 1728c2ecf20Sopenharmony_ci unsigned long flags; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (agent) { 1758c2ecf20Sopenharmony_ci send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, 1768c2ecf20Sopenharmony_ci IB_MGMT_MAD_DATA, GFP_ATOMIC, 1778c2ecf20Sopenharmony_ci IB_MGMT_BASE_VERSION); 1788c2ecf20Sopenharmony_ci if (IS_ERR(send_buf)) 1798c2ecf20Sopenharmony_ci return; 1808c2ecf20Sopenharmony_ci /* 1818c2ecf20Sopenharmony_ci * We rely here on the fact that MLX QPs don't use the 1828c2ecf20Sopenharmony_ci * address handle after the send is posted (this is 1838c2ecf20Sopenharmony_ci * wrong following the IB spec strictly, but we know 1848c2ecf20Sopenharmony_ci * it's OK for our devices). 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->sm_lock, flags); 1878c2ecf20Sopenharmony_ci memcpy(send_buf->mad, mad, sizeof *mad); 1888c2ecf20Sopenharmony_ci if ((send_buf->ah = dev->sm_ah[port_num - 1])) 1898c2ecf20Sopenharmony_ci ret = ib_post_send_mad(send_buf, NULL); 1908c2ecf20Sopenharmony_ci else 1918c2ecf20Sopenharmony_ci ret = -EINVAL; 1928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->sm_lock, flags); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (ret) 1958c2ecf20Sopenharmony_ci ib_free_send_mad(send_buf); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ciint mthca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, 2008c2ecf20Sopenharmony_ci const struct ib_wc *in_wc, const struct ib_grh *in_grh, 2018c2ecf20Sopenharmony_ci const struct ib_mad *in, struct ib_mad *out, 2028c2ecf20Sopenharmony_ci size_t *out_mad_size, u16 *out_mad_pkey_index) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci int err; 2058c2ecf20Sopenharmony_ci u16 slid = in_wc ? ib_lid_cpu16(in_wc->slid) : be16_to_cpu(IB_LID_PERMISSIVE); 2068c2ecf20Sopenharmony_ci u16 prev_lid = 0; 2078c2ecf20Sopenharmony_ci struct ib_port_attr pattr; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* Forward locally generated traps to the SM */ 2108c2ecf20Sopenharmony_ci if (in->mad_hdr.method == IB_MGMT_METHOD_TRAP && !slid) { 2118c2ecf20Sopenharmony_ci forward_trap(to_mdev(ibdev), port_num, in); 2128c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* 2168c2ecf20Sopenharmony_ci * Only handle SM gets, sets and trap represses for SM class 2178c2ecf20Sopenharmony_ci * 2188c2ecf20Sopenharmony_ci * Only handle PMA and Mellanox vendor-specific class gets and 2198c2ecf20Sopenharmony_ci * sets for other classes. 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_ci if (in->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 2228c2ecf20Sopenharmony_ci in->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 2238c2ecf20Sopenharmony_ci if (in->mad_hdr.method != IB_MGMT_METHOD_GET && 2248c2ecf20Sopenharmony_ci in->mad_hdr.method != IB_MGMT_METHOD_SET && 2258c2ecf20Sopenharmony_ci in->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) 2268c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* 2298c2ecf20Sopenharmony_ci * Don't process SMInfo queries or vendor-specific 2308c2ecf20Sopenharmony_ci * MADs -- the SMA can't handle them. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci if (in->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO || 2338c2ecf20Sopenharmony_ci ((in->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) == 2348c2ecf20Sopenharmony_ci IB_SMP_ATTR_VENDOR_MASK)) 2358c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS; 2368c2ecf20Sopenharmony_ci } else if (in->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || 2378c2ecf20Sopenharmony_ci in->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS1 || 2388c2ecf20Sopenharmony_ci in->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS2) { 2398c2ecf20Sopenharmony_ci if (in->mad_hdr.method != IB_MGMT_METHOD_GET && 2408c2ecf20Sopenharmony_ci in->mad_hdr.method != IB_MGMT_METHOD_SET) 2418c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS; 2428c2ecf20Sopenharmony_ci } else 2438c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS; 2448c2ecf20Sopenharmony_ci if ((in->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 2458c2ecf20Sopenharmony_ci in->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 2468c2ecf20Sopenharmony_ci in->mad_hdr.method == IB_MGMT_METHOD_SET && 2478c2ecf20Sopenharmony_ci in->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO && 2488c2ecf20Sopenharmony_ci !ib_query_port(ibdev, port_num, &pattr)) 2498c2ecf20Sopenharmony_ci prev_lid = ib_lid_cpu16(pattr.lid); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci err = mthca_MAD_IFC(to_mdev(ibdev), mad_flags & IB_MAD_IGNORE_MKEY, 2528c2ecf20Sopenharmony_ci mad_flags & IB_MAD_IGNORE_BKEY, port_num, in_wc, 2538c2ecf20Sopenharmony_ci in_grh, in, out); 2548c2ecf20Sopenharmony_ci if (err == -EBADMSG) 2558c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS; 2568c2ecf20Sopenharmony_ci else if (err) { 2578c2ecf20Sopenharmony_ci mthca_err(to_mdev(ibdev), "MAD_IFC returned %d\n", err); 2588c2ecf20Sopenharmony_ci return IB_MAD_RESULT_FAILURE; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (!out->mad_hdr.status) { 2628c2ecf20Sopenharmony_ci smp_snoop(ibdev, port_num, in, prev_lid); 2638c2ecf20Sopenharmony_ci node_desc_override(ibdev, out); 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* set return bit in status of directed route responses */ 2678c2ecf20Sopenharmony_ci if (in->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) 2688c2ecf20Sopenharmony_ci out->mad_hdr.status |= cpu_to_be16(1 << 15); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (in->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) 2718c2ecf20Sopenharmony_ci /* no response for trap repress */ 2728c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic void send_handler(struct ib_mad_agent *agent, 2788c2ecf20Sopenharmony_ci struct ib_mad_send_wc *mad_send_wc) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci ib_free_send_mad(mad_send_wc->send_buf); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ciint mthca_create_agents(struct mthca_dev *dev) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct ib_mad_agent *agent; 2868c2ecf20Sopenharmony_ci int p, q; 2878c2ecf20Sopenharmony_ci int ret; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci spin_lock_init(&dev->sm_lock); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci for (p = 0; p < dev->limits.num_ports; ++p) 2928c2ecf20Sopenharmony_ci for (q = 0; q <= 1; ++q) { 2938c2ecf20Sopenharmony_ci agent = ib_register_mad_agent(&dev->ib_dev, p + 1, 2948c2ecf20Sopenharmony_ci q ? IB_QPT_GSI : IB_QPT_SMI, 2958c2ecf20Sopenharmony_ci NULL, 0, send_handler, 2968c2ecf20Sopenharmony_ci NULL, NULL, 0); 2978c2ecf20Sopenharmony_ci if (IS_ERR(agent)) { 2988c2ecf20Sopenharmony_ci ret = PTR_ERR(agent); 2998c2ecf20Sopenharmony_ci goto err; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci dev->send_agent[p][q] = agent; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci for (p = 1; p <= dev->limits.num_ports; ++p) { 3068c2ecf20Sopenharmony_ci ret = mthca_update_rate(dev, p); 3078c2ecf20Sopenharmony_ci if (ret) { 3088c2ecf20Sopenharmony_ci mthca_err(dev, "Failed to obtain port %d rate." 3098c2ecf20Sopenharmony_ci " aborting.\n", p); 3108c2ecf20Sopenharmony_ci goto err; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cierr: 3178c2ecf20Sopenharmony_ci for (p = 0; p < dev->limits.num_ports; ++p) 3188c2ecf20Sopenharmony_ci for (q = 0; q <= 1; ++q) 3198c2ecf20Sopenharmony_ci if (dev->send_agent[p][q]) 3208c2ecf20Sopenharmony_ci ib_unregister_mad_agent(dev->send_agent[p][q]); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return ret; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_civoid mthca_free_agents(struct mthca_dev *dev) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct ib_mad_agent *agent; 3288c2ecf20Sopenharmony_ci int p, q; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci for (p = 0; p < dev->limits.num_ports; ++p) { 3318c2ecf20Sopenharmony_ci for (q = 0; q <= 1; ++q) { 3328c2ecf20Sopenharmony_ci agent = dev->send_agent[p][q]; 3338c2ecf20Sopenharmony_ci dev->send_agent[p][q] = NULL; 3348c2ecf20Sopenharmony_ci ib_unregister_mad_agent(agent); 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (dev->sm_ah[p]) 3388c2ecf20Sopenharmony_ci rdma_destroy_ah(dev->sm_ah[p], 3398c2ecf20Sopenharmony_ci RDMA_DESTROY_AH_SLEEPABLE); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci} 342