1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0 3 * 4 * Copyright (c) 2004, 2005 Mellanox Technologies Ltd. All rights reserved. 5 * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved. 6 * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. 7 * Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved. 8 * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved. 9 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 10 * 11 * This software is available to you under a choice of one of two 12 * licenses. You may choose to be licensed under the terms of the GNU 13 * General Public License (GPL) Version 2, available from the file 14 * COPYING in the main directory of this source tree, or the 15 * OpenIB.org BSD license below: 16 * 17 * Redistribution and use in source and binary forms, with or 18 * without modification, are permitted provided that the following 19 * conditions are met: 20 * 21 * - Redistributions of source code must retain the above 22 * copyright notice, this list of conditions and the following 23 * disclaimer. 24 * 25 * - Redistributions in binary form must reproduce the above 26 * copyright notice, this list of conditions and the following 27 * disclaimer in the documentation and/or other materials 28 * provided with the distribution. 29 * 30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 31 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 32 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 33 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 34 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 35 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 36 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 37 * SOFTWARE. 38 */ 39 40 #include <sys/cdefs.h> 41 __FBSDID("$FreeBSD$"); 42 43 #include <linux/slab.h> 44 #include <linux/string.h> 45 46 #include "agent.h" 47 #include "smi.h" 48 #include "mad_priv.h" 49 50 #define SPFX "ib_agent: " 51 52 struct ib_agent_port_private { 53 struct list_head port_list; 54 struct ib_mad_agent *agent[2]; 55 }; 56 57 static DEFINE_SPINLOCK(ib_agent_port_list_lock); 58 static LIST_HEAD(ib_agent_port_list); 59 60 static struct ib_agent_port_private * 61 __ib_get_agent_port(const struct ib_device *device, int port_num) 62 { 63 struct ib_agent_port_private *entry; 64 65 list_for_each_entry(entry, &ib_agent_port_list, port_list) { 66 if (entry->agent[1]->device == device && 67 entry->agent[1]->port_num == port_num) 68 return entry; 69 } 70 return NULL; 71 } 72 73 static struct ib_agent_port_private * 74 ib_get_agent_port(const struct ib_device *device, int port_num) 75 { 76 struct ib_agent_port_private *entry; 77 unsigned long flags; 78 79 spin_lock_irqsave(&ib_agent_port_list_lock, flags); 80 entry = __ib_get_agent_port(device, port_num); 81 spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); 82 return entry; 83 } 84 85 void agent_send_response(const struct ib_mad_hdr *mad_hdr, const struct ib_grh *grh, 86 const struct ib_wc *wc, const struct ib_device *device, 87 int port_num, int qpn, size_t resp_mad_len, bool opa) 88 { 89 struct ib_agent_port_private *port_priv; 90 struct ib_mad_agent *agent; 91 struct ib_mad_send_buf *send_buf; 92 struct ib_ah *ah; 93 struct ib_mad_send_wr_private *mad_send_wr; 94 95 if (rdma_cap_ib_switch(device)) 96 port_priv = ib_get_agent_port(device, 0); 97 else 98 port_priv = ib_get_agent_port(device, port_num); 99 100 if (!port_priv) { 101 dev_err(&device->dev, "Unable to find port agent\n"); 102 return; 103 } 104 105 agent = port_priv->agent[qpn]; 106 ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num); 107 if (IS_ERR(ah)) { 108 dev_err(&device->dev, "ib_create_ah_from_wc error %ld\n", 109 PTR_ERR(ah)); 110 return; 111 } 112 113 if (opa && mad_hdr->base_version != OPA_MGMT_BASE_VERSION) 114 resp_mad_len = IB_MGMT_MAD_SIZE; 115 116 send_buf = ib_create_send_mad(agent, wc->src_qp, wc->pkey_index, 0, 117 IB_MGMT_MAD_HDR, 118 resp_mad_len - IB_MGMT_MAD_HDR, 119 GFP_KERNEL, 120 mad_hdr->base_version); 121 if (IS_ERR(send_buf)) { 122 dev_err(&device->dev, "ib_create_send_mad error\n"); 123 goto err1; 124 } 125 126 memcpy(send_buf->mad, mad_hdr, resp_mad_len); 127 send_buf->ah = ah; 128 129 if (rdma_cap_ib_switch(device)) { 130 mad_send_wr = container_of(send_buf, 131 struct ib_mad_send_wr_private, 132 send_buf); 133 mad_send_wr->send_wr.port_num = port_num; 134 } 135 136 if (ib_post_send_mad(send_buf, NULL)) { 137 dev_err(&device->dev, "ib_post_send_mad error\n"); 138 goto err2; 139 } 140 return; 141 err2: 142 ib_free_send_mad(send_buf); 143 err1: 144 ib_destroy_ah(ah, RDMA_DESTROY_AH_SLEEPABLE); 145 } 146 147 static void agent_send_handler(struct ib_mad_agent *mad_agent, 148 struct ib_mad_send_wc *mad_send_wc) 149 { 150 ib_destroy_ah(mad_send_wc->send_buf->ah, RDMA_DESTROY_AH_SLEEPABLE); 151 ib_free_send_mad(mad_send_wc->send_buf); 152 } 153 154 int ib_agent_port_open(struct ib_device *device, int port_num) 155 { 156 struct ib_agent_port_private *port_priv; 157 unsigned long flags; 158 int ret; 159 160 /* Create new device info */ 161 port_priv = kzalloc(sizeof *port_priv, GFP_KERNEL); 162 if (!port_priv) { 163 dev_err(&device->dev, "No memory for ib_agent_port_private\n"); 164 ret = -ENOMEM; 165 goto error1; 166 } 167 168 if (rdma_cap_ib_smi(device, port_num)) { 169 /* Obtain send only MAD agent for SMI QP */ 170 port_priv->agent[0] = ib_register_mad_agent(device, port_num, 171 IB_QPT_SMI, NULL, 0, 172 &agent_send_handler, 173 NULL, NULL, 0); 174 if (IS_ERR(port_priv->agent[0])) { 175 ret = PTR_ERR(port_priv->agent[0]); 176 goto error2; 177 } 178 } 179 180 /* Obtain send only MAD agent for GSI QP */ 181 port_priv->agent[1] = ib_register_mad_agent(device, port_num, 182 IB_QPT_GSI, NULL, 0, 183 &agent_send_handler, 184 NULL, NULL, 0); 185 if (IS_ERR(port_priv->agent[1])) { 186 ret = PTR_ERR(port_priv->agent[1]); 187 goto error3; 188 } 189 190 spin_lock_irqsave(&ib_agent_port_list_lock, flags); 191 list_add_tail(&port_priv->port_list, &ib_agent_port_list); 192 spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); 193 194 return 0; 195 196 error3: 197 if (port_priv->agent[0]) 198 ib_unregister_mad_agent(port_priv->agent[0]); 199 error2: 200 kfree(port_priv); 201 error1: 202 return ret; 203 } 204 205 int ib_agent_port_close(struct ib_device *device, int port_num) 206 { 207 struct ib_agent_port_private *port_priv; 208 unsigned long flags; 209 210 spin_lock_irqsave(&ib_agent_port_list_lock, flags); 211 port_priv = __ib_get_agent_port(device, port_num); 212 if (port_priv == NULL) { 213 spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); 214 dev_err(&device->dev, "Port %d not found\n", port_num); 215 return -ENODEV; 216 } 217 list_del(&port_priv->port_list); 218 spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); 219 220 ib_unregister_mad_agent(port_priv->agent[1]); 221 if (port_priv->agent[0]) 222 ib_unregister_mad_agent(port_priv->agent[0]); 223 224 kfree(port_priv); 225 return 0; 226 } 227