diff options
Diffstat (limited to 'drivers/infiniband/core/agent.c')
-rw-r--r-- | drivers/infiniband/core/agent.c | 293 |
1 files changed, 76 insertions, 217 deletions
diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c index 5ac86f566dc0..0c3c6952faae 100644 --- a/drivers/infiniband/core/agent.c +++ b/drivers/infiniband/core/agent.c | |||
@@ -37,58 +37,41 @@ | |||
37 | * $Id: agent.c 1389 2004-12-27 22:56:47Z roland $ | 37 | * $Id: agent.c 1389 2004-12-27 22:56:47Z roland $ |
38 | */ | 38 | */ |
39 | 39 | ||
40 | #include <linux/dma-mapping.h> | 40 | #include "agent.h" |
41 | 41 | #include "smi.h" | |
42 | #include <asm/bug.h> | ||
43 | 42 | ||
44 | #include <rdma/ib_smi.h> | 43 | #define SPFX "ib_agent: " |
45 | 44 | ||
46 | #include "smi.h" | 45 | struct ib_agent_port_private { |
47 | #include "agent_priv.h" | 46 | struct list_head port_list; |
48 | #include "mad_priv.h" | 47 | struct ib_mad_agent *agent[2]; |
49 | #include "agent.h" | 48 | }; |
50 | 49 | ||
51 | spinlock_t ib_agent_port_list_lock; | 50 | static DEFINE_SPINLOCK(ib_agent_port_list_lock); |
52 | static LIST_HEAD(ib_agent_port_list); | 51 | static LIST_HEAD(ib_agent_port_list); |
53 | 52 | ||
54 | /* | 53 | static struct ib_agent_port_private * |
55 | * Caller must hold ib_agent_port_list_lock | 54 | __ib_get_agent_port(struct ib_device *device, int port_num) |
56 | */ | ||
57 | static inline struct ib_agent_port_private * | ||
58 | __ib_get_agent_port(struct ib_device *device, int port_num, | ||
59 | struct ib_mad_agent *mad_agent) | ||
60 | { | 55 | { |
61 | struct ib_agent_port_private *entry; | 56 | struct ib_agent_port_private *entry; |
62 | 57 | ||
63 | BUG_ON(!(!!device ^ !!mad_agent)); /* Exactly one MUST be (!NULL) */ | 58 | list_for_each_entry(entry, &ib_agent_port_list, port_list) { |
64 | 59 | if (entry->agent[0]->device == device && | |
65 | if (device) { | 60 | entry->agent[0]->port_num == port_num) |
66 | list_for_each_entry(entry, &ib_agent_port_list, port_list) { | 61 | return entry; |
67 | if (entry->smp_agent->device == device && | ||
68 | entry->port_num == port_num) | ||
69 | return entry; | ||
70 | } | ||
71 | } else { | ||
72 | list_for_each_entry(entry, &ib_agent_port_list, port_list) { | ||
73 | if ((entry->smp_agent == mad_agent) || | ||
74 | (entry->perf_mgmt_agent == mad_agent)) | ||
75 | return entry; | ||
76 | } | ||
77 | } | 62 | } |
78 | return NULL; | 63 | return NULL; |
79 | } | 64 | } |
80 | 65 | ||
81 | static inline struct ib_agent_port_private * | 66 | static struct ib_agent_port_private * |
82 | ib_get_agent_port(struct ib_device *device, int port_num, | 67 | ib_get_agent_port(struct ib_device *device, int port_num) |
83 | struct ib_mad_agent *mad_agent) | ||
84 | { | 68 | { |
85 | struct ib_agent_port_private *entry; | 69 | struct ib_agent_port_private *entry; |
86 | unsigned long flags; | 70 | unsigned long flags; |
87 | 71 | ||
88 | spin_lock_irqsave(&ib_agent_port_list_lock, flags); | 72 | spin_lock_irqsave(&ib_agent_port_list_lock, flags); |
89 | entry = __ib_get_agent_port(device, port_num, mad_agent); | 73 | entry = __ib_get_agent_port(device, port_num); |
90 | spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); | 74 | spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); |
91 | |||
92 | return entry; | 75 | return entry; |
93 | } | 76 | } |
94 | 77 | ||
@@ -100,192 +83,76 @@ int smi_check_local_dr_smp(struct ib_smp *smp, | |||
100 | 83 | ||
101 | if (smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) | 84 | if (smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) |
102 | return 1; | 85 | return 1; |
103 | port_priv = ib_get_agent_port(device, port_num, NULL); | 86 | |
87 | port_priv = ib_get_agent_port(device, port_num); | ||
104 | if (!port_priv) { | 88 | if (!port_priv) { |
105 | printk(KERN_DEBUG SPFX "smi_check_local_dr_smp %s port %d " | 89 | printk(KERN_DEBUG SPFX "smi_check_local_dr_smp %s port %d " |
106 | "not open\n", | 90 | "not open\n", device->name, port_num); |
107 | device->name, port_num); | ||
108 | return 1; | 91 | return 1; |
109 | } | 92 | } |
110 | 93 | ||
111 | return smi_check_local_smp(port_priv->smp_agent, smp); | 94 | return smi_check_local_smp(port_priv->agent[0], smp); |
112 | } | 95 | } |
113 | 96 | ||
114 | static int agent_mad_send(struct ib_mad_agent *mad_agent, | 97 | int agent_send_response(struct ib_mad *mad, struct ib_grh *grh, |
115 | struct ib_agent_port_private *port_priv, | 98 | struct ib_wc *wc, struct ib_device *device, |
116 | struct ib_mad_private *mad_priv, | 99 | int port_num, int qpn) |
117 | struct ib_grh *grh, | ||
118 | struct ib_wc *wc) | ||
119 | { | 100 | { |
120 | struct ib_agent_send_wr *agent_send_wr; | 101 | struct ib_agent_port_private *port_priv; |
121 | struct ib_sge gather_list; | 102 | struct ib_mad_agent *agent; |
122 | struct ib_send_wr send_wr; | 103 | struct ib_mad_send_buf *send_buf; |
123 | struct ib_send_wr *bad_send_wr; | 104 | struct ib_ah *ah; |
124 | struct ib_ah_attr ah_attr; | 105 | int ret; |
125 | unsigned long flags; | ||
126 | int ret = 1; | ||
127 | |||
128 | agent_send_wr = kmalloc(sizeof(*agent_send_wr), GFP_KERNEL); | ||
129 | if (!agent_send_wr) | ||
130 | goto out; | ||
131 | agent_send_wr->mad = mad_priv; | ||
132 | |||
133 | gather_list.addr = dma_map_single(mad_agent->device->dma_device, | ||
134 | &mad_priv->mad, | ||
135 | sizeof(mad_priv->mad), | ||
136 | DMA_TO_DEVICE); | ||
137 | gather_list.length = sizeof(mad_priv->mad); | ||
138 | gather_list.lkey = mad_agent->mr->lkey; | ||
139 | |||
140 | send_wr.next = NULL; | ||
141 | send_wr.opcode = IB_WR_SEND; | ||
142 | send_wr.sg_list = &gather_list; | ||
143 | send_wr.num_sge = 1; | ||
144 | send_wr.wr.ud.remote_qpn = wc->src_qp; /* DQPN */ | ||
145 | send_wr.wr.ud.timeout_ms = 0; | ||
146 | send_wr.send_flags = IB_SEND_SIGNALED | IB_SEND_SOLICITED; | ||
147 | 106 | ||
148 | ah_attr.dlid = wc->slid; | 107 | port_priv = ib_get_agent_port(device, port_num); |
149 | ah_attr.port_num = mad_agent->port_num; | 108 | if (!port_priv) { |
150 | ah_attr.src_path_bits = wc->dlid_path_bits; | 109 | printk(KERN_ERR SPFX "Unable to find port agent\n"); |
151 | ah_attr.sl = wc->sl; | 110 | return -ENODEV; |
152 | ah_attr.static_rate = 0; | ||
153 | ah_attr.ah_flags = 0; /* No GRH */ | ||
154 | if (mad_priv->mad.mad.mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT) { | ||
155 | if (wc->wc_flags & IB_WC_GRH) { | ||
156 | ah_attr.ah_flags = IB_AH_GRH; | ||
157 | /* Should sgid be looked up ? */ | ||
158 | ah_attr.grh.sgid_index = 0; | ||
159 | ah_attr.grh.hop_limit = grh->hop_limit; | ||
160 | ah_attr.grh.flow_label = be32_to_cpu( | ||
161 | grh->version_tclass_flow) & 0xfffff; | ||
162 | ah_attr.grh.traffic_class = (be32_to_cpu( | ||
163 | grh->version_tclass_flow) >> 20) & 0xff; | ||
164 | memcpy(ah_attr.grh.dgid.raw, | ||
165 | grh->sgid.raw, | ||
166 | sizeof(ah_attr.grh.dgid)); | ||
167 | } | ||
168 | } | 111 | } |
169 | 112 | ||
170 | agent_send_wr->ah = ib_create_ah(mad_agent->qp->pd, &ah_attr); | 113 | agent = port_priv->agent[qpn]; |
171 | if (IS_ERR(agent_send_wr->ah)) { | 114 | ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num); |
172 | printk(KERN_ERR SPFX "No memory for address handle\n"); | 115 | if (IS_ERR(ah)) { |
173 | kfree(agent_send_wr); | 116 | ret = PTR_ERR(ah); |
174 | goto out; | 117 | printk(KERN_ERR SPFX "ib_create_ah_from_wc error:%d\n", ret); |
118 | return ret; | ||
175 | } | 119 | } |
176 | 120 | ||
177 | send_wr.wr.ud.ah = agent_send_wr->ah; | 121 | send_buf = ib_create_send_mad(agent, wc->src_qp, wc->pkey_index, 0, |
178 | if (mad_priv->mad.mad.mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT) { | 122 | IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, |
179 | send_wr.wr.ud.pkey_index = wc->pkey_index; | 123 | GFP_KERNEL); |
180 | send_wr.wr.ud.remote_qkey = IB_QP1_QKEY; | 124 | if (IS_ERR(send_buf)) { |
181 | } else { /* for SMPs */ | 125 | ret = PTR_ERR(send_buf); |
182 | send_wr.wr.ud.pkey_index = 0; | 126 | printk(KERN_ERR SPFX "ib_create_send_mad error:%d\n", ret); |
183 | send_wr.wr.ud.remote_qkey = 0; | 127 | goto err1; |
184 | } | 128 | } |
185 | send_wr.wr.ud.mad_hdr = &mad_priv->mad.mad.mad_hdr; | ||
186 | send_wr.wr_id = (unsigned long)agent_send_wr; | ||
187 | 129 | ||
188 | pci_unmap_addr_set(agent_send_wr, mapping, gather_list.addr); | 130 | memcpy(send_buf->mad, mad, sizeof *mad); |
189 | 131 | send_buf->ah = ah; | |
190 | /* Send */ | 132 | if ((ret = ib_post_send_mad(send_buf, NULL))) { |
191 | spin_lock_irqsave(&port_priv->send_list_lock, flags); | 133 | printk(KERN_ERR SPFX "ib_post_send_mad error:%d\n", ret); |
192 | if (ib_post_send_mad(mad_agent, &send_wr, &bad_send_wr)) { | 134 | goto err2; |
193 | spin_unlock_irqrestore(&port_priv->send_list_lock, flags); | ||
194 | dma_unmap_single(mad_agent->device->dma_device, | ||
195 | pci_unmap_addr(agent_send_wr, mapping), | ||
196 | sizeof(mad_priv->mad), | ||
197 | DMA_TO_DEVICE); | ||
198 | ib_destroy_ah(agent_send_wr->ah); | ||
199 | kfree(agent_send_wr); | ||
200 | } else { | ||
201 | list_add_tail(&agent_send_wr->send_list, | ||
202 | &port_priv->send_posted_list); | ||
203 | spin_unlock_irqrestore(&port_priv->send_list_lock, flags); | ||
204 | ret = 0; | ||
205 | } | 135 | } |
206 | 136 | return 0; | |
207 | out: | 137 | err2: |
138 | ib_free_send_mad(send_buf); | ||
139 | err1: | ||
140 | ib_destroy_ah(ah); | ||
208 | return ret; | 141 | return ret; |
209 | } | 142 | } |
210 | 143 | ||
211 | int agent_send(struct ib_mad_private *mad, | ||
212 | struct ib_grh *grh, | ||
213 | struct ib_wc *wc, | ||
214 | struct ib_device *device, | ||
215 | int port_num) | ||
216 | { | ||
217 | struct ib_agent_port_private *port_priv; | ||
218 | struct ib_mad_agent *mad_agent; | ||
219 | |||
220 | port_priv = ib_get_agent_port(device, port_num, NULL); | ||
221 | if (!port_priv) { | ||
222 | printk(KERN_DEBUG SPFX "agent_send %s port %d not open\n", | ||
223 | device->name, port_num); | ||
224 | return 1; | ||
225 | } | ||
226 | |||
227 | /* Get mad agent based on mgmt_class in MAD */ | ||
228 | switch (mad->mad.mad.mad_hdr.mgmt_class) { | ||
229 | case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: | ||
230 | case IB_MGMT_CLASS_SUBN_LID_ROUTED: | ||
231 | mad_agent = port_priv->smp_agent; | ||
232 | break; | ||
233 | case IB_MGMT_CLASS_PERF_MGMT: | ||
234 | mad_agent = port_priv->perf_mgmt_agent; | ||
235 | break; | ||
236 | default: | ||
237 | return 1; | ||
238 | } | ||
239 | |||
240 | return agent_mad_send(mad_agent, port_priv, mad, grh, wc); | ||
241 | } | ||
242 | |||
243 | static void agent_send_handler(struct ib_mad_agent *mad_agent, | 144 | static void agent_send_handler(struct ib_mad_agent *mad_agent, |
244 | struct ib_mad_send_wc *mad_send_wc) | 145 | struct ib_mad_send_wc *mad_send_wc) |
245 | { | 146 | { |
246 | struct ib_agent_port_private *port_priv; | 147 | ib_destroy_ah(mad_send_wc->send_buf->ah); |
247 | struct ib_agent_send_wr *agent_send_wr; | 148 | ib_free_send_mad(mad_send_wc->send_buf); |
248 | unsigned long flags; | ||
249 | |||
250 | /* Find matching MAD agent */ | ||
251 | port_priv = ib_get_agent_port(NULL, 0, mad_agent); | ||
252 | if (!port_priv) { | ||
253 | printk(KERN_ERR SPFX "agent_send_handler: no matching MAD " | ||
254 | "agent %p\n", mad_agent); | ||
255 | return; | ||
256 | } | ||
257 | |||
258 | agent_send_wr = (struct ib_agent_send_wr *)(unsigned long)mad_send_wc->wr_id; | ||
259 | spin_lock_irqsave(&port_priv->send_list_lock, flags); | ||
260 | /* Remove completed send from posted send MAD list */ | ||
261 | list_del(&agent_send_wr->send_list); | ||
262 | spin_unlock_irqrestore(&port_priv->send_list_lock, flags); | ||
263 | |||
264 | dma_unmap_single(mad_agent->device->dma_device, | ||
265 | pci_unmap_addr(agent_send_wr, mapping), | ||
266 | sizeof(agent_send_wr->mad->mad), | ||
267 | DMA_TO_DEVICE); | ||
268 | |||
269 | ib_destroy_ah(agent_send_wr->ah); | ||
270 | |||
271 | /* Release allocated memory */ | ||
272 | kmem_cache_free(ib_mad_cache, agent_send_wr->mad); | ||
273 | kfree(agent_send_wr); | ||
274 | } | 149 | } |
275 | 150 | ||
276 | int ib_agent_port_open(struct ib_device *device, int port_num) | 151 | int ib_agent_port_open(struct ib_device *device, int port_num) |
277 | { | 152 | { |
278 | int ret; | ||
279 | struct ib_agent_port_private *port_priv; | 153 | struct ib_agent_port_private *port_priv; |
280 | unsigned long flags; | 154 | unsigned long flags; |
281 | 155 | int ret; | |
282 | /* First, check if port already open for SMI */ | ||
283 | port_priv = ib_get_agent_port(device, port_num, NULL); | ||
284 | if (port_priv) { | ||
285 | printk(KERN_DEBUG SPFX "%s port %d already open\n", | ||
286 | device->name, port_num); | ||
287 | return 0; | ||
288 | } | ||
289 | 156 | ||
290 | /* Create new device info */ | 157 | /* Create new device info */ |
291 | port_priv = kmalloc(sizeof *port_priv, GFP_KERNEL); | 158 | port_priv = kmalloc(sizeof *port_priv, GFP_KERNEL); |
@@ -294,32 +161,25 @@ int ib_agent_port_open(struct ib_device *device, int port_num) | |||
294 | ret = -ENOMEM; | 161 | ret = -ENOMEM; |
295 | goto error1; | 162 | goto error1; |
296 | } | 163 | } |
297 | |||
298 | memset(port_priv, 0, sizeof *port_priv); | 164 | memset(port_priv, 0, sizeof *port_priv); |
299 | port_priv->port_num = port_num; | ||
300 | spin_lock_init(&port_priv->send_list_lock); | ||
301 | INIT_LIST_HEAD(&port_priv->send_posted_list); | ||
302 | 165 | ||
303 | /* Obtain send only MAD agent for SM class (SMI QP) */ | 166 | /* Obtain send only MAD agent for SMI QP */ |
304 | port_priv->smp_agent = ib_register_mad_agent(device, port_num, | 167 | port_priv->agent[0] = ib_register_mad_agent(device, port_num, |
305 | IB_QPT_SMI, | 168 | IB_QPT_SMI, NULL, 0, |
306 | NULL, 0, | ||
307 | &agent_send_handler, | 169 | &agent_send_handler, |
308 | NULL, NULL); | 170 | NULL, NULL); |
309 | 171 | if (IS_ERR(port_priv->agent[0])) { | |
310 | if (IS_ERR(port_priv->smp_agent)) { | 172 | ret = PTR_ERR(port_priv->agent[0]); |
311 | ret = PTR_ERR(port_priv->smp_agent); | ||
312 | goto error2; | 173 | goto error2; |
313 | } | 174 | } |
314 | 175 | ||
315 | /* Obtain send only MAD agent for PerfMgmt class (GSI QP) */ | 176 | /* Obtain send only MAD agent for GSI QP */ |
316 | port_priv->perf_mgmt_agent = ib_register_mad_agent(device, port_num, | 177 | port_priv->agent[1] = ib_register_mad_agent(device, port_num, |
317 | IB_QPT_GSI, | 178 | IB_QPT_GSI, NULL, 0, |
318 | NULL, 0, | 179 | &agent_send_handler, |
319 | &agent_send_handler, | 180 | NULL, NULL); |
320 | NULL, NULL); | 181 | if (IS_ERR(port_priv->agent[1])) { |
321 | if (IS_ERR(port_priv->perf_mgmt_agent)) { | 182 | ret = PTR_ERR(port_priv->agent[1]); |
322 | ret = PTR_ERR(port_priv->perf_mgmt_agent); | ||
323 | goto error3; | 183 | goto error3; |
324 | } | 184 | } |
325 | 185 | ||
@@ -330,7 +190,7 @@ int ib_agent_port_open(struct ib_device *device, int port_num) | |||
330 | return 0; | 190 | return 0; |
331 | 191 | ||
332 | error3: | 192 | error3: |
333 | ib_unregister_mad_agent(port_priv->smp_agent); | 193 | ib_unregister_mad_agent(port_priv->agent[0]); |
334 | error2: | 194 | error2: |
335 | kfree(port_priv); | 195 | kfree(port_priv); |
336 | error1: | 196 | error1: |
@@ -343,7 +203,7 @@ int ib_agent_port_close(struct ib_device *device, int port_num) | |||
343 | unsigned long flags; | 203 | unsigned long flags; |
344 | 204 | ||
345 | spin_lock_irqsave(&ib_agent_port_list_lock, flags); | 205 | spin_lock_irqsave(&ib_agent_port_list_lock, flags); |
346 | port_priv = __ib_get_agent_port(device, port_num, NULL); | 206 | port_priv = __ib_get_agent_port(device, port_num); |
347 | if (port_priv == NULL) { | 207 | if (port_priv == NULL) { |
348 | spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); | 208 | spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); |
349 | printk(KERN_ERR SPFX "Port %d not found\n", port_num); | 209 | printk(KERN_ERR SPFX "Port %d not found\n", port_num); |
@@ -352,9 +212,8 @@ int ib_agent_port_close(struct ib_device *device, int port_num) | |||
352 | list_del(&port_priv->port_list); | 212 | list_del(&port_priv->port_list); |
353 | spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); | 213 | spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); |
354 | 214 | ||
355 | ib_unregister_mad_agent(port_priv->perf_mgmt_agent); | 215 | ib_unregister_mad_agent(port_priv->agent[1]); |
356 | ib_unregister_mad_agent(port_priv->smp_agent); | 216 | ib_unregister_mad_agent(port_priv->agent[0]); |
357 | kfree(port_priv); | 217 | kfree(port_priv); |
358 | |||
359 | return 0; | 218 | return 0; |
360 | } | 219 | } |