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