11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (c) 2004 Topspin Communications. All rights reserved. 32a1d9b7fSRoland Dreier * Copyright (c) 2005 Mellanox Technologies. All rights reserved. 42a1d9b7fSRoland Dreier * Copyright (c) 2004 Voltaire, Inc. All rights reserved. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This software is available to you under a choice of one of two 71da177e4SLinus Torvalds * licenses. You may choose to be licensed under the terms of the GNU 81da177e4SLinus Torvalds * General Public License (GPL) Version 2, available from the file 91da177e4SLinus Torvalds * COPYING in the main directory of this source tree, or the 101da177e4SLinus Torvalds * OpenIB.org BSD license below: 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * Redistribution and use in source and binary forms, with or 131da177e4SLinus Torvalds * without modification, are permitted provided that the following 141da177e4SLinus Torvalds * conditions are met: 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * - Redistributions of source code must retain the above 171da177e4SLinus Torvalds * copyright notice, this list of conditions and the following 181da177e4SLinus Torvalds * disclaimer. 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds * - Redistributions in binary form must reproduce the above 211da177e4SLinus Torvalds * copyright notice, this list of conditions and the following 221da177e4SLinus Torvalds * disclaimer in the documentation and/or other materials 231da177e4SLinus Torvalds * provided with the distribution. 241da177e4SLinus Torvalds * 251da177e4SLinus Torvalds * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 261da177e4SLinus Torvalds * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 271da177e4SLinus Torvalds * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 281da177e4SLinus Torvalds * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 291da177e4SLinus Torvalds * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 301da177e4SLinus Torvalds * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 311da177e4SLinus Torvalds * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 321da177e4SLinus Torvalds * SOFTWARE. 331da177e4SLinus Torvalds */ 341da177e4SLinus Torvalds 354e57b681STim Schmielau #include <linux/string.h> 364e57b681STim Schmielau #include <linux/slab.h> 374e57b681STim Schmielau 38a4d61e84SRoland Dreier #include <rdma/ib_verbs.h> 39a4d61e84SRoland Dreier #include <rdma/ib_mad.h> 40a4d61e84SRoland Dreier #include <rdma/ib_smi.h> 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds #include "mthca_dev.h" 431da177e4SLinus Torvalds #include "mthca_cmd.h" 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds enum { 461da177e4SLinus Torvalds MTHCA_VENDOR_CLASS1 = 0x9, 471da177e4SLinus Torvalds MTHCA_VENDOR_CLASS2 = 0xa 481da177e4SLinus Torvalds }; 491da177e4SLinus Torvalds 50415dcd95SAdrian Bunk static int mthca_update_rate(struct mthca_dev *dev, u8 port_num) 51bf6a9e31SJack Morgenstein { 52bf6a9e31SJack Morgenstein struct ib_port_attr *tprops = NULL; 53bf6a9e31SJack Morgenstein int ret; 54bf6a9e31SJack Morgenstein 55bf6a9e31SJack Morgenstein tprops = kmalloc(sizeof *tprops, GFP_KERNEL); 56bf6a9e31SJack Morgenstein if (!tprops) 57bf6a9e31SJack Morgenstein return -ENOMEM; 58bf6a9e31SJack Morgenstein 59bf6a9e31SJack Morgenstein ret = ib_query_port(&dev->ib_dev, port_num, tprops); 60bf6a9e31SJack Morgenstein if (ret) { 615a738b5dSJason Gunthorpe dev_warn(&dev->ib_dev.dev, 625a738b5dSJason Gunthorpe "ib_query_port failed (%d) forport %d\n", ret, 635a738b5dSJason Gunthorpe port_num); 64bf6a9e31SJack Morgenstein goto out; 65bf6a9e31SJack Morgenstein } 66bf6a9e31SJack Morgenstein 67bf6a9e31SJack Morgenstein dev->rate[port_num - 1] = tprops->active_speed * 68bf6a9e31SJack Morgenstein ib_width_enum_to_int(tprops->active_width); 69bf6a9e31SJack Morgenstein 70bf6a9e31SJack Morgenstein out: 71bf6a9e31SJack Morgenstein kfree(tprops); 72bf6a9e31SJack Morgenstein return ret; 73bf6a9e31SJack Morgenstein } 74bf6a9e31SJack Morgenstein 751da177e4SLinus Torvalds static void update_sm_ah(struct mthca_dev *dev, 761da177e4SLinus Torvalds u8 port_num, u16 lid, u8 sl) 771da177e4SLinus Torvalds { 781da177e4SLinus Torvalds struct ib_ah *new_ah; 7990898850SDasaratharaman Chandramouli struct rdma_ah_attr ah_attr; 801da177e4SLinus Torvalds unsigned long flags; 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds if (!dev->send_agent[port_num - 1][0]) 831da177e4SLinus Torvalds return; 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds memset(&ah_attr, 0, sizeof ah_attr); 8644c58487SDasaratharaman Chandramouli ah_attr.type = rdma_ah_find_type(&dev->ib_dev, port_num); 87d8966fcdSDasaratharaman Chandramouli rdma_ah_set_dlid(&ah_attr, lid); 88d8966fcdSDasaratharaman Chandramouli rdma_ah_set_sl(&ah_attr, sl); 89d8966fcdSDasaratharaman Chandramouli rdma_ah_set_port_num(&ah_attr, port_num); 901da177e4SLinus Torvalds 910a18cfe4SDasaratharaman Chandramouli new_ah = rdma_create_ah(dev->send_agent[port_num - 1][0]->qp->pd, 92b090c4e3SGal Pressman &ah_attr, 0); 931da177e4SLinus Torvalds if (IS_ERR(new_ah)) 941da177e4SLinus Torvalds return; 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds spin_lock_irqsave(&dev->sm_lock, flags); 971da177e4SLinus Torvalds if (dev->sm_ah[port_num - 1]) 9836523159SDasaratharaman Chandramouli rdma_destroy_ah(dev->sm_ah[port_num - 1]); 991da177e4SLinus Torvalds dev->sm_ah[port_num - 1] = new_ah; 1001da177e4SLinus Torvalds spin_unlock_irqrestore(&dev->sm_lock, flags); 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds /* 1041da177e4SLinus Torvalds * Snoop SM MADs for port info and P_Key table sets, so we can 1051da177e4SLinus Torvalds * synthesize LID change and P_Key change events. 1061da177e4SLinus Torvalds */ 1071da177e4SLinus Torvalds static void smp_snoop(struct ib_device *ibdev, 1081da177e4SLinus Torvalds u8 port_num, 109a97e2d86SIra Weiny const struct ib_mad *mad, 110270b8b85SMoni Shoua u16 prev_lid) 1111da177e4SLinus Torvalds { 1121da177e4SLinus Torvalds struct ib_event event; 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 1151da177e4SLinus Torvalds mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 1161da177e4SLinus Torvalds mad->mad_hdr.method == IB_MGMT_METHOD_SET) { 1171da177e4SLinus Torvalds if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) { 11812bbb2b7SLeonid Arsh struct ib_port_info *pinfo = 11912bbb2b7SLeonid Arsh (struct ib_port_info *) ((struct ib_smp *) mad)->data; 120270b8b85SMoni Shoua u16 lid = be16_to_cpu(pinfo->lid); 12112bbb2b7SLeonid Arsh 122bf6a9e31SJack Morgenstein mthca_update_rate(to_mdev(ibdev), port_num); 1231da177e4SLinus Torvalds update_sm_ah(to_mdev(ibdev), port_num, 124b2707573SJack Morgenstein be16_to_cpu(pinfo->sm_lid), 12512bbb2b7SLeonid Arsh pinfo->neighbormtu_mastersmsl & 0xf); 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds event.device = ibdev; 1281da177e4SLinus Torvalds event.element.port_num = port_num; 12912bbb2b7SLeonid Arsh 130270b8b85SMoni Shoua if (pinfo->clientrereg_resv_subnetto & 0x80) { 13112bbb2b7SLeonid Arsh event.event = IB_EVENT_CLIENT_REREGISTER; 1321da177e4SLinus Torvalds ib_dispatch_event(&event); 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 135270b8b85SMoni Shoua if (prev_lid != lid) { 136270b8b85SMoni Shoua event.event = IB_EVENT_LID_CHANGE; 137270b8b85SMoni Shoua ib_dispatch_event(&event); 138270b8b85SMoni Shoua } 139270b8b85SMoni Shoua } 140270b8b85SMoni Shoua 1411da177e4SLinus Torvalds if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) { 1421da177e4SLinus Torvalds event.device = ibdev; 1431da177e4SLinus Torvalds event.event = IB_EVENT_PKEY_CHANGE; 1441da177e4SLinus Torvalds event.element.port_num = port_num; 1451da177e4SLinus Torvalds ib_dispatch_event(&event); 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds } 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds 1506dfc3901SRoland Dreier static void node_desc_override(struct ib_device *dev, 1516dfc3901SRoland Dreier struct ib_mad *mad) 1526dfc3901SRoland Dreier { 1536dfc3901SRoland Dreier if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 1546dfc3901SRoland Dreier mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 1556dfc3901SRoland Dreier mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP && 1566dfc3901SRoland Dreier mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) { 1576dfc3901SRoland Dreier mutex_lock(&to_mdev(dev)->cap_mask_mutex); 158bd99fdeaSYuval Shaia memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 159bd99fdeaSYuval Shaia IB_DEVICE_NODE_DESC_MAX); 1606dfc3901SRoland Dreier mutex_unlock(&to_mdev(dev)->cap_mask_mutex); 1616dfc3901SRoland Dreier } 1626dfc3901SRoland Dreier } 1636dfc3901SRoland Dreier 1641da177e4SLinus Torvalds static void forward_trap(struct mthca_dev *dev, 1651da177e4SLinus Torvalds u8 port_num, 166a97e2d86SIra Weiny const struct ib_mad *mad) 1671da177e4SLinus Torvalds { 1681da177e4SLinus Torvalds int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; 16934816ad9SSean Hefty struct ib_mad_send_buf *send_buf; 1701da177e4SLinus Torvalds struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; 1711da177e4SLinus Torvalds int ret; 1721da177e4SLinus Torvalds unsigned long flags; 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds if (agent) { 17534816ad9SSean Hefty send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, 176da2dfaa3SIra Weiny IB_MGMT_MAD_DATA, GFP_ATOMIC, 177da2dfaa3SIra Weiny IB_MGMT_BASE_VERSION); 178d0444f15SDan Carpenter if (IS_ERR(send_buf)) 179d0444f15SDan Carpenter return; 1801da177e4SLinus Torvalds /* 1811da177e4SLinus Torvalds * We rely here on the fact that MLX QPs don't use the 1821da177e4SLinus Torvalds * address handle after the send is posted (this is 1831da177e4SLinus Torvalds * wrong following the IB spec strictly, but we know 1841da177e4SLinus Torvalds * it's OK for our devices). 1851da177e4SLinus Torvalds */ 1861da177e4SLinus Torvalds spin_lock_irqsave(&dev->sm_lock, flags); 18734816ad9SSean Hefty memcpy(send_buf->mad, mad, sizeof *mad); 18834816ad9SSean Hefty if ((send_buf->ah = dev->sm_ah[port_num - 1])) 18934816ad9SSean Hefty ret = ib_post_send_mad(send_buf, NULL); 1901da177e4SLinus Torvalds else 1911da177e4SLinus Torvalds ret = -EINVAL; 1921da177e4SLinus Torvalds spin_unlock_irqrestore(&dev->sm_lock, flags); 1931da177e4SLinus Torvalds 19434816ad9SSean Hefty if (ret) 19534816ad9SSean Hefty ib_free_send_mad(send_buf); 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds } 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds int mthca_process_mad(struct ib_device *ibdev, 2001da177e4SLinus Torvalds int mad_flags, 2011da177e4SLinus Torvalds u8 port_num, 202a97e2d86SIra Weiny const struct ib_wc *in_wc, 203a97e2d86SIra Weiny const struct ib_grh *in_grh, 2044cd7c947SIra Weiny const struct ib_mad_hdr *in, size_t in_mad_size, 2054cd7c947SIra Weiny struct ib_mad_hdr *out, size_t *out_mad_size, 2064cd7c947SIra Weiny u16 *out_mad_pkey_index) 2071da177e4SLinus Torvalds { 2081da177e4SLinus Torvalds int err; 20962ede777SHiatt, Don u16 slid = in_wc ? ib_lid_cpu16(in_wc->slid) : be16_to_cpu(IB_LID_PERMISSIVE); 210270b8b85SMoni Shoua u16 prev_lid = 0; 211270b8b85SMoni Shoua struct ib_port_attr pattr; 2124cd7c947SIra Weiny const struct ib_mad *in_mad = (const struct ib_mad *)in; 2134cd7c947SIra Weiny struct ib_mad *out_mad = (struct ib_mad *)out; 2144cd7c947SIra Weiny 2153b8ab700SIra Weiny if (WARN_ON_ONCE(in_mad_size != sizeof(*in_mad) || 2163b8ab700SIra Weiny *out_mad_size != sizeof(*out_mad))) 2173b8ab700SIra Weiny return IB_MAD_RESULT_FAILURE; 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds /* Forward locally generated traps to the SM */ 2201da177e4SLinus Torvalds if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && 2211da177e4SLinus Torvalds slid == 0) { 2221da177e4SLinus Torvalds forward_trap(to_mdev(ibdev), port_num, in_mad); 2231da177e4SLinus Torvalds return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds /* 2271da177e4SLinus Torvalds * Only handle SM gets, sets and trap represses for SM class 2281da177e4SLinus Torvalds * 2291da177e4SLinus Torvalds * Only handle PMA and Mellanox vendor-specific class gets and 2301da177e4SLinus Torvalds * sets for other classes. 2311da177e4SLinus Torvalds */ 2321da177e4SLinus Torvalds if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 2331da177e4SLinus Torvalds in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 2341da177e4SLinus Torvalds if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 2351da177e4SLinus Torvalds in_mad->mad_hdr.method != IB_MGMT_METHOD_SET && 2361da177e4SLinus Torvalds in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) 2371da177e4SLinus Torvalds return IB_MAD_RESULT_SUCCESS; 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds /* 2401da177e4SLinus Torvalds * Don't process SMInfo queries or vendor-specific 2411da177e4SLinus Torvalds * MADs -- the SMA can't handle them. 2421da177e4SLinus Torvalds */ 2431da177e4SLinus Torvalds if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO || 2441da177e4SLinus Torvalds ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) == 2451da177e4SLinus Torvalds IB_SMP_ATTR_VENDOR_MASK)) 2461da177e4SLinus Torvalds return IB_MAD_RESULT_SUCCESS; 2471da177e4SLinus Torvalds } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || 2481da177e4SLinus Torvalds in_mad->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS1 || 2491da177e4SLinus Torvalds in_mad->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS2) { 2501da177e4SLinus Torvalds if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 2511da177e4SLinus Torvalds in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) 2521da177e4SLinus Torvalds return IB_MAD_RESULT_SUCCESS; 2531da177e4SLinus Torvalds } else 2541da177e4SLinus Torvalds return IB_MAD_RESULT_SUCCESS; 255270b8b85SMoni Shoua if ((in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 256270b8b85SMoni Shoua in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 257270b8b85SMoni Shoua in_mad->mad_hdr.method == IB_MGMT_METHOD_SET && 258270b8b85SMoni Shoua in_mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO && 259270b8b85SMoni Shoua !ib_query_port(ibdev, port_num, &pattr)) 26062ede777SHiatt, Don prev_lid = ib_lid_cpu16(pattr.lid); 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds err = mthca_MAD_IFC(to_mdev(ibdev), 2631da177e4SLinus Torvalds mad_flags & IB_MAD_IGNORE_MKEY, 2641da177e4SLinus Torvalds mad_flags & IB_MAD_IGNORE_BKEY, 265cdb73db0SGoldwyn Rodrigues port_num, in_wc, in_grh, in_mad, out_mad); 266cdb73db0SGoldwyn Rodrigues if (err == -EBADMSG) 2671da177e4SLinus Torvalds return IB_MAD_RESULT_SUCCESS; 268cdb73db0SGoldwyn Rodrigues else if (err) { 269cdb73db0SGoldwyn Rodrigues mthca_err(to_mdev(ibdev), "MAD_IFC returned %d\n", err); 2701da177e4SLinus Torvalds return IB_MAD_RESULT_FAILURE; 2711da177e4SLinus Torvalds } 2721da177e4SLinus Torvalds 2736dfc3901SRoland Dreier if (!out_mad->mad_hdr.status) { 274270b8b85SMoni Shoua smp_snoop(ibdev, port_num, in_mad, prev_lid); 2756dfc3901SRoland Dreier node_desc_override(ibdev, out_mad); 2766dfc3901SRoland Dreier } 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds /* set return bit in status of directed route responses */ 2791da177e4SLinus Torvalds if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) 2801da177e4SLinus Torvalds out_mad->mad_hdr.status |= cpu_to_be16(1 << 15); 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) 2831da177e4SLinus Torvalds /* no response for trap repress */ 2841da177e4SLinus Torvalds return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 2871da177e4SLinus Torvalds } 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds static void send_handler(struct ib_mad_agent *agent, 2901da177e4SLinus Torvalds struct ib_mad_send_wc *mad_send_wc) 2911da177e4SLinus Torvalds { 29234816ad9SSean Hefty ib_free_send_mad(mad_send_wc->send_buf); 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds int mthca_create_agents(struct mthca_dev *dev) 2961da177e4SLinus Torvalds { 2971da177e4SLinus Torvalds struct ib_mad_agent *agent; 2981da177e4SLinus Torvalds int p, q; 299bf6a9e31SJack Morgenstein int ret; 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds spin_lock_init(&dev->sm_lock); 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds for (p = 0; p < dev->limits.num_ports; ++p) 3041da177e4SLinus Torvalds for (q = 0; q <= 1; ++q) { 3051da177e4SLinus Torvalds agent = ib_register_mad_agent(&dev->ib_dev, p + 1, 3061da177e4SLinus Torvalds q ? IB_QPT_GSI : IB_QPT_SMI, 3071da177e4SLinus Torvalds NULL, 0, send_handler, 3080f29b46dSIra Weiny NULL, NULL, 0); 309bf6a9e31SJack Morgenstein if (IS_ERR(agent)) { 310bf6a9e31SJack Morgenstein ret = PTR_ERR(agent); 3111da177e4SLinus Torvalds goto err; 312bf6a9e31SJack Morgenstein } 3131da177e4SLinus Torvalds dev->send_agent[p][q] = agent; 3141da177e4SLinus Torvalds } 3151da177e4SLinus Torvalds 316bf6a9e31SJack Morgenstein 317bf6a9e31SJack Morgenstein for (p = 1; p <= dev->limits.num_ports; ++p) { 318bf6a9e31SJack Morgenstein ret = mthca_update_rate(dev, p); 319bf6a9e31SJack Morgenstein if (ret) { 320bf6a9e31SJack Morgenstein mthca_err(dev, "Failed to obtain port %d rate." 321bf6a9e31SJack Morgenstein " aborting.\n", p); 322bf6a9e31SJack Morgenstein goto err; 323bf6a9e31SJack Morgenstein } 324bf6a9e31SJack Morgenstein } 325bf6a9e31SJack Morgenstein 3261da177e4SLinus Torvalds return 0; 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds err: 3291da177e4SLinus Torvalds for (p = 0; p < dev->limits.num_ports; ++p) 3301da177e4SLinus Torvalds for (q = 0; q <= 1; ++q) 3311da177e4SLinus Torvalds if (dev->send_agent[p][q]) 3321da177e4SLinus Torvalds ib_unregister_mad_agent(dev->send_agent[p][q]); 3331da177e4SLinus Torvalds 334bf6a9e31SJack Morgenstein return ret; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 337f4f3d0f0SRoland Dreier void mthca_free_agents(struct mthca_dev *dev) 3381da177e4SLinus Torvalds { 3391da177e4SLinus Torvalds struct ib_mad_agent *agent; 3401da177e4SLinus Torvalds int p, q; 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds for (p = 0; p < dev->limits.num_ports; ++p) { 3431da177e4SLinus Torvalds for (q = 0; q <= 1; ++q) { 3441da177e4SLinus Torvalds agent = dev->send_agent[p][q]; 3451da177e4SLinus Torvalds dev->send_agent[p][q] = NULL; 3461da177e4SLinus Torvalds ib_unregister_mad_agent(agent); 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds if (dev->sm_ah[p]) 35036523159SDasaratharaman Chandramouli rdma_destroy_ah(dev->sm_ah[p]); 3511da177e4SLinus Torvalds } 3521da177e4SLinus Torvalds } 353