11da177e4SLinus Torvalds /* 22a1d9b7fSRoland Dreier * Copyright (c) 2004, 2005 Mellanox Technologies Ltd. All rights reserved. 32a1d9b7fSRoland Dreier * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved. 42a1d9b7fSRoland Dreier * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. 52a1d9b7fSRoland Dreier * Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved. 61bae4dbfSHal Rosenstock * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved. 72a1d9b7fSRoland Dreier * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * This software is available to you under a choice of one of two 101da177e4SLinus Torvalds * licenses. You may choose to be licensed under the terms of the GNU 111da177e4SLinus Torvalds * General Public License (GPL) Version 2, available from the file 121da177e4SLinus Torvalds * COPYING in the main directory of this source tree, or the 131da177e4SLinus Torvalds * OpenIB.org BSD license below: 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds * Redistribution and use in source and binary forms, with or 161da177e4SLinus Torvalds * without modification, are permitted provided that the following 171da177e4SLinus Torvalds * conditions are met: 181da177e4SLinus Torvalds * 191da177e4SLinus Torvalds * - Redistributions of source code must retain the above 201da177e4SLinus Torvalds * copyright notice, this list of conditions and the following 211da177e4SLinus Torvalds * disclaimer. 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * - Redistributions in binary form must reproduce the above 241da177e4SLinus Torvalds * copyright notice, this list of conditions and the following 251da177e4SLinus Torvalds * disclaimer in the documentation and/or other materials 261da177e4SLinus Torvalds * provided with the distribution. 271da177e4SLinus Torvalds * 281da177e4SLinus Torvalds * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 291da177e4SLinus Torvalds * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 301da177e4SLinus Torvalds * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 311da177e4SLinus Torvalds * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 321da177e4SLinus Torvalds * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 331da177e4SLinus Torvalds * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 341da177e4SLinus Torvalds * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 351da177e4SLinus Torvalds * SOFTWARE. 361da177e4SLinus Torvalds * 371da177e4SLinus Torvalds */ 381da177e4SLinus Torvalds 398c65b4a6STim Schmielau #include <linux/slab.h> 408c65b4a6STim Schmielau #include <linux/string.h> 418c65b4a6STim Schmielau 421da177e4SLinus Torvalds #include "agent.h" 4334816ad9SSean Hefty #include "smi.h" 441bae4dbfSHal Rosenstock #include "mad_priv.h" 451da177e4SLinus Torvalds 4634816ad9SSean Hefty #define SPFX "ib_agent: " 4734816ad9SSean Hefty 4834816ad9SSean Hefty struct ib_agent_port_private { 4934816ad9SSean Hefty struct list_head port_list; 5034816ad9SSean Hefty struct ib_mad_agent *agent[2]; 5134816ad9SSean Hefty }; 5234816ad9SSean Hefty 5334816ad9SSean Hefty static DEFINE_SPINLOCK(ib_agent_port_list_lock); 541da177e4SLinus Torvalds static LIST_HEAD(ib_agent_port_list); 551da177e4SLinus Torvalds 5634816ad9SSean Hefty static struct ib_agent_port_private * 5773cdaaeeSIra Weiny __ib_get_agent_port(const struct ib_device *device, int port_num) 581da177e4SLinus Torvalds { 591da177e4SLinus Torvalds struct ib_agent_port_private *entry; 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds list_for_each_entry(entry, &ib_agent_port_list, port_list) { 62fac70d51SEli Cohen if (entry->agent[1]->device == device && 63fac70d51SEli Cohen entry->agent[1]->port_num == port_num) 641da177e4SLinus Torvalds return entry; 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds return NULL; 671da177e4SLinus Torvalds } 681da177e4SLinus Torvalds 6934816ad9SSean Hefty static struct ib_agent_port_private * 7073cdaaeeSIra Weiny ib_get_agent_port(const struct ib_device *device, int port_num) 711da177e4SLinus Torvalds { 721da177e4SLinus Torvalds struct ib_agent_port_private *entry; 731da177e4SLinus Torvalds unsigned long flags; 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds spin_lock_irqsave(&ib_agent_port_list_lock, flags); 7634816ad9SSean Hefty entry = __ib_get_agent_port(device, port_num); 771da177e4SLinus Torvalds spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); 781da177e4SLinus Torvalds return entry; 791da177e4SLinus Torvalds } 801da177e4SLinus Torvalds 81c9082e51SIra Weiny void agent_send_response(const struct ib_mad_hdr *mad_hdr, const struct ib_grh *grh, 8273cdaaeeSIra Weiny const struct ib_wc *wc, const struct ib_device *device, 838e4349d1SIra Weiny int port_num, int qpn, size_t resp_mad_len, bool opa) 841da177e4SLinus Torvalds { 8534816ad9SSean Hefty struct ib_agent_port_private *port_priv; 8634816ad9SSean Hefty struct ib_mad_agent *agent; 8734816ad9SSean Hefty struct ib_mad_send_buf *send_buf; 8834816ad9SSean Hefty struct ib_ah *ah; 891bae4dbfSHal Rosenstock struct ib_mad_send_wr_private *mad_send_wr; 901da177e4SLinus Torvalds 914139032bSHal Rosenstock if (rdma_cap_ib_switch(device)) 921bae4dbfSHal Rosenstock port_priv = ib_get_agent_port(device, 0); 931bae4dbfSHal Rosenstock else 9434816ad9SSean Hefty port_priv = ib_get_agent_port(device, port_num); 951bae4dbfSHal Rosenstock 9634816ad9SSean Hefty if (!port_priv) { 977ef5d4b0SIra Weiny dev_err(&device->dev, "Unable to find port agent\n"); 988fc394b1SHal Rosenstock return; 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds 10134816ad9SSean Hefty agent = port_priv->agent[qpn]; 10234816ad9SSean Hefty ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num); 10334816ad9SSean Hefty if (IS_ERR(ah)) { 1047ef5d4b0SIra Weiny dev_err(&device->dev, "ib_create_ah_from_wc error %ld\n", 1051eba843dSMichael Heinz PTR_ERR(ah)); 1068fc394b1SHal Rosenstock return; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 1098e4349d1SIra Weiny if (opa && mad_hdr->base_version != OPA_MGMT_BASE_VERSION) 1108e4349d1SIra Weiny resp_mad_len = IB_MGMT_MAD_SIZE; 1118e4349d1SIra Weiny 11234816ad9SSean Hefty send_buf = ib_create_send_mad(agent, wc->src_qp, wc->pkey_index, 0, 113c9082e51SIra Weiny IB_MGMT_MAD_HDR, 114c9082e51SIra Weiny resp_mad_len - IB_MGMT_MAD_HDR, 115da2dfaa3SIra Weiny GFP_KERNEL, 1168e4349d1SIra Weiny mad_hdr->base_version); 11734816ad9SSean Hefty if (IS_ERR(send_buf)) { 1187ef5d4b0SIra Weiny dev_err(&device->dev, "ib_create_send_mad error\n"); 11934816ad9SSean Hefty goto err1; 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds 122c9082e51SIra Weiny memcpy(send_buf->mad, mad_hdr, resp_mad_len); 12334816ad9SSean Hefty send_buf->ah = ah; 1241bae4dbfSHal Rosenstock 1254139032bSHal Rosenstock if (rdma_cap_ib_switch(device)) { 1261bae4dbfSHal Rosenstock mad_send_wr = container_of(send_buf, 1271bae4dbfSHal Rosenstock struct ib_mad_send_wr_private, 1281bae4dbfSHal Rosenstock send_buf); 1291bae4dbfSHal Rosenstock mad_send_wr->send_wr.wr.ud.port_num = port_num; 1301bae4dbfSHal Rosenstock } 1311bae4dbfSHal Rosenstock 1328fc394b1SHal Rosenstock if (ib_post_send_mad(send_buf, NULL)) { 1337ef5d4b0SIra Weiny dev_err(&device->dev, "ib_post_send_mad error\n"); 13434816ad9SSean Hefty goto err2; 1351da177e4SLinus Torvalds } 1368fc394b1SHal Rosenstock return; 13734816ad9SSean Hefty err2: 13834816ad9SSean Hefty ib_free_send_mad(send_buf); 13934816ad9SSean Hefty err1: 14034816ad9SSean Hefty ib_destroy_ah(ah); 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds static void agent_send_handler(struct ib_mad_agent *mad_agent, 1441da177e4SLinus Torvalds struct ib_mad_send_wc *mad_send_wc) 1451da177e4SLinus Torvalds { 14634816ad9SSean Hefty ib_destroy_ah(mad_send_wc->send_buf->ah); 14734816ad9SSean Hefty ib_free_send_mad(mad_send_wc->send_buf); 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds int ib_agent_port_open(struct ib_device *device, int port_num) 1511da177e4SLinus Torvalds { 1521da177e4SLinus Torvalds struct ib_agent_port_private *port_priv; 1531da177e4SLinus Torvalds unsigned long flags; 15434816ad9SSean Hefty int ret; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds /* Create new device info */ 157de6eb66bSRoland Dreier port_priv = kzalloc(sizeof *port_priv, GFP_KERNEL); 1581da177e4SLinus Torvalds if (!port_priv) { 1597ef5d4b0SIra Weiny dev_err(&device->dev, "No memory for ib_agent_port_private\n"); 1601da177e4SLinus Torvalds ret = -ENOMEM; 1611da177e4SLinus Torvalds goto error1; 1621da177e4SLinus Torvalds } 1631da177e4SLinus Torvalds 16429541e3aSMichael Wang if (rdma_cap_ib_smi(device, port_num)) { 16534816ad9SSean Hefty /* Obtain send only MAD agent for SMI QP */ 16634816ad9SSean Hefty port_priv->agent[0] = ib_register_mad_agent(device, port_num, 16734816ad9SSean Hefty IB_QPT_SMI, NULL, 0, 1681da177e4SLinus Torvalds &agent_send_handler, 1690f29b46dSIra Weiny NULL, NULL, 0); 17034816ad9SSean Hefty if (IS_ERR(port_priv->agent[0])) { 17134816ad9SSean Hefty ret = PTR_ERR(port_priv->agent[0]); 1721da177e4SLinus Torvalds goto error2; 1731da177e4SLinus Torvalds } 174fac70d51SEli Cohen } 1751da177e4SLinus Torvalds 17634816ad9SSean Hefty /* Obtain send only MAD agent for GSI QP */ 17734816ad9SSean Hefty port_priv->agent[1] = ib_register_mad_agent(device, port_num, 17834816ad9SSean Hefty IB_QPT_GSI, NULL, 0, 1791da177e4SLinus Torvalds &agent_send_handler, 1800f29b46dSIra Weiny NULL, NULL, 0); 18134816ad9SSean Hefty if (IS_ERR(port_priv->agent[1])) { 18234816ad9SSean Hefty ret = PTR_ERR(port_priv->agent[1]); 1831da177e4SLinus Torvalds goto error3; 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds spin_lock_irqsave(&ib_agent_port_list_lock, flags); 1871da177e4SLinus Torvalds list_add_tail(&port_priv->port_list, &ib_agent_port_list); 1881da177e4SLinus Torvalds spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds return 0; 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds error3: 193fac70d51SEli Cohen if (port_priv->agent[0]) 19434816ad9SSean Hefty ib_unregister_mad_agent(port_priv->agent[0]); 1951da177e4SLinus Torvalds error2: 1961da177e4SLinus Torvalds kfree(port_priv); 1971da177e4SLinus Torvalds error1: 1981da177e4SLinus Torvalds return ret; 1991da177e4SLinus Torvalds } 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds int ib_agent_port_close(struct ib_device *device, int port_num) 2021da177e4SLinus Torvalds { 2031da177e4SLinus Torvalds struct ib_agent_port_private *port_priv; 2041da177e4SLinus Torvalds unsigned long flags; 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds spin_lock_irqsave(&ib_agent_port_list_lock, flags); 20734816ad9SSean Hefty port_priv = __ib_get_agent_port(device, port_num); 2081da177e4SLinus Torvalds if (port_priv == NULL) { 2091da177e4SLinus Torvalds spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); 2107ef5d4b0SIra Weiny dev_err(&device->dev, "Port %d not found\n", port_num); 2111da177e4SLinus Torvalds return -ENODEV; 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds list_del(&port_priv->port_list); 2141da177e4SLinus Torvalds spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); 2151da177e4SLinus Torvalds 21634816ad9SSean Hefty ib_unregister_mad_agent(port_priv->agent[1]); 217fac70d51SEli Cohen if (port_priv->agent[0]) 21834816ad9SSean Hefty ib_unregister_mad_agent(port_priv->agent[0]); 219fac70d51SEli Cohen 2201da177e4SLinus Torvalds kfree(port_priv); 2211da177e4SLinus Torvalds return 0; 2221da177e4SLinus Torvalds } 223