Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2004, 2005 Mellanox Technologies Ltd.  All rights reserved.
0003  * Copyright (c) 2004, 2005 Infinicon Corporation.  All rights reserved.
0004  * Copyright (c) 2004, 2005 Intel Corporation.  All rights reserved.
0005  * Copyright (c) 2004, 2005 Topspin Corporation.  All rights reserved.
0006  * Copyright (c) 2004-2007 Voltaire Corporation.  All rights reserved.
0007  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
0008  *
0009  * This software is available to you under a choice of one of two
0010  * licenses.  You may choose to be licensed under the terms of the GNU
0011  * General Public License (GPL) Version 2, available from the file
0012  * COPYING in the main directory of this source tree, or the
0013  * OpenIB.org BSD license below:
0014  *
0015  *     Redistribution and use in source and binary forms, with or
0016  *     without modification, are permitted provided that the following
0017  *     conditions are met:
0018  *
0019  *      - Redistributions of source code must retain the above
0020  *        copyright notice, this list of conditions and the following
0021  *        disclaimer.
0022  *
0023  *      - Redistributions in binary form must reproduce the above
0024  *        copyright notice, this list of conditions and the following
0025  *        disclaimer in the documentation and/or other materials
0026  *        provided with the distribution.
0027  *
0028  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0029  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0030  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0031  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0032  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0033  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0034  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0035  * SOFTWARE.
0036  *
0037  */
0038 
0039 #include <linux/slab.h>
0040 #include <linux/string.h>
0041 
0042 #include "agent.h"
0043 #include "smi.h"
0044 #include "mad_priv.h"
0045 
0046 #define SPFX "ib_agent: "
0047 
0048 struct ib_agent_port_private {
0049     struct list_head port_list;
0050     struct ib_mad_agent *agent[2];
0051 };
0052 
0053 static DEFINE_SPINLOCK(ib_agent_port_list_lock);
0054 static LIST_HEAD(ib_agent_port_list);
0055 
0056 static struct ib_agent_port_private *
0057 __ib_get_agent_port(const struct ib_device *device, int port_num)
0058 {
0059     struct ib_agent_port_private *entry;
0060 
0061     list_for_each_entry(entry, &ib_agent_port_list, port_list) {
0062         if (entry->agent[1]->device == device &&
0063             entry->agent[1]->port_num == port_num)
0064             return entry;
0065     }
0066     return NULL;
0067 }
0068 
0069 static struct ib_agent_port_private *
0070 ib_get_agent_port(const struct ib_device *device, int port_num)
0071 {
0072     struct ib_agent_port_private *entry;
0073     unsigned long flags;
0074 
0075     spin_lock_irqsave(&ib_agent_port_list_lock, flags);
0076     entry = __ib_get_agent_port(device, port_num);
0077     spin_unlock_irqrestore(&ib_agent_port_list_lock, flags);
0078     return entry;
0079 }
0080 
0081 void agent_send_response(const struct ib_mad_hdr *mad_hdr, const struct ib_grh *grh,
0082              const struct ib_wc *wc, const struct ib_device *device,
0083              int port_num, int qpn, size_t resp_mad_len, bool opa)
0084 {
0085     struct ib_agent_port_private *port_priv;
0086     struct ib_mad_agent *agent;
0087     struct ib_mad_send_buf *send_buf;
0088     struct ib_ah *ah;
0089     struct ib_mad_send_wr_private *mad_send_wr;
0090 
0091     if (rdma_cap_ib_switch(device))
0092         port_priv = ib_get_agent_port(device, 0);
0093     else
0094         port_priv = ib_get_agent_port(device, port_num);
0095 
0096     if (!port_priv) {
0097         dev_err(&device->dev, "Unable to find port agent\n");
0098         return;
0099     }
0100 
0101     agent = port_priv->agent[qpn];
0102     ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num);
0103     if (IS_ERR(ah)) {
0104         dev_err(&device->dev, "ib_create_ah_from_wc error %ld\n",
0105             PTR_ERR(ah));
0106         return;
0107     }
0108 
0109     if (opa && mad_hdr->base_version != OPA_MGMT_BASE_VERSION)
0110         resp_mad_len = IB_MGMT_MAD_SIZE;
0111 
0112     send_buf = ib_create_send_mad(agent, wc->src_qp, wc->pkey_index, 0,
0113                       IB_MGMT_MAD_HDR,
0114                       resp_mad_len - IB_MGMT_MAD_HDR,
0115                       GFP_KERNEL,
0116                       mad_hdr->base_version);
0117     if (IS_ERR(send_buf)) {
0118         dev_err(&device->dev, "ib_create_send_mad error\n");
0119         goto err1;
0120     }
0121 
0122     memcpy(send_buf->mad, mad_hdr, resp_mad_len);
0123     send_buf->ah = ah;
0124 
0125     if (rdma_cap_ib_switch(device)) {
0126         mad_send_wr = container_of(send_buf,
0127                        struct ib_mad_send_wr_private,
0128                        send_buf);
0129         mad_send_wr->send_wr.port_num = port_num;
0130     }
0131 
0132     if (ib_post_send_mad(send_buf, NULL)) {
0133         dev_err(&device->dev, "ib_post_send_mad error\n");
0134         goto err2;
0135     }
0136     return;
0137 err2:
0138     ib_free_send_mad(send_buf);
0139 err1:
0140     rdma_destroy_ah(ah, RDMA_DESTROY_AH_SLEEPABLE);
0141 }
0142 
0143 static void agent_send_handler(struct ib_mad_agent *mad_agent,
0144                    struct ib_mad_send_wc *mad_send_wc)
0145 {
0146     rdma_destroy_ah(mad_send_wc->send_buf->ah, RDMA_DESTROY_AH_SLEEPABLE);
0147     ib_free_send_mad(mad_send_wc->send_buf);
0148 }
0149 
0150 int ib_agent_port_open(struct ib_device *device, int port_num)
0151 {
0152     struct ib_agent_port_private *port_priv;
0153     unsigned long flags;
0154     int ret;
0155 
0156     /* Create new device info */
0157     port_priv = kzalloc(sizeof *port_priv, GFP_KERNEL);
0158     if (!port_priv) {
0159         ret = -ENOMEM;
0160         goto error1;
0161     }
0162 
0163     if (rdma_cap_ib_smi(device, port_num)) {
0164         /* Obtain send only MAD agent for SMI QP */
0165         port_priv->agent[0] = ib_register_mad_agent(device, port_num,
0166                                 IB_QPT_SMI, NULL, 0,
0167                                 &agent_send_handler,
0168                                 NULL, NULL, 0);
0169         if (IS_ERR(port_priv->agent[0])) {
0170             ret = PTR_ERR(port_priv->agent[0]);
0171             goto error2;
0172         }
0173     }
0174 
0175     /* Obtain send only MAD agent for GSI QP */
0176     port_priv->agent[1] = ib_register_mad_agent(device, port_num,
0177                             IB_QPT_GSI, NULL, 0,
0178                             &agent_send_handler,
0179                             NULL, NULL, 0);
0180     if (IS_ERR(port_priv->agent[1])) {
0181         ret = PTR_ERR(port_priv->agent[1]);
0182         goto error3;
0183     }
0184 
0185     spin_lock_irqsave(&ib_agent_port_list_lock, flags);
0186     list_add_tail(&port_priv->port_list, &ib_agent_port_list);
0187     spin_unlock_irqrestore(&ib_agent_port_list_lock, flags);
0188 
0189     return 0;
0190 
0191 error3:
0192     if (port_priv->agent[0])
0193         ib_unregister_mad_agent(port_priv->agent[0]);
0194 error2:
0195     kfree(port_priv);
0196 error1:
0197     return ret;
0198 }
0199 
0200 int ib_agent_port_close(struct ib_device *device, int port_num)
0201 {
0202     struct ib_agent_port_private *port_priv;
0203     unsigned long flags;
0204 
0205     spin_lock_irqsave(&ib_agent_port_list_lock, flags);
0206     port_priv = __ib_get_agent_port(device, port_num);
0207     if (port_priv == NULL) {
0208         spin_unlock_irqrestore(&ib_agent_port_list_lock, flags);
0209         dev_err(&device->dev, "Port %d not found\n", port_num);
0210         return -ENODEV;
0211     }
0212     list_del(&port_priv->port_list);
0213     spin_unlock_irqrestore(&ib_agent_port_list_lock, flags);
0214 
0215     ib_unregister_mad_agent(port_priv->agent[1]);
0216     if (port_priv->agent[0])
0217         ib_unregister_mad_agent(port_priv->agent[0]);
0218 
0219     kfree(port_priv);
0220     return 0;
0221 }