1279377Simp/* 2279377Simp * Copyright (c) 2004, 2005 Mellanox Technologies Ltd. All rights reserved. 3279377Simp * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved. 4279377Simp * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. 5279377Simp * Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved. 6279377Simp * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved. 7279377Simp * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 8279377Simp * 9279377Simp * This software is available to you under a choice of one of two 10279377Simp * licenses. You may choose to be licensed under the terms of the GNU 11279377Simp * General Public License (GPL) Version 2, available from the file 12279377Simp * COPYING in the main directory of this source tree, or the 13279377Simp * OpenIB.org BSD license below: 14279377Simp * 15279377Simp * Redistribution and use in source and binary forms, with or 16279377Simp * without modification, are permitted provided that the following 17279377Simp * conditions are met: 18279377Simp * 19279377Simp * - Redistributions of source code must retain the above 20279377Simp * copyright notice, this list of conditions and the following 21279377Simp * disclaimer. 22279377Simp * 23279377Simp * - Redistributions in binary form must reproduce the above 24279377Simp * copyright notice, this list of conditions and the following 25279377Simp * disclaimer in the documentation and/or other materials 26279377Simp * provided with the distribution. 27279377Simp * 28279377Simp * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 29279377Simp * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 30279377Simp * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 31279377Simp * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 32279377Simp * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 33279377Simp * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 34279377Simp * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35279377Simp * SOFTWARE. 36279377Simp * 37279377Simp */ 38279377Simp 39279377Simp#include <linux/slab.h> 40279377Simp#include <linux/string.h> 41279377Simp 42279377Simp#include "agent.h" 43279377Simp#include "smi.h" 44279377Simp#include "mad_priv.h" 45279377Simp 46279377Simp#define SPFX "ib_agent: " 47279377Simp 48279377Simpstruct ib_agent_port_private { 49279377Simp struct list_head port_list; 50279377Simp struct ib_mad_agent *agent[2]; 51279377Simp}; 52279377Simp 53279377Simpstatic DEFINE_SPINLOCK(ib_agent_port_list_lock); 54279377Simpstatic LIST_HEAD(ib_agent_port_list); 55279377Simp 56279377Simpstatic struct ib_agent_port_private * 57279377Simp__ib_get_agent_port(const struct ib_device *device, int port_num) 58279377Simp{ 59279377Simp struct ib_agent_port_private *entry; 60279377Simp 61279377Simp list_for_each_entry(entry, &ib_agent_port_list, port_list) { 62279377Simp if (entry->agent[1]->device == device && 63279377Simp entry->agent[1]->port_num == port_num) 64279377Simp return entry; 65279377Simp } 66279377Simp return NULL; 67279377Simp} 68279377Simp 69279377Simpstatic struct ib_agent_port_private * 70279377Simpib_get_agent_port(const struct ib_device *device, int port_num) 71279377Simp{ 72279377Simp struct ib_agent_port_private *entry; 73279377Simp unsigned long flags; 74279377Simp 75279377Simp spin_lock_irqsave(&ib_agent_port_list_lock, flags); 76279377Simp entry = __ib_get_agent_port(device, port_num); 77279377Simp spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); 78279377Simp return entry; 79279377Simp} 80279377Simp 81279377Simpvoid agent_send_response(const struct ib_mad_hdr *mad_hdr, const struct ib_grh *grh, 82279377Simp const struct ib_wc *wc, const struct ib_device *device, 83279377Simp int port_num, int qpn, size_t resp_mad_len, bool opa) 84279377Simp{ 85279377Simp struct ib_agent_port_private *port_priv; 86279377Simp struct ib_mad_agent *agent; 87279377Simp struct ib_mad_send_buf *send_buf; 88279377Simp struct ib_ah *ah; 89279377Simp struct ib_mad_send_wr_private *mad_send_wr; 90279377Simp 91279377Simp if (rdma_cap_ib_switch(device)) 92279377Simp port_priv = ib_get_agent_port(device, 0); 93279377Simp else 94279377Simp port_priv = ib_get_agent_port(device, port_num); 95279377Simp 96279377Simp if (!port_priv) { 97279377Simp dev_err(&device->dev, "Unable to find port agent\n"); 98279377Simp return; 99279377Simp } 100279377Simp 101279377Simp agent = port_priv->agent[qpn]; 102279377Simp ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num); 103279377Simp if (IS_ERR(ah)) { 104279377Simp dev_err(&device->dev, "ib_create_ah_from_wc error %ld\n", 105279377Simp PTR_ERR(ah)); 106279377Simp return; 107279377Simp } 108279377Simp 109279377Simp if (opa && mad_hdr->base_version != OPA_MGMT_BASE_VERSION) 110279377Simp resp_mad_len = IB_MGMT_MAD_SIZE; 111279377Simp 112279377Simp send_buf = ib_create_send_mad(agent, wc->src_qp, wc->pkey_index, 0, 113279377Simp IB_MGMT_MAD_HDR, 114279377Simp resp_mad_len - IB_MGMT_MAD_HDR, 115279377Simp GFP_KERNEL, 116279377Simp mad_hdr->base_version); 117279377Simp if (IS_ERR(send_buf)) { 118279377Simp dev_err(&device->dev, "ib_create_send_mad error\n"); 119279377Simp goto err1; 120279377Simp } 121279377Simp 122279377Simp memcpy(send_buf->mad, mad_hdr, resp_mad_len); 123279377Simp send_buf->ah = ah; 124279377Simp 125279377Simp if (rdma_cap_ib_switch(device)) { 126279377Simp mad_send_wr = container_of(send_buf, 127279377Simp struct ib_mad_send_wr_private, 128279377Simp send_buf); 129279377Simp mad_send_wr->send_wr.port_num = port_num; 130279377Simp } 131279377Simp 132279377Simp if (ib_post_send_mad(send_buf, NULL)) { 133279377Simp dev_err(&device->dev, "ib_post_send_mad error\n"); 134279377Simp goto err2; 135279377Simp } 136279377Simp return; 137279377Simperr2: 138279377Simp ib_free_send_mad(send_buf); 139279377Simperr1: 140279377Simp rdma_destroy_ah(ah, RDMA_DESTROY_AH_SLEEPABLE); 141279377Simp} 142279377Simp 143279377Simpstatic void agent_send_handler(struct ib_mad_agent *mad_agent, 144279377Simp struct ib_mad_send_wc *mad_send_wc) 145279377Simp{ 146279377Simp rdma_destroy_ah(mad_send_wc->send_buf->ah, RDMA_DESTROY_AH_SLEEPABLE); 147279377Simp ib_free_send_mad(mad_send_wc->send_buf); 148279377Simp} 149279377Simp 150279377Simpint ib_agent_port_open(struct ib_device *device, int port_num) 151279377Simp{ 152279377Simp struct ib_agent_port_private *port_priv; 153279377Simp unsigned long flags; 154279377Simp int ret; 155279377Simp 156279377Simp /* Create new device info */ 157279377Simp port_priv = kzalloc(sizeof *port_priv, GFP_KERNEL); 158279377Simp if (!port_priv) { 159279377Simp ret = -ENOMEM; 160279377Simp goto error1; 161279377Simp } 162279377Simp 163279377Simp if (rdma_cap_ib_smi(device, port_num)) { 164279377Simp /* Obtain send only MAD agent for SMI QP */ 165279377Simp port_priv->agent[0] = ib_register_mad_agent(device, port_num, 166279377Simp IB_QPT_SMI, NULL, 0, 167279377Simp &agent_send_handler, 168279377Simp NULL, NULL, 0); 169279377Simp if (IS_ERR(port_priv->agent[0])) { 170279377Simp ret = PTR_ERR(port_priv->agent[0]); 171279377Simp goto error2; 172279377Simp } 173279377Simp } 174279377Simp 175279377Simp /* Obtain send only MAD agent for GSI QP */ 176279377Simp port_priv->agent[1] = ib_register_mad_agent(device, port_num, 177279377Simp IB_QPT_GSI, NULL, 0, 178279377Simp &agent_send_handler, 179279377Simp NULL, NULL, 0); 180279377Simp if (IS_ERR(port_priv->agent[1])) { 181279377Simp ret = PTR_ERR(port_priv->agent[1]); 182279377Simp goto error3; 183279377Simp } 184 185 spin_lock_irqsave(&ib_agent_port_list_lock, flags); 186 list_add_tail(&port_priv->port_list, &ib_agent_port_list); 187 spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); 188 189 return 0; 190 191error3: 192 if (port_priv->agent[0]) 193 ib_unregister_mad_agent(port_priv->agent[0]); 194error2: 195 kfree(port_priv); 196error1: 197 return ret; 198} 199 200int ib_agent_port_close(struct ib_device *device, int port_num) 201{ 202 struct ib_agent_port_private *port_priv; 203 unsigned long flags; 204 205 spin_lock_irqsave(&ib_agent_port_list_lock, flags); 206 port_priv = __ib_get_agent_port(device, port_num); 207 if (port_priv == NULL) { 208 spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); 209 dev_err(&device->dev, "Port %d not found\n", port_num); 210 return -ENODEV; 211 } 212 list_del(&port_priv->port_list); 213 spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); 214 215 ib_unregister_mad_agent(port_priv->agent[1]); 216 if (port_priv->agent[0]) 217 ib_unregister_mad_agent(port_priv->agent[0]); 218 219 kfree(port_priv); 220 return 0; 221} 222