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