diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/infiniband/core |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/infiniband/core')
-rw-r--r-- | drivers/infiniband/core/Makefile | 12 | ||||
-rw-r--r-- | drivers/infiniband/core/agent.c | 373 | ||||
-rw-r--r-- | drivers/infiniband/core/agent.h | 55 | ||||
-rw-r--r-- | drivers/infiniband/core/agent_priv.h | 63 | ||||
-rw-r--r-- | drivers/infiniband/core/cache.c | 365 | ||||
-rw-r--r-- | drivers/infiniband/core/core_priv.h | 52 | ||||
-rw-r--r-- | drivers/infiniband/core/device.c | 614 | ||||
-rw-r--r-- | drivers/infiniband/core/fmr_pool.c | 507 | ||||
-rw-r--r-- | drivers/infiniband/core/mad.c | 2714 | ||||
-rw-r--r-- | drivers/infiniband/core/mad_priv.h | 199 | ||||
-rw-r--r-- | drivers/infiniband/core/packer.c | 201 | ||||
-rw-r--r-- | drivers/infiniband/core/sa_query.c | 866 | ||||
-rw-r--r-- | drivers/infiniband/core/smi.c | 234 | ||||
-rw-r--r-- | drivers/infiniband/core/smi.h | 67 | ||||
-rw-r--r-- | drivers/infiniband/core/sysfs.c | 762 | ||||
-rw-r--r-- | drivers/infiniband/core/ud_header.c | 365 | ||||
-rw-r--r-- | drivers/infiniband/core/user_mad.c | 840 | ||||
-rw-r--r-- | drivers/infiniband/core/verbs.c | 434 |
18 files changed, 8723 insertions, 0 deletions
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile new file mode 100644 index 000000000000..d2dbfb52c0a3 --- /dev/null +++ b/drivers/infiniband/core/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | EXTRA_CFLAGS += -Idrivers/infiniband/include | ||
2 | |||
3 | obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o ib_umad.o | ||
4 | |||
5 | ib_core-y := packer.o ud_header.o verbs.o sysfs.o \ | ||
6 | device.o fmr_pool.o cache.o | ||
7 | |||
8 | ib_mad-y := mad.o smi.o agent.o | ||
9 | |||
10 | ib_sa-y := sa_query.o | ||
11 | |||
12 | ib_umad-y := user_mad.o | ||
diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c new file mode 100644 index 000000000000..7aee5ebf3f01 --- /dev/null +++ b/drivers/infiniband/core/agent.c | |||
@@ -0,0 +1,373 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. | ||
3 | * Copyright (c) 2004 Infinicon Corporation. All rights reserved. | ||
4 | * Copyright (c) 2004 Intel Corporation. All rights reserved. | ||
5 | * Copyright (c) 2004 Topspin Corporation. All rights reserved. | ||
6 | * Copyright (c) 2004 Voltaire Corporation. All rights reserved. | ||
7 | * | ||
8 | * This software is available to you under a choice of one of two | ||
9 | * licenses. You may choose to be licensed under the terms of the GNU | ||
10 | * General Public License (GPL) Version 2, available from the file | ||
11 | * COPYING in the main directory of this source tree, or the | ||
12 | * OpenIB.org BSD license below: | ||
13 | * | ||
14 | * Redistribution and use in source and binary forms, with or | ||
15 | * without modification, are permitted provided that the following | ||
16 | * conditions are met: | ||
17 | * | ||
18 | * - Redistributions of source code must retain the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer. | ||
21 | * | ||
22 | * - Redistributions in binary form must reproduce the above | ||
23 | * copyright notice, this list of conditions and the following | ||
24 | * disclaimer in the documentation and/or other materials | ||
25 | * provided with the distribution. | ||
26 | * | ||
27 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
28 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
29 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
30 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
31 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
32 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
33 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
34 | * SOFTWARE. | ||
35 | * | ||
36 | * $Id: agent.c 1389 2004-12-27 22:56:47Z roland $ | ||
37 | */ | ||
38 | |||
39 | #include <linux/dma-mapping.h> | ||
40 | |||
41 | #include <asm/bug.h> | ||
42 | |||
43 | #include <ib_smi.h> | ||
44 | |||
45 | #include "smi.h" | ||
46 | #include "agent_priv.h" | ||
47 | #include "mad_priv.h" | ||
48 | #include "agent.h" | ||
49 | |||
50 | spinlock_t ib_agent_port_list_lock; | ||
51 | static LIST_HEAD(ib_agent_port_list); | ||
52 | |||
53 | /* | ||
54 | * Caller must hold ib_agent_port_list_lock | ||
55 | */ | ||
56 | static inline struct ib_agent_port_private * | ||
57 | __ib_get_agent_port(struct ib_device *device, int port_num, | ||
58 | struct ib_mad_agent *mad_agent) | ||
59 | { | ||
60 | struct ib_agent_port_private *entry; | ||
61 | |||
62 | BUG_ON(!(!!device ^ !!mad_agent)); /* Exactly one MUST be (!NULL) */ | ||
63 | |||
64 | if (device) { | ||
65 | list_for_each_entry(entry, &ib_agent_port_list, port_list) { | ||
66 | if (entry->smp_agent->device == device && | ||
67 | entry->port_num == port_num) | ||
68 | return entry; | ||
69 | } | ||
70 | } else { | ||
71 | list_for_each_entry(entry, &ib_agent_port_list, port_list) { | ||
72 | if ((entry->smp_agent == mad_agent) || | ||
73 | (entry->perf_mgmt_agent == mad_agent)) | ||
74 | return entry; | ||
75 | } | ||
76 | } | ||
77 | return NULL; | ||
78 | } | ||
79 | |||
80 | static inline struct ib_agent_port_private * | ||
81 | ib_get_agent_port(struct ib_device *device, int port_num, | ||
82 | struct ib_mad_agent *mad_agent) | ||
83 | { | ||
84 | struct ib_agent_port_private *entry; | ||
85 | unsigned long flags; | ||
86 | |||
87 | spin_lock_irqsave(&ib_agent_port_list_lock, flags); | ||
88 | entry = __ib_get_agent_port(device, port_num, mad_agent); | ||
89 | spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); | ||
90 | |||
91 | return entry; | ||
92 | } | ||
93 | |||
94 | int smi_check_local_dr_smp(struct ib_smp *smp, | ||
95 | struct ib_device *device, | ||
96 | int port_num) | ||
97 | { | ||
98 | struct ib_agent_port_private *port_priv; | ||
99 | |||
100 | if (smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) | ||
101 | return 1; | ||
102 | port_priv = ib_get_agent_port(device, port_num, NULL); | ||
103 | if (!port_priv) { | ||
104 | printk(KERN_DEBUG SPFX "smi_check_local_dr_smp %s port %d " | ||
105 | "not open\n", | ||
106 | device->name, port_num); | ||
107 | return 1; | ||
108 | } | ||
109 | |||
110 | return smi_check_local_smp(port_priv->smp_agent, smp); | ||
111 | } | ||
112 | |||
113 | static int agent_mad_send(struct ib_mad_agent *mad_agent, | ||
114 | struct ib_agent_port_private *port_priv, | ||
115 | struct ib_mad_private *mad_priv, | ||
116 | struct ib_grh *grh, | ||
117 | struct ib_wc *wc) | ||
118 | { | ||
119 | struct ib_agent_send_wr *agent_send_wr; | ||
120 | struct ib_sge gather_list; | ||
121 | struct ib_send_wr send_wr; | ||
122 | struct ib_send_wr *bad_send_wr; | ||
123 | struct ib_ah_attr ah_attr; | ||
124 | unsigned long flags; | ||
125 | int ret = 1; | ||
126 | |||
127 | agent_send_wr = kmalloc(sizeof(*agent_send_wr), GFP_KERNEL); | ||
128 | if (!agent_send_wr) | ||
129 | goto out; | ||
130 | agent_send_wr->mad = mad_priv; | ||
131 | |||
132 | /* PCI mapping */ | ||
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 = (*port_priv->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 | |||
148 | ah_attr.dlid = wc->slid; | ||
149 | ah_attr.port_num = mad_agent->port_num; | ||
150 | ah_attr.src_path_bits = wc->dlid_path_bits; | ||
151 | ah_attr.sl = wc->sl; | ||
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_cpup( | ||
161 | &grh->version_tclass_flow) & 0xfffff; | ||
162 | ah_attr.grh.traffic_class = (be32_to_cpup( | ||
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 | } | ||
169 | |||
170 | agent_send_wr->ah = ib_create_ah(mad_agent->qp->pd, &ah_attr); | ||
171 | if (IS_ERR(agent_send_wr->ah)) { | ||
172 | printk(KERN_ERR SPFX "No memory for address handle\n"); | ||
173 | kfree(agent_send_wr); | ||
174 | goto out; | ||
175 | } | ||
176 | |||
177 | send_wr.wr.ud.ah = agent_send_wr->ah; | ||
178 | if (mad_priv->mad.mad.mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT) { | ||
179 | send_wr.wr.ud.pkey_index = wc->pkey_index; | ||
180 | send_wr.wr.ud.remote_qkey = IB_QP1_QKEY; | ||
181 | } else { /* for SMPs */ | ||
182 | send_wr.wr.ud.pkey_index = 0; | ||
183 | send_wr.wr.ud.remote_qkey = 0; | ||
184 | } | ||
185 | send_wr.wr.ud.mad_hdr = &mad_priv->mad.mad.mad_hdr; | ||
186 | send_wr.wr_id = (unsigned long)agent_send_wr; | ||
187 | |||
188 | pci_unmap_addr_set(agent_send_wr, mapping, gather_list.addr); | ||
189 | |||
190 | /* Send */ | ||
191 | spin_lock_irqsave(&port_priv->send_list_lock, flags); | ||
192 | if (ib_post_send_mad(mad_agent, &send_wr, &bad_send_wr)) { | ||
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 | } | ||
206 | |||
207 | out: | ||
208 | return ret; | ||
209 | } | ||
210 | |||
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, | ||
244 | struct ib_mad_send_wc *mad_send_wc) | ||
245 | { | ||
246 | struct ib_agent_port_private *port_priv; | ||
247 | struct ib_agent_send_wr *agent_send_wr; | ||
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 | /* Unmap PCI */ | ||
265 | dma_unmap_single(mad_agent->device->dma_device, | ||
266 | pci_unmap_addr(agent_send_wr, mapping), | ||
267 | sizeof(agent_send_wr->mad->mad), | ||
268 | DMA_TO_DEVICE); | ||
269 | |||
270 | ib_destroy_ah(agent_send_wr->ah); | ||
271 | |||
272 | /* Release allocated memory */ | ||
273 | kmem_cache_free(ib_mad_cache, agent_send_wr->mad); | ||
274 | kfree(agent_send_wr); | ||
275 | } | ||
276 | |||
277 | int ib_agent_port_open(struct ib_device *device, int port_num) | ||
278 | { | ||
279 | int ret; | ||
280 | struct ib_agent_port_private *port_priv; | ||
281 | unsigned long flags; | ||
282 | |||
283 | /* First, check if port already open for SMI */ | ||
284 | port_priv = ib_get_agent_port(device, port_num, NULL); | ||
285 | if (port_priv) { | ||
286 | printk(KERN_DEBUG SPFX "%s port %d already open\n", | ||
287 | device->name, port_num); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | /* Create new device info */ | ||
292 | port_priv = kmalloc(sizeof *port_priv, GFP_KERNEL); | ||
293 | if (!port_priv) { | ||
294 | printk(KERN_ERR SPFX "No memory for ib_agent_port_private\n"); | ||
295 | ret = -ENOMEM; | ||
296 | goto error1; | ||
297 | } | ||
298 | |||
299 | memset(port_priv, 0, sizeof *port_priv); | ||
300 | port_priv->port_num = port_num; | ||
301 | spin_lock_init(&port_priv->send_list_lock); | ||
302 | INIT_LIST_HEAD(&port_priv->send_posted_list); | ||
303 | |||
304 | /* Obtain send only MAD agent for SM class (SMI QP) */ | ||
305 | port_priv->smp_agent = ib_register_mad_agent(device, port_num, | ||
306 | IB_QPT_SMI, | ||
307 | NULL, 0, | ||
308 | &agent_send_handler, | ||
309 | NULL, NULL); | ||
310 | |||
311 | if (IS_ERR(port_priv->smp_agent)) { | ||
312 | ret = PTR_ERR(port_priv->smp_agent); | ||
313 | goto error2; | ||
314 | } | ||
315 | |||
316 | /* Obtain send only MAD agent for PerfMgmt class (GSI QP) */ | ||
317 | port_priv->perf_mgmt_agent = ib_register_mad_agent(device, port_num, | ||
318 | IB_QPT_GSI, | ||
319 | NULL, 0, | ||
320 | &agent_send_handler, | ||
321 | NULL, NULL); | ||
322 | if (IS_ERR(port_priv->perf_mgmt_agent)) { | ||
323 | ret = PTR_ERR(port_priv->perf_mgmt_agent); | ||
324 | goto error3; | ||
325 | } | ||
326 | |||
327 | port_priv->mr = ib_get_dma_mr(port_priv->smp_agent->qp->pd, | ||
328 | IB_ACCESS_LOCAL_WRITE); | ||
329 | if (IS_ERR(port_priv->mr)) { | ||
330 | printk(KERN_ERR SPFX "Couldn't get DMA MR\n"); | ||
331 | ret = PTR_ERR(port_priv->mr); | ||
332 | goto error4; | ||
333 | } | ||
334 | |||
335 | spin_lock_irqsave(&ib_agent_port_list_lock, flags); | ||
336 | list_add_tail(&port_priv->port_list, &ib_agent_port_list); | ||
337 | spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); | ||
338 | |||
339 | return 0; | ||
340 | |||
341 | error4: | ||
342 | ib_unregister_mad_agent(port_priv->perf_mgmt_agent); | ||
343 | error3: | ||
344 | ib_unregister_mad_agent(port_priv->smp_agent); | ||
345 | error2: | ||
346 | kfree(port_priv); | ||
347 | error1: | ||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | int ib_agent_port_close(struct ib_device *device, int port_num) | ||
352 | { | ||
353 | struct ib_agent_port_private *port_priv; | ||
354 | unsigned long flags; | ||
355 | |||
356 | spin_lock_irqsave(&ib_agent_port_list_lock, flags); | ||
357 | port_priv = __ib_get_agent_port(device, port_num, NULL); | ||
358 | if (port_priv == NULL) { | ||
359 | spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); | ||
360 | printk(KERN_ERR SPFX "Port %d not found\n", port_num); | ||
361 | return -ENODEV; | ||
362 | } | ||
363 | list_del(&port_priv->port_list); | ||
364 | spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); | ||
365 | |||
366 | ib_dereg_mr(port_priv->mr); | ||
367 | |||
368 | ib_unregister_mad_agent(port_priv->perf_mgmt_agent); | ||
369 | ib_unregister_mad_agent(port_priv->smp_agent); | ||
370 | kfree(port_priv); | ||
371 | |||
372 | return 0; | ||
373 | } | ||
diff --git a/drivers/infiniband/core/agent.h b/drivers/infiniband/core/agent.h new file mode 100644 index 000000000000..d9426842254a --- /dev/null +++ b/drivers/infiniband/core/agent.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. | ||
3 | * Copyright (c) 2004 Infinicon Corporation. All rights reserved. | ||
4 | * Copyright (c) 2004 Intel Corporation. All rights reserved. | ||
5 | * Copyright (c) 2004 Topspin Corporation. All rights reserved. | ||
6 | * Copyright (c) 2004 Voltaire Corporation. All rights reserved. | ||
7 | * | ||
8 | * This software is available to you under a choice of one of two | ||
9 | * licenses. You may choose to be licensed under the terms of the GNU | ||
10 | * General Public License (GPL) Version 2, available from the file | ||
11 | * COPYING in the main directory of this source tree, or the | ||
12 | * OpenIB.org BSD license below: | ||
13 | * | ||
14 | * Redistribution and use in source and binary forms, with or | ||
15 | * without modification, are permitted provided that the following | ||
16 | * conditions are met: | ||
17 | * | ||
18 | * - Redistributions of source code must retain the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer. | ||
21 | * | ||
22 | * - Redistributions in binary form must reproduce the above | ||
23 | * copyright notice, this list of conditions and the following | ||
24 | * disclaimer in the documentation and/or other materials | ||
25 | * provided with the distribution. | ||
26 | * | ||
27 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
28 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
29 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
30 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
31 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
32 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
33 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
34 | * SOFTWARE. | ||
35 | * | ||
36 | * $Id: agent.h 1389 2004-12-27 22:56:47Z roland $ | ||
37 | */ | ||
38 | |||
39 | #ifndef __AGENT_H_ | ||
40 | #define __AGENT_H_ | ||
41 | |||
42 | extern spinlock_t ib_agent_port_list_lock; | ||
43 | |||
44 | extern int ib_agent_port_open(struct ib_device *device, | ||
45 | int port_num); | ||
46 | |||
47 | extern int ib_agent_port_close(struct ib_device *device, int port_num); | ||
48 | |||
49 | extern int agent_send(struct ib_mad_private *mad, | ||
50 | struct ib_grh *grh, | ||
51 | struct ib_wc *wc, | ||
52 | struct ib_device *device, | ||
53 | int port_num); | ||
54 | |||
55 | #endif /* __AGENT_H_ */ | ||
diff --git a/drivers/infiniband/core/agent_priv.h b/drivers/infiniband/core/agent_priv.h new file mode 100644 index 000000000000..17a0cce5813c --- /dev/null +++ b/drivers/infiniband/core/agent_priv.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. | ||
3 | * Copyright (c) 2004 Infinicon Corporation. All rights reserved. | ||
4 | * Copyright (c) 2004 Intel Corporation. All rights reserved. | ||
5 | * Copyright (c) 2004 Topspin Corporation. All rights reserved. | ||
6 | * Copyright (c) 2004 Voltaire Corporation. All rights reserved. | ||
7 | * | ||
8 | * This software is available to you under a choice of one of two | ||
9 | * licenses. You may choose to be licensed under the terms of the GNU | ||
10 | * General Public License (GPL) Version 2, available from the file | ||
11 | * COPYING in the main directory of this source tree, or the | ||
12 | * OpenIB.org BSD license below: | ||
13 | * | ||
14 | * Redistribution and use in source and binary forms, with or | ||
15 | * without modification, are permitted provided that the following | ||
16 | * conditions are met: | ||
17 | * | ||
18 | * - Redistributions of source code must retain the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer. | ||
21 | * | ||
22 | * - Redistributions in binary form must reproduce the above | ||
23 | * copyright notice, this list of conditions and the following | ||
24 | * disclaimer in the documentation and/or other materials | ||
25 | * provided with the distribution. | ||
26 | * | ||
27 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
28 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
29 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
30 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
31 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
32 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
33 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
34 | * SOFTWARE. | ||
35 | * | ||
36 | * $Id: agent_priv.h 1389 2004-12-27 22:56:47Z roland $ | ||
37 | */ | ||
38 | |||
39 | #ifndef __IB_AGENT_PRIV_H__ | ||
40 | #define __IB_AGENT_PRIV_H__ | ||
41 | |||
42 | #include <linux/pci.h> | ||
43 | |||
44 | #define SPFX "ib_agent: " | ||
45 | |||
46 | struct ib_agent_send_wr { | ||
47 | struct list_head send_list; | ||
48 | struct ib_ah *ah; | ||
49 | struct ib_mad_private *mad; | ||
50 | DECLARE_PCI_UNMAP_ADDR(mapping) | ||
51 | }; | ||
52 | |||
53 | struct ib_agent_port_private { | ||
54 | struct list_head port_list; | ||
55 | struct list_head send_posted_list; | ||
56 | spinlock_t send_list_lock; | ||
57 | int port_num; | ||
58 | struct ib_mad_agent *smp_agent; /* SM class */ | ||
59 | struct ib_mad_agent *perf_mgmt_agent; /* PerfMgmt class */ | ||
60 | struct ib_mr *mr; | ||
61 | }; | ||
62 | |||
63 | #endif /* __IB_AGENT_PRIV_H__ */ | ||
diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c new file mode 100644 index 000000000000..3042360c97e1 --- /dev/null +++ b/drivers/infiniband/core/cache.c | |||
@@ -0,0 +1,365 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | * $Id: cache.c 1349 2004-12-16 21:09:43Z roland $ | ||
33 | */ | ||
34 | |||
35 | #include <linux/version.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/errno.h> | ||
38 | #include <linux/slab.h> | ||
39 | |||
40 | #include <ib_cache.h> | ||
41 | |||
42 | #include "core_priv.h" | ||
43 | |||
44 | struct ib_pkey_cache { | ||
45 | int table_len; | ||
46 | u16 table[0]; | ||
47 | }; | ||
48 | |||
49 | struct ib_gid_cache { | ||
50 | int table_len; | ||
51 | union ib_gid table[0]; | ||
52 | }; | ||
53 | |||
54 | struct ib_update_work { | ||
55 | struct work_struct work; | ||
56 | struct ib_device *device; | ||
57 | u8 port_num; | ||
58 | }; | ||
59 | |||
60 | static inline int start_port(struct ib_device *device) | ||
61 | { | ||
62 | return device->node_type == IB_NODE_SWITCH ? 0 : 1; | ||
63 | } | ||
64 | |||
65 | static inline int end_port(struct ib_device *device) | ||
66 | { | ||
67 | return device->node_type == IB_NODE_SWITCH ? 0 : device->phys_port_cnt; | ||
68 | } | ||
69 | |||
70 | int ib_get_cached_gid(struct ib_device *device, | ||
71 | u8 port_num, | ||
72 | int index, | ||
73 | union ib_gid *gid) | ||
74 | { | ||
75 | struct ib_gid_cache *cache; | ||
76 | unsigned long flags; | ||
77 | int ret = 0; | ||
78 | |||
79 | if (port_num < start_port(device) || port_num > end_port(device)) | ||
80 | return -EINVAL; | ||
81 | |||
82 | read_lock_irqsave(&device->cache.lock, flags); | ||
83 | |||
84 | cache = device->cache.gid_cache[port_num - start_port(device)]; | ||
85 | |||
86 | if (index < 0 || index >= cache->table_len) | ||
87 | ret = -EINVAL; | ||
88 | else | ||
89 | *gid = cache->table[index]; | ||
90 | |||
91 | read_unlock_irqrestore(&device->cache.lock, flags); | ||
92 | |||
93 | return ret; | ||
94 | } | ||
95 | EXPORT_SYMBOL(ib_get_cached_gid); | ||
96 | |||
97 | int ib_find_cached_gid(struct ib_device *device, | ||
98 | union ib_gid *gid, | ||
99 | u8 *port_num, | ||
100 | u16 *index) | ||
101 | { | ||
102 | struct ib_gid_cache *cache; | ||
103 | unsigned long flags; | ||
104 | int p, i; | ||
105 | int ret = -ENOENT; | ||
106 | |||
107 | *port_num = -1; | ||
108 | if (index) | ||
109 | *index = -1; | ||
110 | |||
111 | read_lock_irqsave(&device->cache.lock, flags); | ||
112 | |||
113 | for (p = 0; p <= end_port(device) - start_port(device); ++p) { | ||
114 | cache = device->cache.gid_cache[p]; | ||
115 | for (i = 0; i < cache->table_len; ++i) { | ||
116 | if (!memcmp(gid, &cache->table[i], sizeof *gid)) { | ||
117 | *port_num = p + start_port(device); | ||
118 | if (index) | ||
119 | *index = i; | ||
120 | ret = 0; | ||
121 | goto found; | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | found: | ||
126 | read_unlock_irqrestore(&device->cache.lock, flags); | ||
127 | |||
128 | return ret; | ||
129 | } | ||
130 | EXPORT_SYMBOL(ib_find_cached_gid); | ||
131 | |||
132 | int ib_get_cached_pkey(struct ib_device *device, | ||
133 | u8 port_num, | ||
134 | int index, | ||
135 | u16 *pkey) | ||
136 | { | ||
137 | struct ib_pkey_cache *cache; | ||
138 | unsigned long flags; | ||
139 | int ret = 0; | ||
140 | |||
141 | if (port_num < start_port(device) || port_num > end_port(device)) | ||
142 | return -EINVAL; | ||
143 | |||
144 | read_lock_irqsave(&device->cache.lock, flags); | ||
145 | |||
146 | cache = device->cache.pkey_cache[port_num - start_port(device)]; | ||
147 | |||
148 | if (index < 0 || index >= cache->table_len) | ||
149 | ret = -EINVAL; | ||
150 | else | ||
151 | *pkey = cache->table[index]; | ||
152 | |||
153 | read_unlock_irqrestore(&device->cache.lock, flags); | ||
154 | |||
155 | return ret; | ||
156 | } | ||
157 | EXPORT_SYMBOL(ib_get_cached_pkey); | ||
158 | |||
159 | int ib_find_cached_pkey(struct ib_device *device, | ||
160 | u8 port_num, | ||
161 | u16 pkey, | ||
162 | u16 *index) | ||
163 | { | ||
164 | struct ib_pkey_cache *cache; | ||
165 | unsigned long flags; | ||
166 | int i; | ||
167 | int ret = -ENOENT; | ||
168 | |||
169 | if (port_num < start_port(device) || port_num > end_port(device)) | ||
170 | return -EINVAL; | ||
171 | |||
172 | read_lock_irqsave(&device->cache.lock, flags); | ||
173 | |||
174 | cache = device->cache.pkey_cache[port_num - start_port(device)]; | ||
175 | |||
176 | *index = -1; | ||
177 | |||
178 | for (i = 0; i < cache->table_len; ++i) | ||
179 | if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) { | ||
180 | *index = i; | ||
181 | ret = 0; | ||
182 | break; | ||
183 | } | ||
184 | |||
185 | read_unlock_irqrestore(&device->cache.lock, flags); | ||
186 | |||
187 | return ret; | ||
188 | } | ||
189 | EXPORT_SYMBOL(ib_find_cached_pkey); | ||
190 | |||
191 | static void ib_cache_update(struct ib_device *device, | ||
192 | u8 port) | ||
193 | { | ||
194 | struct ib_port_attr *tprops = NULL; | ||
195 | struct ib_pkey_cache *pkey_cache = NULL, *old_pkey_cache; | ||
196 | struct ib_gid_cache *gid_cache = NULL, *old_gid_cache; | ||
197 | int i; | ||
198 | int ret; | ||
199 | |||
200 | tprops = kmalloc(sizeof *tprops, GFP_KERNEL); | ||
201 | if (!tprops) | ||
202 | return; | ||
203 | |||
204 | ret = ib_query_port(device, port, tprops); | ||
205 | if (ret) { | ||
206 | printk(KERN_WARNING "ib_query_port failed (%d) for %s\n", | ||
207 | ret, device->name); | ||
208 | goto err; | ||
209 | } | ||
210 | |||
211 | pkey_cache = kmalloc(sizeof *pkey_cache + tprops->pkey_tbl_len * | ||
212 | sizeof *pkey_cache->table, GFP_KERNEL); | ||
213 | if (!pkey_cache) | ||
214 | goto err; | ||
215 | |||
216 | pkey_cache->table_len = tprops->pkey_tbl_len; | ||
217 | |||
218 | gid_cache = kmalloc(sizeof *gid_cache + tprops->gid_tbl_len * | ||
219 | sizeof *gid_cache->table, GFP_KERNEL); | ||
220 | if (!gid_cache) | ||
221 | goto err; | ||
222 | |||
223 | gid_cache->table_len = tprops->gid_tbl_len; | ||
224 | |||
225 | for (i = 0; i < pkey_cache->table_len; ++i) { | ||
226 | ret = ib_query_pkey(device, port, i, pkey_cache->table + i); | ||
227 | if (ret) { | ||
228 | printk(KERN_WARNING "ib_query_pkey failed (%d) for %s (index %d)\n", | ||
229 | ret, device->name, i); | ||
230 | goto err; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | for (i = 0; i < gid_cache->table_len; ++i) { | ||
235 | ret = ib_query_gid(device, port, i, gid_cache->table + i); | ||
236 | if (ret) { | ||
237 | printk(KERN_WARNING "ib_query_gid failed (%d) for %s (index %d)\n", | ||
238 | ret, device->name, i); | ||
239 | goto err; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | write_lock_irq(&device->cache.lock); | ||
244 | |||
245 | old_pkey_cache = device->cache.pkey_cache[port - start_port(device)]; | ||
246 | old_gid_cache = device->cache.gid_cache [port - start_port(device)]; | ||
247 | |||
248 | device->cache.pkey_cache[port - start_port(device)] = pkey_cache; | ||
249 | device->cache.gid_cache [port - start_port(device)] = gid_cache; | ||
250 | |||
251 | write_unlock_irq(&device->cache.lock); | ||
252 | |||
253 | kfree(old_pkey_cache); | ||
254 | kfree(old_gid_cache); | ||
255 | kfree(tprops); | ||
256 | return; | ||
257 | |||
258 | err: | ||
259 | kfree(pkey_cache); | ||
260 | kfree(gid_cache); | ||
261 | kfree(tprops); | ||
262 | } | ||
263 | |||
264 | static void ib_cache_task(void *work_ptr) | ||
265 | { | ||
266 | struct ib_update_work *work = work_ptr; | ||
267 | |||
268 | ib_cache_update(work->device, work->port_num); | ||
269 | kfree(work); | ||
270 | } | ||
271 | |||
272 | static void ib_cache_event(struct ib_event_handler *handler, | ||
273 | struct ib_event *event) | ||
274 | { | ||
275 | struct ib_update_work *work; | ||
276 | |||
277 | if (event->event == IB_EVENT_PORT_ERR || | ||
278 | event->event == IB_EVENT_PORT_ACTIVE || | ||
279 | event->event == IB_EVENT_LID_CHANGE || | ||
280 | event->event == IB_EVENT_PKEY_CHANGE || | ||
281 | event->event == IB_EVENT_SM_CHANGE) { | ||
282 | work = kmalloc(sizeof *work, GFP_ATOMIC); | ||
283 | if (work) { | ||
284 | INIT_WORK(&work->work, ib_cache_task, work); | ||
285 | work->device = event->device; | ||
286 | work->port_num = event->element.port_num; | ||
287 | schedule_work(&work->work); | ||
288 | } | ||
289 | } | ||
290 | } | ||
291 | |||
292 | static void ib_cache_setup_one(struct ib_device *device) | ||
293 | { | ||
294 | int p; | ||
295 | |||
296 | rwlock_init(&device->cache.lock); | ||
297 | |||
298 | device->cache.pkey_cache = | ||
299 | kmalloc(sizeof *device->cache.pkey_cache * | ||
300 | (end_port(device) - start_port(device) + 1), GFP_KERNEL); | ||
301 | device->cache.gid_cache = | ||
302 | kmalloc(sizeof *device->cache.pkey_cache * | ||
303 | (end_port(device) - start_port(device) + 1), GFP_KERNEL); | ||
304 | |||
305 | if (!device->cache.pkey_cache || !device->cache.gid_cache) { | ||
306 | printk(KERN_WARNING "Couldn't allocate cache " | ||
307 | "for %s\n", device->name); | ||
308 | goto err; | ||
309 | } | ||
310 | |||
311 | for (p = 0; p <= end_port(device) - start_port(device); ++p) { | ||
312 | device->cache.pkey_cache[p] = NULL; | ||
313 | device->cache.gid_cache [p] = NULL; | ||
314 | ib_cache_update(device, p + start_port(device)); | ||
315 | } | ||
316 | |||
317 | INIT_IB_EVENT_HANDLER(&device->cache.event_handler, | ||
318 | device, ib_cache_event); | ||
319 | if (ib_register_event_handler(&device->cache.event_handler)) | ||
320 | goto err_cache; | ||
321 | |||
322 | return; | ||
323 | |||
324 | err_cache: | ||
325 | for (p = 0; p <= end_port(device) - start_port(device); ++p) { | ||
326 | kfree(device->cache.pkey_cache[p]); | ||
327 | kfree(device->cache.gid_cache[p]); | ||
328 | } | ||
329 | |||
330 | err: | ||
331 | kfree(device->cache.pkey_cache); | ||
332 | kfree(device->cache.gid_cache); | ||
333 | } | ||
334 | |||
335 | static void ib_cache_cleanup_one(struct ib_device *device) | ||
336 | { | ||
337 | int p; | ||
338 | |||
339 | ib_unregister_event_handler(&device->cache.event_handler); | ||
340 | flush_scheduled_work(); | ||
341 | |||
342 | for (p = 0; p <= end_port(device) - start_port(device); ++p) { | ||
343 | kfree(device->cache.pkey_cache[p]); | ||
344 | kfree(device->cache.gid_cache[p]); | ||
345 | } | ||
346 | |||
347 | kfree(device->cache.pkey_cache); | ||
348 | kfree(device->cache.gid_cache); | ||
349 | } | ||
350 | |||
351 | static struct ib_client cache_client = { | ||
352 | .name = "cache", | ||
353 | .add = ib_cache_setup_one, | ||
354 | .remove = ib_cache_cleanup_one | ||
355 | }; | ||
356 | |||
357 | int __init ib_cache_setup(void) | ||
358 | { | ||
359 | return ib_register_client(&cache_client); | ||
360 | } | ||
361 | |||
362 | void __exit ib_cache_cleanup(void) | ||
363 | { | ||
364 | ib_unregister_client(&cache_client); | ||
365 | } | ||
diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h new file mode 100644 index 000000000000..797049626ff6 --- /dev/null +++ b/drivers/infiniband/core/core_priv.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | * $Id: core_priv.h 1349 2004-12-16 21:09:43Z roland $ | ||
33 | */ | ||
34 | |||
35 | #ifndef _CORE_PRIV_H | ||
36 | #define _CORE_PRIV_H | ||
37 | |||
38 | #include <linux/list.h> | ||
39 | #include <linux/spinlock.h> | ||
40 | |||
41 | #include <ib_verbs.h> | ||
42 | |||
43 | int ib_device_register_sysfs(struct ib_device *device); | ||
44 | void ib_device_unregister_sysfs(struct ib_device *device); | ||
45 | |||
46 | int ib_sysfs_setup(void); | ||
47 | void ib_sysfs_cleanup(void); | ||
48 | |||
49 | int ib_cache_setup(void); | ||
50 | void ib_cache_cleanup(void); | ||
51 | |||
52 | #endif /* _CORE_PRIV_H */ | ||
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c new file mode 100644 index 000000000000..9197e92d708a --- /dev/null +++ b/drivers/infiniband/core/device.c | |||
@@ -0,0 +1,614 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | * $Id: device.c 1349 2004-12-16 21:09:43Z roland $ | ||
33 | */ | ||
34 | |||
35 | #include <linux/module.h> | ||
36 | #include <linux/string.h> | ||
37 | #include <linux/errno.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/init.h> | ||
40 | |||
41 | #include <asm/semaphore.h> | ||
42 | |||
43 | #include "core_priv.h" | ||
44 | |||
45 | MODULE_AUTHOR("Roland Dreier"); | ||
46 | MODULE_DESCRIPTION("core kernel InfiniBand API"); | ||
47 | MODULE_LICENSE("Dual BSD/GPL"); | ||
48 | |||
49 | struct ib_client_data { | ||
50 | struct list_head list; | ||
51 | struct ib_client *client; | ||
52 | void * data; | ||
53 | }; | ||
54 | |||
55 | static LIST_HEAD(device_list); | ||
56 | static LIST_HEAD(client_list); | ||
57 | |||
58 | /* | ||
59 | * device_sem protects access to both device_list and client_list. | ||
60 | * There's no real point to using multiple locks or something fancier | ||
61 | * like an rwsem: we always access both lists, and we're always | ||
62 | * modifying one list or the other list. In any case this is not a | ||
63 | * hot path so there's no point in trying to optimize. | ||
64 | */ | ||
65 | static DECLARE_MUTEX(device_sem); | ||
66 | |||
67 | static int ib_device_check_mandatory(struct ib_device *device) | ||
68 | { | ||
69 | #define IB_MANDATORY_FUNC(x) { offsetof(struct ib_device, x), #x } | ||
70 | static const struct { | ||
71 | size_t offset; | ||
72 | char *name; | ||
73 | } mandatory_table[] = { | ||
74 | IB_MANDATORY_FUNC(query_device), | ||
75 | IB_MANDATORY_FUNC(query_port), | ||
76 | IB_MANDATORY_FUNC(query_pkey), | ||
77 | IB_MANDATORY_FUNC(query_gid), | ||
78 | IB_MANDATORY_FUNC(alloc_pd), | ||
79 | IB_MANDATORY_FUNC(dealloc_pd), | ||
80 | IB_MANDATORY_FUNC(create_ah), | ||
81 | IB_MANDATORY_FUNC(destroy_ah), | ||
82 | IB_MANDATORY_FUNC(create_qp), | ||
83 | IB_MANDATORY_FUNC(modify_qp), | ||
84 | IB_MANDATORY_FUNC(destroy_qp), | ||
85 | IB_MANDATORY_FUNC(post_send), | ||
86 | IB_MANDATORY_FUNC(post_recv), | ||
87 | IB_MANDATORY_FUNC(create_cq), | ||
88 | IB_MANDATORY_FUNC(destroy_cq), | ||
89 | IB_MANDATORY_FUNC(poll_cq), | ||
90 | IB_MANDATORY_FUNC(req_notify_cq), | ||
91 | IB_MANDATORY_FUNC(get_dma_mr), | ||
92 | IB_MANDATORY_FUNC(dereg_mr) | ||
93 | }; | ||
94 | int i; | ||
95 | |||
96 | for (i = 0; i < sizeof mandatory_table / sizeof mandatory_table[0]; ++i) { | ||
97 | if (!*(void **) ((void *) device + mandatory_table[i].offset)) { | ||
98 | printk(KERN_WARNING "Device %s is missing mandatory function %s\n", | ||
99 | device->name, mandatory_table[i].name); | ||
100 | return -EINVAL; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static struct ib_device *__ib_device_get_by_name(const char *name) | ||
108 | { | ||
109 | struct ib_device *device; | ||
110 | |||
111 | list_for_each_entry(device, &device_list, core_list) | ||
112 | if (!strncmp(name, device->name, IB_DEVICE_NAME_MAX)) | ||
113 | return device; | ||
114 | |||
115 | return NULL; | ||
116 | } | ||
117 | |||
118 | |||
119 | static int alloc_name(char *name) | ||
120 | { | ||
121 | long *inuse; | ||
122 | char buf[IB_DEVICE_NAME_MAX]; | ||
123 | struct ib_device *device; | ||
124 | int i; | ||
125 | |||
126 | inuse = (long *) get_zeroed_page(GFP_KERNEL); | ||
127 | if (!inuse) | ||
128 | return -ENOMEM; | ||
129 | |||
130 | list_for_each_entry(device, &device_list, core_list) { | ||
131 | if (!sscanf(device->name, name, &i)) | ||
132 | continue; | ||
133 | if (i < 0 || i >= PAGE_SIZE * 8) | ||
134 | continue; | ||
135 | snprintf(buf, sizeof buf, name, i); | ||
136 | if (!strncmp(buf, device->name, IB_DEVICE_NAME_MAX)) | ||
137 | set_bit(i, inuse); | ||
138 | } | ||
139 | |||
140 | i = find_first_zero_bit(inuse, PAGE_SIZE * 8); | ||
141 | free_page((unsigned long) inuse); | ||
142 | snprintf(buf, sizeof buf, name, i); | ||
143 | |||
144 | if (__ib_device_get_by_name(buf)) | ||
145 | return -ENFILE; | ||
146 | |||
147 | strlcpy(name, buf, IB_DEVICE_NAME_MAX); | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * ib_alloc_device - allocate an IB device struct | ||
153 | * @size:size of structure to allocate | ||
154 | * | ||
155 | * Low-level drivers should use ib_alloc_device() to allocate &struct | ||
156 | * ib_device. @size is the size of the structure to be allocated, | ||
157 | * including any private data used by the low-level driver. | ||
158 | * ib_dealloc_device() must be used to free structures allocated with | ||
159 | * ib_alloc_device(). | ||
160 | */ | ||
161 | struct ib_device *ib_alloc_device(size_t size) | ||
162 | { | ||
163 | void *dev; | ||
164 | |||
165 | BUG_ON(size < sizeof (struct ib_device)); | ||
166 | |||
167 | dev = kmalloc(size, GFP_KERNEL); | ||
168 | if (!dev) | ||
169 | return NULL; | ||
170 | |||
171 | memset(dev, 0, size); | ||
172 | |||
173 | return dev; | ||
174 | } | ||
175 | EXPORT_SYMBOL(ib_alloc_device); | ||
176 | |||
177 | /** | ||
178 | * ib_dealloc_device - free an IB device struct | ||
179 | * @device:structure to free | ||
180 | * | ||
181 | * Free a structure allocated with ib_alloc_device(). | ||
182 | */ | ||
183 | void ib_dealloc_device(struct ib_device *device) | ||
184 | { | ||
185 | if (device->reg_state == IB_DEV_UNINITIALIZED) { | ||
186 | kfree(device); | ||
187 | return; | ||
188 | } | ||
189 | |||
190 | BUG_ON(device->reg_state != IB_DEV_UNREGISTERED); | ||
191 | |||
192 | ib_device_unregister_sysfs(device); | ||
193 | } | ||
194 | EXPORT_SYMBOL(ib_dealloc_device); | ||
195 | |||
196 | static int add_client_context(struct ib_device *device, struct ib_client *client) | ||
197 | { | ||
198 | struct ib_client_data *context; | ||
199 | unsigned long flags; | ||
200 | |||
201 | context = kmalloc(sizeof *context, GFP_KERNEL); | ||
202 | if (!context) { | ||
203 | printk(KERN_WARNING "Couldn't allocate client context for %s/%s\n", | ||
204 | device->name, client->name); | ||
205 | return -ENOMEM; | ||
206 | } | ||
207 | |||
208 | context->client = client; | ||
209 | context->data = NULL; | ||
210 | |||
211 | spin_lock_irqsave(&device->client_data_lock, flags); | ||
212 | list_add(&context->list, &device->client_data_list); | ||
213 | spin_unlock_irqrestore(&device->client_data_lock, flags); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | /** | ||
219 | * ib_register_device - Register an IB device with IB core | ||
220 | * @device:Device to register | ||
221 | * | ||
222 | * Low-level drivers use ib_register_device() to register their | ||
223 | * devices with the IB core. All registered clients will receive a | ||
224 | * callback for each device that is added. @device must be allocated | ||
225 | * with ib_alloc_device(). | ||
226 | */ | ||
227 | int ib_register_device(struct ib_device *device) | ||
228 | { | ||
229 | int ret; | ||
230 | |||
231 | down(&device_sem); | ||
232 | |||
233 | if (strchr(device->name, '%')) { | ||
234 | ret = alloc_name(device->name); | ||
235 | if (ret) | ||
236 | goto out; | ||
237 | } | ||
238 | |||
239 | if (ib_device_check_mandatory(device)) { | ||
240 | ret = -EINVAL; | ||
241 | goto out; | ||
242 | } | ||
243 | |||
244 | INIT_LIST_HEAD(&device->event_handler_list); | ||
245 | INIT_LIST_HEAD(&device->client_data_list); | ||
246 | spin_lock_init(&device->event_handler_lock); | ||
247 | spin_lock_init(&device->client_data_lock); | ||
248 | |||
249 | ret = ib_device_register_sysfs(device); | ||
250 | if (ret) { | ||
251 | printk(KERN_WARNING "Couldn't register device %s with driver model\n", | ||
252 | device->name); | ||
253 | goto out; | ||
254 | } | ||
255 | |||
256 | list_add_tail(&device->core_list, &device_list); | ||
257 | |||
258 | device->reg_state = IB_DEV_REGISTERED; | ||
259 | |||
260 | { | ||
261 | struct ib_client *client; | ||
262 | |||
263 | list_for_each_entry(client, &client_list, list) | ||
264 | if (client->add && !add_client_context(device, client)) | ||
265 | client->add(device); | ||
266 | } | ||
267 | |||
268 | out: | ||
269 | up(&device_sem); | ||
270 | return ret; | ||
271 | } | ||
272 | EXPORT_SYMBOL(ib_register_device); | ||
273 | |||
274 | /** | ||
275 | * ib_unregister_device - Unregister an IB device | ||
276 | * @device:Device to unregister | ||
277 | * | ||
278 | * Unregister an IB device. All clients will receive a remove callback. | ||
279 | */ | ||
280 | void ib_unregister_device(struct ib_device *device) | ||
281 | { | ||
282 | struct ib_client *client; | ||
283 | struct ib_client_data *context, *tmp; | ||
284 | unsigned long flags; | ||
285 | |||
286 | down(&device_sem); | ||
287 | |||
288 | list_for_each_entry_reverse(client, &client_list, list) | ||
289 | if (client->remove) | ||
290 | client->remove(device); | ||
291 | |||
292 | list_del(&device->core_list); | ||
293 | |||
294 | up(&device_sem); | ||
295 | |||
296 | spin_lock_irqsave(&device->client_data_lock, flags); | ||
297 | list_for_each_entry_safe(context, tmp, &device->client_data_list, list) | ||
298 | kfree(context); | ||
299 | spin_unlock_irqrestore(&device->client_data_lock, flags); | ||
300 | |||
301 | device->reg_state = IB_DEV_UNREGISTERED; | ||
302 | } | ||
303 | EXPORT_SYMBOL(ib_unregister_device); | ||
304 | |||
305 | /** | ||
306 | * ib_register_client - Register an IB client | ||
307 | * @client:Client to register | ||
308 | * | ||
309 | * Upper level users of the IB drivers can use ib_register_client() to | ||
310 | * register callbacks for IB device addition and removal. When an IB | ||
311 | * device is added, each registered client's add method will be called | ||
312 | * (in the order the clients were registered), and when a device is | ||
313 | * removed, each client's remove method will be called (in the reverse | ||
314 | * order that clients were registered). In addition, when | ||
315 | * ib_register_client() is called, the client will receive an add | ||
316 | * callback for all devices already registered. | ||
317 | */ | ||
318 | int ib_register_client(struct ib_client *client) | ||
319 | { | ||
320 | struct ib_device *device; | ||
321 | |||
322 | down(&device_sem); | ||
323 | |||
324 | list_add_tail(&client->list, &client_list); | ||
325 | list_for_each_entry(device, &device_list, core_list) | ||
326 | if (client->add && !add_client_context(device, client)) | ||
327 | client->add(device); | ||
328 | |||
329 | up(&device_sem); | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | EXPORT_SYMBOL(ib_register_client); | ||
334 | |||
335 | /** | ||
336 | * ib_unregister_client - Unregister an IB client | ||
337 | * @client:Client to unregister | ||
338 | * | ||
339 | * Upper level users use ib_unregister_client() to remove their client | ||
340 | * registration. When ib_unregister_client() is called, the client | ||
341 | * will receive a remove callback for each IB device still registered. | ||
342 | */ | ||
343 | void ib_unregister_client(struct ib_client *client) | ||
344 | { | ||
345 | struct ib_client_data *context, *tmp; | ||
346 | struct ib_device *device; | ||
347 | unsigned long flags; | ||
348 | |||
349 | down(&device_sem); | ||
350 | |||
351 | list_for_each_entry(device, &device_list, core_list) { | ||
352 | if (client->remove) | ||
353 | client->remove(device); | ||
354 | |||
355 | spin_lock_irqsave(&device->client_data_lock, flags); | ||
356 | list_for_each_entry_safe(context, tmp, &device->client_data_list, list) | ||
357 | if (context->client == client) { | ||
358 | list_del(&context->list); | ||
359 | kfree(context); | ||
360 | } | ||
361 | spin_unlock_irqrestore(&device->client_data_lock, flags); | ||
362 | } | ||
363 | list_del(&client->list); | ||
364 | |||
365 | up(&device_sem); | ||
366 | } | ||
367 | EXPORT_SYMBOL(ib_unregister_client); | ||
368 | |||
369 | /** | ||
370 | * ib_get_client_data - Get IB client context | ||
371 | * @device:Device to get context for | ||
372 | * @client:Client to get context for | ||
373 | * | ||
374 | * ib_get_client_data() returns client context set with | ||
375 | * ib_set_client_data(). | ||
376 | */ | ||
377 | void *ib_get_client_data(struct ib_device *device, struct ib_client *client) | ||
378 | { | ||
379 | struct ib_client_data *context; | ||
380 | void *ret = NULL; | ||
381 | unsigned long flags; | ||
382 | |||
383 | spin_lock_irqsave(&device->client_data_lock, flags); | ||
384 | list_for_each_entry(context, &device->client_data_list, list) | ||
385 | if (context->client == client) { | ||
386 | ret = context->data; | ||
387 | break; | ||
388 | } | ||
389 | spin_unlock_irqrestore(&device->client_data_lock, flags); | ||
390 | |||
391 | return ret; | ||
392 | } | ||
393 | EXPORT_SYMBOL(ib_get_client_data); | ||
394 | |||
395 | /** | ||
396 | * ib_set_client_data - Get IB client context | ||
397 | * @device:Device to set context for | ||
398 | * @client:Client to set context for | ||
399 | * @data:Context to set | ||
400 | * | ||
401 | * ib_set_client_data() sets client context that can be retrieved with | ||
402 | * ib_get_client_data(). | ||
403 | */ | ||
404 | void ib_set_client_data(struct ib_device *device, struct ib_client *client, | ||
405 | void *data) | ||
406 | { | ||
407 | struct ib_client_data *context; | ||
408 | unsigned long flags; | ||
409 | |||
410 | spin_lock_irqsave(&device->client_data_lock, flags); | ||
411 | list_for_each_entry(context, &device->client_data_list, list) | ||
412 | if (context->client == client) { | ||
413 | context->data = data; | ||
414 | goto out; | ||
415 | } | ||
416 | |||
417 | printk(KERN_WARNING "No client context found for %s/%s\n", | ||
418 | device->name, client->name); | ||
419 | |||
420 | out: | ||
421 | spin_unlock_irqrestore(&device->client_data_lock, flags); | ||
422 | } | ||
423 | EXPORT_SYMBOL(ib_set_client_data); | ||
424 | |||
425 | /** | ||
426 | * ib_register_event_handler - Register an IB event handler | ||
427 | * @event_handler:Handler to register | ||
428 | * | ||
429 | * ib_register_event_handler() registers an event handler that will be | ||
430 | * called back when asynchronous IB events occur (as defined in | ||
431 | * chapter 11 of the InfiniBand Architecture Specification). This | ||
432 | * callback may occur in interrupt context. | ||
433 | */ | ||
434 | int ib_register_event_handler (struct ib_event_handler *event_handler) | ||
435 | { | ||
436 | unsigned long flags; | ||
437 | |||
438 | spin_lock_irqsave(&event_handler->device->event_handler_lock, flags); | ||
439 | list_add_tail(&event_handler->list, | ||
440 | &event_handler->device->event_handler_list); | ||
441 | spin_unlock_irqrestore(&event_handler->device->event_handler_lock, flags); | ||
442 | |||
443 | return 0; | ||
444 | } | ||
445 | EXPORT_SYMBOL(ib_register_event_handler); | ||
446 | |||
447 | /** | ||
448 | * ib_unregister_event_handler - Unregister an event handler | ||
449 | * @event_handler:Handler to unregister | ||
450 | * | ||
451 | * Unregister an event handler registered with | ||
452 | * ib_register_event_handler(). | ||
453 | */ | ||
454 | int ib_unregister_event_handler(struct ib_event_handler *event_handler) | ||
455 | { | ||
456 | unsigned long flags; | ||
457 | |||
458 | spin_lock_irqsave(&event_handler->device->event_handler_lock, flags); | ||
459 | list_del(&event_handler->list); | ||
460 | spin_unlock_irqrestore(&event_handler->device->event_handler_lock, flags); | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | EXPORT_SYMBOL(ib_unregister_event_handler); | ||
465 | |||
466 | /** | ||
467 | * ib_dispatch_event - Dispatch an asynchronous event | ||
468 | * @event:Event to dispatch | ||
469 | * | ||
470 | * Low-level drivers must call ib_dispatch_event() to dispatch the | ||
471 | * event to all registered event handlers when an asynchronous event | ||
472 | * occurs. | ||
473 | */ | ||
474 | void ib_dispatch_event(struct ib_event *event) | ||
475 | { | ||
476 | unsigned long flags; | ||
477 | struct ib_event_handler *handler; | ||
478 | |||
479 | spin_lock_irqsave(&event->device->event_handler_lock, flags); | ||
480 | |||
481 | list_for_each_entry(handler, &event->device->event_handler_list, list) | ||
482 | handler->handler(handler, event); | ||
483 | |||
484 | spin_unlock_irqrestore(&event->device->event_handler_lock, flags); | ||
485 | } | ||
486 | EXPORT_SYMBOL(ib_dispatch_event); | ||
487 | |||
488 | /** | ||
489 | * ib_query_device - Query IB device attributes | ||
490 | * @device:Device to query | ||
491 | * @device_attr:Device attributes | ||
492 | * | ||
493 | * ib_query_device() returns the attributes of a device through the | ||
494 | * @device_attr pointer. | ||
495 | */ | ||
496 | int ib_query_device(struct ib_device *device, | ||
497 | struct ib_device_attr *device_attr) | ||
498 | { | ||
499 | return device->query_device(device, device_attr); | ||
500 | } | ||
501 | EXPORT_SYMBOL(ib_query_device); | ||
502 | |||
503 | /** | ||
504 | * ib_query_port - Query IB port attributes | ||
505 | * @device:Device to query | ||
506 | * @port_num:Port number to query | ||
507 | * @port_attr:Port attributes | ||
508 | * | ||
509 | * ib_query_port() returns the attributes of a port through the | ||
510 | * @port_attr pointer. | ||
511 | */ | ||
512 | int ib_query_port(struct ib_device *device, | ||
513 | u8 port_num, | ||
514 | struct ib_port_attr *port_attr) | ||
515 | { | ||
516 | return device->query_port(device, port_num, port_attr); | ||
517 | } | ||
518 | EXPORT_SYMBOL(ib_query_port); | ||
519 | |||
520 | /** | ||
521 | * ib_query_gid - Get GID table entry | ||
522 | * @device:Device to query | ||
523 | * @port_num:Port number to query | ||
524 | * @index:GID table index to query | ||
525 | * @gid:Returned GID | ||
526 | * | ||
527 | * ib_query_gid() fetches the specified GID table entry. | ||
528 | */ | ||
529 | int ib_query_gid(struct ib_device *device, | ||
530 | u8 port_num, int index, union ib_gid *gid) | ||
531 | { | ||
532 | return device->query_gid(device, port_num, index, gid); | ||
533 | } | ||
534 | EXPORT_SYMBOL(ib_query_gid); | ||
535 | |||
536 | /** | ||
537 | * ib_query_pkey - Get P_Key table entry | ||
538 | * @device:Device to query | ||
539 | * @port_num:Port number to query | ||
540 | * @index:P_Key table index to query | ||
541 | * @pkey:Returned P_Key | ||
542 | * | ||
543 | * ib_query_pkey() fetches the specified P_Key table entry. | ||
544 | */ | ||
545 | int ib_query_pkey(struct ib_device *device, | ||
546 | u8 port_num, u16 index, u16 *pkey) | ||
547 | { | ||
548 | return device->query_pkey(device, port_num, index, pkey); | ||
549 | } | ||
550 | EXPORT_SYMBOL(ib_query_pkey); | ||
551 | |||
552 | /** | ||
553 | * ib_modify_device - Change IB device attributes | ||
554 | * @device:Device to modify | ||
555 | * @device_modify_mask:Mask of attributes to change | ||
556 | * @device_modify:New attribute values | ||
557 | * | ||
558 | * ib_modify_device() changes a device's attributes as specified by | ||
559 | * the @device_modify_mask and @device_modify structure. | ||
560 | */ | ||
561 | int ib_modify_device(struct ib_device *device, | ||
562 | int device_modify_mask, | ||
563 | struct ib_device_modify *device_modify) | ||
564 | { | ||
565 | return device->modify_device(device, device_modify_mask, | ||
566 | device_modify); | ||
567 | } | ||
568 | EXPORT_SYMBOL(ib_modify_device); | ||
569 | |||
570 | /** | ||
571 | * ib_modify_port - Modifies the attributes for the specified port. | ||
572 | * @device: The device to modify. | ||
573 | * @port_num: The number of the port to modify. | ||
574 | * @port_modify_mask: Mask used to specify which attributes of the port | ||
575 | * to change. | ||
576 | * @port_modify: New attribute values for the port. | ||
577 | * | ||
578 | * ib_modify_port() changes a port's attributes as specified by the | ||
579 | * @port_modify_mask and @port_modify structure. | ||
580 | */ | ||
581 | int ib_modify_port(struct ib_device *device, | ||
582 | u8 port_num, int port_modify_mask, | ||
583 | struct ib_port_modify *port_modify) | ||
584 | { | ||
585 | return device->modify_port(device, port_num, port_modify_mask, | ||
586 | port_modify); | ||
587 | } | ||
588 | EXPORT_SYMBOL(ib_modify_port); | ||
589 | |||
590 | static int __init ib_core_init(void) | ||
591 | { | ||
592 | int ret; | ||
593 | |||
594 | ret = ib_sysfs_setup(); | ||
595 | if (ret) | ||
596 | printk(KERN_WARNING "Couldn't create InfiniBand device class\n"); | ||
597 | |||
598 | ret = ib_cache_setup(); | ||
599 | if (ret) { | ||
600 | printk(KERN_WARNING "Couldn't set up InfiniBand P_Key/GID cache\n"); | ||
601 | ib_sysfs_cleanup(); | ||
602 | } | ||
603 | |||
604 | return ret; | ||
605 | } | ||
606 | |||
607 | static void __exit ib_core_cleanup(void) | ||
608 | { | ||
609 | ib_cache_cleanup(); | ||
610 | ib_sysfs_cleanup(); | ||
611 | } | ||
612 | |||
613 | module_init(ib_core_init); | ||
614 | module_exit(ib_core_cleanup); | ||
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c new file mode 100644 index 000000000000..2e9469f18926 --- /dev/null +++ b/drivers/infiniband/core/fmr_pool.c | |||
@@ -0,0 +1,507 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | * $Id: fmr_pool.c 1349 2004-12-16 21:09:43Z roland $ | ||
33 | */ | ||
34 | |||
35 | #include <linux/errno.h> | ||
36 | #include <linux/spinlock.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/jhash.h> | ||
39 | #include <linux/kthread.h> | ||
40 | |||
41 | #include <ib_fmr_pool.h> | ||
42 | |||
43 | #include "core_priv.h" | ||
44 | |||
45 | enum { | ||
46 | IB_FMR_MAX_REMAPS = 32, | ||
47 | |||
48 | IB_FMR_HASH_BITS = 8, | ||
49 | IB_FMR_HASH_SIZE = 1 << IB_FMR_HASH_BITS, | ||
50 | IB_FMR_HASH_MASK = IB_FMR_HASH_SIZE - 1 | ||
51 | }; | ||
52 | |||
53 | /* | ||
54 | * If an FMR is not in use, then the list member will point to either | ||
55 | * its pool's free_list (if the FMR can be mapped again; that is, | ||
56 | * remap_count < IB_FMR_MAX_REMAPS) or its pool's dirty_list (if the | ||
57 | * FMR needs to be unmapped before being remapped). In either of | ||
58 | * these cases it is a bug if the ref_count is not 0. In other words, | ||
59 | * if ref_count is > 0, then the list member must not be linked into | ||
60 | * either free_list or dirty_list. | ||
61 | * | ||
62 | * The cache_node member is used to link the FMR into a cache bucket | ||
63 | * (if caching is enabled). This is independent of the reference | ||
64 | * count of the FMR. When a valid FMR is released, its ref_count is | ||
65 | * decremented, and if ref_count reaches 0, the FMR is placed in | ||
66 | * either free_list or dirty_list as appropriate. However, it is not | ||
67 | * removed from the cache and may be "revived" if a call to | ||
68 | * ib_fmr_register_physical() occurs before the FMR is remapped. In | ||
69 | * this case we just increment the ref_count and remove the FMR from | ||
70 | * free_list/dirty_list. | ||
71 | * | ||
72 | * Before we remap an FMR from free_list, we remove it from the cache | ||
73 | * (to prevent another user from obtaining a stale FMR). When an FMR | ||
74 | * is released, we add it to the tail of the free list, so that our | ||
75 | * cache eviction policy is "least recently used." | ||
76 | * | ||
77 | * All manipulation of ref_count, list and cache_node is protected by | ||
78 | * pool_lock to maintain consistency. | ||
79 | */ | ||
80 | |||
81 | struct ib_fmr_pool { | ||
82 | spinlock_t pool_lock; | ||
83 | |||
84 | int pool_size; | ||
85 | int max_pages; | ||
86 | int dirty_watermark; | ||
87 | int dirty_len; | ||
88 | struct list_head free_list; | ||
89 | struct list_head dirty_list; | ||
90 | struct hlist_head *cache_bucket; | ||
91 | |||
92 | void (*flush_function)(struct ib_fmr_pool *pool, | ||
93 | void * arg); | ||
94 | void *flush_arg; | ||
95 | |||
96 | struct task_struct *thread; | ||
97 | |||
98 | atomic_t req_ser; | ||
99 | atomic_t flush_ser; | ||
100 | |||
101 | wait_queue_head_t force_wait; | ||
102 | }; | ||
103 | |||
104 | static inline u32 ib_fmr_hash(u64 first_page) | ||
105 | { | ||
106 | return jhash_2words((u32) first_page, | ||
107 | (u32) (first_page >> 32), | ||
108 | 0); | ||
109 | } | ||
110 | |||
111 | /* Caller must hold pool_lock */ | ||
112 | static inline struct ib_pool_fmr *ib_fmr_cache_lookup(struct ib_fmr_pool *pool, | ||
113 | u64 *page_list, | ||
114 | int page_list_len, | ||
115 | u64 io_virtual_address) | ||
116 | { | ||
117 | struct hlist_head *bucket; | ||
118 | struct ib_pool_fmr *fmr; | ||
119 | struct hlist_node *pos; | ||
120 | |||
121 | if (!pool->cache_bucket) | ||
122 | return NULL; | ||
123 | |||
124 | bucket = pool->cache_bucket + ib_fmr_hash(*page_list); | ||
125 | |||
126 | hlist_for_each_entry(fmr, pos, bucket, cache_node) | ||
127 | if (io_virtual_address == fmr->io_virtual_address && | ||
128 | page_list_len == fmr->page_list_len && | ||
129 | !memcmp(page_list, fmr->page_list, | ||
130 | page_list_len * sizeof *page_list)) | ||
131 | return fmr; | ||
132 | |||
133 | return NULL; | ||
134 | } | ||
135 | |||
136 | static void ib_fmr_batch_release(struct ib_fmr_pool *pool) | ||
137 | { | ||
138 | int ret; | ||
139 | struct ib_pool_fmr *fmr; | ||
140 | LIST_HEAD(unmap_list); | ||
141 | LIST_HEAD(fmr_list); | ||
142 | |||
143 | spin_lock_irq(&pool->pool_lock); | ||
144 | |||
145 | list_for_each_entry(fmr, &pool->dirty_list, list) { | ||
146 | hlist_del_init(&fmr->cache_node); | ||
147 | fmr->remap_count = 0; | ||
148 | list_add_tail(&fmr->fmr->list, &fmr_list); | ||
149 | |||
150 | #ifdef DEBUG | ||
151 | if (fmr->ref_count !=0) { | ||
152 | printk(KERN_WARNING "Unmapping FMR 0x%08x with ref count %d", | ||
153 | fmr, fmr->ref_count); | ||
154 | } | ||
155 | #endif | ||
156 | } | ||
157 | |||
158 | list_splice(&pool->dirty_list, &unmap_list); | ||
159 | INIT_LIST_HEAD(&pool->dirty_list); | ||
160 | pool->dirty_len = 0; | ||
161 | |||
162 | spin_unlock_irq(&pool->pool_lock); | ||
163 | |||
164 | if (list_empty(&unmap_list)) { | ||
165 | return; | ||
166 | } | ||
167 | |||
168 | ret = ib_unmap_fmr(&fmr_list); | ||
169 | if (ret) | ||
170 | printk(KERN_WARNING "ib_unmap_fmr returned %d", ret); | ||
171 | |||
172 | spin_lock_irq(&pool->pool_lock); | ||
173 | list_splice(&unmap_list, &pool->free_list); | ||
174 | spin_unlock_irq(&pool->pool_lock); | ||
175 | } | ||
176 | |||
177 | static int ib_fmr_cleanup_thread(void *pool_ptr) | ||
178 | { | ||
179 | struct ib_fmr_pool *pool = pool_ptr; | ||
180 | |||
181 | do { | ||
182 | if (pool->dirty_len >= pool->dirty_watermark || | ||
183 | atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) { | ||
184 | ib_fmr_batch_release(pool); | ||
185 | |||
186 | atomic_inc(&pool->flush_ser); | ||
187 | wake_up_interruptible(&pool->force_wait); | ||
188 | |||
189 | if (pool->flush_function) | ||
190 | pool->flush_function(pool, pool->flush_arg); | ||
191 | } | ||
192 | |||
193 | set_current_state(TASK_INTERRUPTIBLE); | ||
194 | if (pool->dirty_len < pool->dirty_watermark && | ||
195 | atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 && | ||
196 | !kthread_should_stop()) | ||
197 | schedule(); | ||
198 | __set_current_state(TASK_RUNNING); | ||
199 | } while (!kthread_should_stop()); | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | /** | ||
205 | * ib_create_fmr_pool - Create an FMR pool | ||
206 | * @pd:Protection domain for FMRs | ||
207 | * @params:FMR pool parameters | ||
208 | * | ||
209 | * Create a pool of FMRs. Return value is pointer to new pool or | ||
210 | * error code if creation failed. | ||
211 | */ | ||
212 | struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, | ||
213 | struct ib_fmr_pool_param *params) | ||
214 | { | ||
215 | struct ib_device *device; | ||
216 | struct ib_fmr_pool *pool; | ||
217 | int i; | ||
218 | int ret; | ||
219 | |||
220 | if (!params) | ||
221 | return ERR_PTR(-EINVAL); | ||
222 | |||
223 | device = pd->device; | ||
224 | if (!device->alloc_fmr || !device->dealloc_fmr || | ||
225 | !device->map_phys_fmr || !device->unmap_fmr) { | ||
226 | printk(KERN_WARNING "Device %s does not support fast memory regions", | ||
227 | device->name); | ||
228 | return ERR_PTR(-ENOSYS); | ||
229 | } | ||
230 | |||
231 | pool = kmalloc(sizeof *pool, GFP_KERNEL); | ||
232 | if (!pool) { | ||
233 | printk(KERN_WARNING "couldn't allocate pool struct"); | ||
234 | return ERR_PTR(-ENOMEM); | ||
235 | } | ||
236 | |||
237 | pool->cache_bucket = NULL; | ||
238 | |||
239 | pool->flush_function = params->flush_function; | ||
240 | pool->flush_arg = params->flush_arg; | ||
241 | |||
242 | INIT_LIST_HEAD(&pool->free_list); | ||
243 | INIT_LIST_HEAD(&pool->dirty_list); | ||
244 | |||
245 | if (params->cache) { | ||
246 | pool->cache_bucket = | ||
247 | kmalloc(IB_FMR_HASH_SIZE * sizeof *pool->cache_bucket, | ||
248 | GFP_KERNEL); | ||
249 | if (!pool->cache_bucket) { | ||
250 | printk(KERN_WARNING "Failed to allocate cache in pool"); | ||
251 | ret = -ENOMEM; | ||
252 | goto out_free_pool; | ||
253 | } | ||
254 | |||
255 | for (i = 0; i < IB_FMR_HASH_SIZE; ++i) | ||
256 | INIT_HLIST_HEAD(pool->cache_bucket + i); | ||
257 | } | ||
258 | |||
259 | pool->pool_size = 0; | ||
260 | pool->max_pages = params->max_pages_per_fmr; | ||
261 | pool->dirty_watermark = params->dirty_watermark; | ||
262 | pool->dirty_len = 0; | ||
263 | spin_lock_init(&pool->pool_lock); | ||
264 | atomic_set(&pool->req_ser, 0); | ||
265 | atomic_set(&pool->flush_ser, 0); | ||
266 | init_waitqueue_head(&pool->force_wait); | ||
267 | |||
268 | pool->thread = kthread_create(ib_fmr_cleanup_thread, | ||
269 | pool, | ||
270 | "ib_fmr(%s)", | ||
271 | device->name); | ||
272 | if (IS_ERR(pool->thread)) { | ||
273 | printk(KERN_WARNING "couldn't start cleanup thread"); | ||
274 | ret = PTR_ERR(pool->thread); | ||
275 | goto out_free_pool; | ||
276 | } | ||
277 | |||
278 | { | ||
279 | struct ib_pool_fmr *fmr; | ||
280 | struct ib_fmr_attr attr = { | ||
281 | .max_pages = params->max_pages_per_fmr, | ||
282 | .max_maps = IB_FMR_MAX_REMAPS, | ||
283 | .page_size = PAGE_SHIFT | ||
284 | }; | ||
285 | |||
286 | for (i = 0; i < params->pool_size; ++i) { | ||
287 | fmr = kmalloc(sizeof *fmr + params->max_pages_per_fmr * sizeof (u64), | ||
288 | GFP_KERNEL); | ||
289 | if (!fmr) { | ||
290 | printk(KERN_WARNING "failed to allocate fmr struct " | ||
291 | "for FMR %d", i); | ||
292 | goto out_fail; | ||
293 | } | ||
294 | |||
295 | fmr->pool = pool; | ||
296 | fmr->remap_count = 0; | ||
297 | fmr->ref_count = 0; | ||
298 | INIT_HLIST_NODE(&fmr->cache_node); | ||
299 | |||
300 | fmr->fmr = ib_alloc_fmr(pd, params->access, &attr); | ||
301 | if (IS_ERR(fmr->fmr)) { | ||
302 | printk(KERN_WARNING "fmr_create failed for FMR %d", i); | ||
303 | kfree(fmr); | ||
304 | goto out_fail; | ||
305 | } | ||
306 | |||
307 | list_add_tail(&fmr->list, &pool->free_list); | ||
308 | ++pool->pool_size; | ||
309 | } | ||
310 | } | ||
311 | |||
312 | return pool; | ||
313 | |||
314 | out_free_pool: | ||
315 | kfree(pool->cache_bucket); | ||
316 | kfree(pool); | ||
317 | |||
318 | return ERR_PTR(ret); | ||
319 | |||
320 | out_fail: | ||
321 | ib_destroy_fmr_pool(pool); | ||
322 | |||
323 | return ERR_PTR(-ENOMEM); | ||
324 | } | ||
325 | EXPORT_SYMBOL(ib_create_fmr_pool); | ||
326 | |||
327 | /** | ||
328 | * ib_destroy_fmr_pool - Free FMR pool | ||
329 | * @pool:FMR pool to free | ||
330 | * | ||
331 | * Destroy an FMR pool and free all associated resources. | ||
332 | */ | ||
333 | int ib_destroy_fmr_pool(struct ib_fmr_pool *pool) | ||
334 | { | ||
335 | struct ib_pool_fmr *fmr; | ||
336 | struct ib_pool_fmr *tmp; | ||
337 | int i; | ||
338 | |||
339 | kthread_stop(pool->thread); | ||
340 | ib_fmr_batch_release(pool); | ||
341 | |||
342 | i = 0; | ||
343 | list_for_each_entry_safe(fmr, tmp, &pool->free_list, list) { | ||
344 | ib_dealloc_fmr(fmr->fmr); | ||
345 | list_del(&fmr->list); | ||
346 | kfree(fmr); | ||
347 | ++i; | ||
348 | } | ||
349 | |||
350 | if (i < pool->pool_size) | ||
351 | printk(KERN_WARNING "pool still has %d regions registered", | ||
352 | pool->pool_size - i); | ||
353 | |||
354 | kfree(pool->cache_bucket); | ||
355 | kfree(pool); | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | EXPORT_SYMBOL(ib_destroy_fmr_pool); | ||
360 | |||
361 | /** | ||
362 | * ib_flush_fmr_pool - Invalidate all unmapped FMRs | ||
363 | * @pool:FMR pool to flush | ||
364 | * | ||
365 | * Ensure that all unmapped FMRs are fully invalidated. | ||
366 | */ | ||
367 | int ib_flush_fmr_pool(struct ib_fmr_pool *pool) | ||
368 | { | ||
369 | int serial; | ||
370 | |||
371 | atomic_inc(&pool->req_ser); | ||
372 | /* | ||
373 | * It's OK if someone else bumps req_ser again here -- we'll | ||
374 | * just wait a little longer. | ||
375 | */ | ||
376 | serial = atomic_read(&pool->req_ser); | ||
377 | |||
378 | wake_up_process(pool->thread); | ||
379 | |||
380 | if (wait_event_interruptible(pool->force_wait, | ||
381 | atomic_read(&pool->flush_ser) - | ||
382 | atomic_read(&pool->req_ser) >= 0)) | ||
383 | return -EINTR; | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | EXPORT_SYMBOL(ib_flush_fmr_pool); | ||
388 | |||
389 | /** | ||
390 | * ib_fmr_pool_map_phys - | ||
391 | * @pool:FMR pool to allocate FMR from | ||
392 | * @page_list:List of pages to map | ||
393 | * @list_len:Number of pages in @page_list | ||
394 | * @io_virtual_address:I/O virtual address for new FMR | ||
395 | * | ||
396 | * Map an FMR from an FMR pool. | ||
397 | */ | ||
398 | struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle, | ||
399 | u64 *page_list, | ||
400 | int list_len, | ||
401 | u64 *io_virtual_address) | ||
402 | { | ||
403 | struct ib_fmr_pool *pool = pool_handle; | ||
404 | struct ib_pool_fmr *fmr; | ||
405 | unsigned long flags; | ||
406 | int result; | ||
407 | |||
408 | if (list_len < 1 || list_len > pool->max_pages) | ||
409 | return ERR_PTR(-EINVAL); | ||
410 | |||
411 | spin_lock_irqsave(&pool->pool_lock, flags); | ||
412 | fmr = ib_fmr_cache_lookup(pool, | ||
413 | page_list, | ||
414 | list_len, | ||
415 | *io_virtual_address); | ||
416 | if (fmr) { | ||
417 | /* found in cache */ | ||
418 | ++fmr->ref_count; | ||
419 | if (fmr->ref_count == 1) { | ||
420 | list_del(&fmr->list); | ||
421 | } | ||
422 | |||
423 | spin_unlock_irqrestore(&pool->pool_lock, flags); | ||
424 | |||
425 | return fmr; | ||
426 | } | ||
427 | |||
428 | if (list_empty(&pool->free_list)) { | ||
429 | spin_unlock_irqrestore(&pool->pool_lock, flags); | ||
430 | return ERR_PTR(-EAGAIN); | ||
431 | } | ||
432 | |||
433 | fmr = list_entry(pool->free_list.next, struct ib_pool_fmr, list); | ||
434 | list_del(&fmr->list); | ||
435 | hlist_del_init(&fmr->cache_node); | ||
436 | spin_unlock_irqrestore(&pool->pool_lock, flags); | ||
437 | |||
438 | result = ib_map_phys_fmr(fmr->fmr, page_list, list_len, | ||
439 | *io_virtual_address); | ||
440 | |||
441 | if (result) { | ||
442 | spin_lock_irqsave(&pool->pool_lock, flags); | ||
443 | list_add(&fmr->list, &pool->free_list); | ||
444 | spin_unlock_irqrestore(&pool->pool_lock, flags); | ||
445 | |||
446 | printk(KERN_WARNING "fmr_map returns %d", | ||
447 | result); | ||
448 | |||
449 | return ERR_PTR(result); | ||
450 | } | ||
451 | |||
452 | ++fmr->remap_count; | ||
453 | fmr->ref_count = 1; | ||
454 | |||
455 | if (pool->cache_bucket) { | ||
456 | fmr->io_virtual_address = *io_virtual_address; | ||
457 | fmr->page_list_len = list_len; | ||
458 | memcpy(fmr->page_list, page_list, list_len * sizeof(*page_list)); | ||
459 | |||
460 | spin_lock_irqsave(&pool->pool_lock, flags); | ||
461 | hlist_add_head(&fmr->cache_node, | ||
462 | pool->cache_bucket + ib_fmr_hash(fmr->page_list[0])); | ||
463 | spin_unlock_irqrestore(&pool->pool_lock, flags); | ||
464 | } | ||
465 | |||
466 | return fmr; | ||
467 | } | ||
468 | EXPORT_SYMBOL(ib_fmr_pool_map_phys); | ||
469 | |||
470 | /** | ||
471 | * ib_fmr_pool_unmap - Unmap FMR | ||
472 | * @fmr:FMR to unmap | ||
473 | * | ||
474 | * Unmap an FMR. The FMR mapping may remain valid until the FMR is | ||
475 | * reused (or until ib_flush_fmr_pool() is called). | ||
476 | */ | ||
477 | int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr) | ||
478 | { | ||
479 | struct ib_fmr_pool *pool; | ||
480 | unsigned long flags; | ||
481 | |||
482 | pool = fmr->pool; | ||
483 | |||
484 | spin_lock_irqsave(&pool->pool_lock, flags); | ||
485 | |||
486 | --fmr->ref_count; | ||
487 | if (!fmr->ref_count) { | ||
488 | if (fmr->remap_count < IB_FMR_MAX_REMAPS) { | ||
489 | list_add_tail(&fmr->list, &pool->free_list); | ||
490 | } else { | ||
491 | list_add_tail(&fmr->list, &pool->dirty_list); | ||
492 | ++pool->dirty_len; | ||
493 | wake_up_process(pool->thread); | ||
494 | } | ||
495 | } | ||
496 | |||
497 | #ifdef DEBUG | ||
498 | if (fmr->ref_count < 0) | ||
499 | printk(KERN_WARNING "FMR %p has ref count %d < 0", | ||
500 | fmr, fmr->ref_count); | ||
501 | #endif | ||
502 | |||
503 | spin_unlock_irqrestore(&pool->pool_lock, flags); | ||
504 | |||
505 | return 0; | ||
506 | } | ||
507 | EXPORT_SYMBOL(ib_fmr_pool_unmap); | ||
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c new file mode 100644 index 000000000000..4ec7fff29b5d --- /dev/null +++ b/drivers/infiniband/core/mad.c | |||
@@ -0,0 +1,2714 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | * $Id: mad.c 1389 2004-12-27 22:56:47Z roland $ | ||
33 | */ | ||
34 | |||
35 | #include <linux/dma-mapping.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | |||
38 | #include <ib_mad.h> | ||
39 | |||
40 | #include "mad_priv.h" | ||
41 | #include "smi.h" | ||
42 | #include "agent.h" | ||
43 | |||
44 | MODULE_LICENSE("Dual BSD/GPL"); | ||
45 | MODULE_DESCRIPTION("kernel IB MAD API"); | ||
46 | MODULE_AUTHOR("Hal Rosenstock"); | ||
47 | MODULE_AUTHOR("Sean Hefty"); | ||
48 | |||
49 | |||
50 | kmem_cache_t *ib_mad_cache; | ||
51 | static struct list_head ib_mad_port_list; | ||
52 | static u32 ib_mad_client_id = 0; | ||
53 | |||
54 | /* Port list lock */ | ||
55 | static spinlock_t ib_mad_port_list_lock; | ||
56 | |||
57 | |||
58 | /* Forward declarations */ | ||
59 | static int method_in_use(struct ib_mad_mgmt_method_table **method, | ||
60 | struct ib_mad_reg_req *mad_reg_req); | ||
61 | static void remove_mad_reg_req(struct ib_mad_agent_private *priv); | ||
62 | static struct ib_mad_agent_private *find_mad_agent( | ||
63 | struct ib_mad_port_private *port_priv, | ||
64 | struct ib_mad *mad, int solicited); | ||
65 | static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info, | ||
66 | struct ib_mad_private *mad); | ||
67 | static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv); | ||
68 | static void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr, | ||
69 | struct ib_mad_send_wc *mad_send_wc); | ||
70 | static void timeout_sends(void *data); | ||
71 | static void cancel_sends(void *data); | ||
72 | static void local_completions(void *data); | ||
73 | static int solicited_mad(struct ib_mad *mad); | ||
74 | static int add_nonoui_reg_req(struct ib_mad_reg_req *mad_reg_req, | ||
75 | struct ib_mad_agent_private *agent_priv, | ||
76 | u8 mgmt_class); | ||
77 | static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req, | ||
78 | struct ib_mad_agent_private *agent_priv); | ||
79 | |||
80 | /* | ||
81 | * Returns a ib_mad_port_private structure or NULL for a device/port | ||
82 | * Assumes ib_mad_port_list_lock is being held | ||
83 | */ | ||
84 | static inline struct ib_mad_port_private * | ||
85 | __ib_get_mad_port(struct ib_device *device, int port_num) | ||
86 | { | ||
87 | struct ib_mad_port_private *entry; | ||
88 | |||
89 | list_for_each_entry(entry, &ib_mad_port_list, port_list) { | ||
90 | if (entry->device == device && entry->port_num == port_num) | ||
91 | return entry; | ||
92 | } | ||
93 | return NULL; | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Wrapper function to return a ib_mad_port_private structure or NULL | ||
98 | * for a device/port | ||
99 | */ | ||
100 | static inline struct ib_mad_port_private * | ||
101 | ib_get_mad_port(struct ib_device *device, int port_num) | ||
102 | { | ||
103 | struct ib_mad_port_private *entry; | ||
104 | unsigned long flags; | ||
105 | |||
106 | spin_lock_irqsave(&ib_mad_port_list_lock, flags); | ||
107 | entry = __ib_get_mad_port(device, port_num); | ||
108 | spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); | ||
109 | |||
110 | return entry; | ||
111 | } | ||
112 | |||
113 | static inline u8 convert_mgmt_class(u8 mgmt_class) | ||
114 | { | ||
115 | /* Alias IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE to 0 */ | ||
116 | return mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ? | ||
117 | 0 : mgmt_class; | ||
118 | } | ||
119 | |||
120 | static int get_spl_qp_index(enum ib_qp_type qp_type) | ||
121 | { | ||
122 | switch (qp_type) | ||
123 | { | ||
124 | case IB_QPT_SMI: | ||
125 | return 0; | ||
126 | case IB_QPT_GSI: | ||
127 | return 1; | ||
128 | default: | ||
129 | return -1; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | static int vendor_class_index(u8 mgmt_class) | ||
134 | { | ||
135 | return mgmt_class - IB_MGMT_CLASS_VENDOR_RANGE2_START; | ||
136 | } | ||
137 | |||
138 | static int is_vendor_class(u8 mgmt_class) | ||
139 | { | ||
140 | if ((mgmt_class < IB_MGMT_CLASS_VENDOR_RANGE2_START) || | ||
141 | (mgmt_class > IB_MGMT_CLASS_VENDOR_RANGE2_END)) | ||
142 | return 0; | ||
143 | return 1; | ||
144 | } | ||
145 | |||
146 | static int is_vendor_oui(char *oui) | ||
147 | { | ||
148 | if (oui[0] || oui[1] || oui[2]) | ||
149 | return 1; | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int is_vendor_method_in_use( | ||
154 | struct ib_mad_mgmt_vendor_class *vendor_class, | ||
155 | struct ib_mad_reg_req *mad_reg_req) | ||
156 | { | ||
157 | struct ib_mad_mgmt_method_table *method; | ||
158 | int i; | ||
159 | |||
160 | for (i = 0; i < MAX_MGMT_OUI; i++) { | ||
161 | if (!memcmp(vendor_class->oui[i], mad_reg_req->oui, 3)) { | ||
162 | method = vendor_class->method_table[i]; | ||
163 | if (method) { | ||
164 | if (method_in_use(&method, mad_reg_req)) | ||
165 | return 1; | ||
166 | else | ||
167 | break; | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | /* | ||
175 | * ib_register_mad_agent - Register to send/receive MADs | ||
176 | */ | ||
177 | struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, | ||
178 | u8 port_num, | ||
179 | enum ib_qp_type qp_type, | ||
180 | struct ib_mad_reg_req *mad_reg_req, | ||
181 | u8 rmpp_version, | ||
182 | ib_mad_send_handler send_handler, | ||
183 | ib_mad_recv_handler recv_handler, | ||
184 | void *context) | ||
185 | { | ||
186 | struct ib_mad_port_private *port_priv; | ||
187 | struct ib_mad_agent *ret = ERR_PTR(-EINVAL); | ||
188 | struct ib_mad_agent_private *mad_agent_priv; | ||
189 | struct ib_mad_reg_req *reg_req = NULL; | ||
190 | struct ib_mad_mgmt_class_table *class; | ||
191 | struct ib_mad_mgmt_vendor_class_table *vendor; | ||
192 | struct ib_mad_mgmt_vendor_class *vendor_class; | ||
193 | struct ib_mad_mgmt_method_table *method; | ||
194 | int ret2, qpn; | ||
195 | unsigned long flags; | ||
196 | u8 mgmt_class, vclass; | ||
197 | |||
198 | /* Validate parameters */ | ||
199 | qpn = get_spl_qp_index(qp_type); | ||
200 | if (qpn == -1) | ||
201 | goto error1; | ||
202 | |||
203 | if (rmpp_version) | ||
204 | goto error1; /* XXX: until RMPP implemented */ | ||
205 | |||
206 | /* Validate MAD registration request if supplied */ | ||
207 | if (mad_reg_req) { | ||
208 | if (mad_reg_req->mgmt_class_version >= MAX_MGMT_VERSION) | ||
209 | goto error1; | ||
210 | if (!recv_handler) | ||
211 | goto error1; | ||
212 | if (mad_reg_req->mgmt_class >= MAX_MGMT_CLASS) { | ||
213 | /* | ||
214 | * IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE is the only | ||
215 | * one in this range currently allowed | ||
216 | */ | ||
217 | if (mad_reg_req->mgmt_class != | ||
218 | IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) | ||
219 | goto error1; | ||
220 | } else if (mad_reg_req->mgmt_class == 0) { | ||
221 | /* | ||
222 | * Class 0 is reserved in IBA and is used for | ||
223 | * aliasing of IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE | ||
224 | */ | ||
225 | goto error1; | ||
226 | } else if (is_vendor_class(mad_reg_req->mgmt_class)) { | ||
227 | /* | ||
228 | * If class is in "new" vendor range, | ||
229 | * ensure supplied OUI is not zero | ||
230 | */ | ||
231 | if (!is_vendor_oui(mad_reg_req->oui)) | ||
232 | goto error1; | ||
233 | } | ||
234 | /* Make sure class supplied is consistent with QP type */ | ||
235 | if (qp_type == IB_QPT_SMI) { | ||
236 | if ((mad_reg_req->mgmt_class != | ||
237 | IB_MGMT_CLASS_SUBN_LID_ROUTED) && | ||
238 | (mad_reg_req->mgmt_class != | ||
239 | IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)) | ||
240 | goto error1; | ||
241 | } else { | ||
242 | if ((mad_reg_req->mgmt_class == | ||
243 | IB_MGMT_CLASS_SUBN_LID_ROUTED) || | ||
244 | (mad_reg_req->mgmt_class == | ||
245 | IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)) | ||
246 | goto error1; | ||
247 | } | ||
248 | } else { | ||
249 | /* No registration request supplied */ | ||
250 | if (!send_handler) | ||
251 | goto error1; | ||
252 | } | ||
253 | |||
254 | /* Validate device and port */ | ||
255 | port_priv = ib_get_mad_port(device, port_num); | ||
256 | if (!port_priv) { | ||
257 | ret = ERR_PTR(-ENODEV); | ||
258 | goto error1; | ||
259 | } | ||
260 | |||
261 | /* Allocate structures */ | ||
262 | mad_agent_priv = kmalloc(sizeof *mad_agent_priv, GFP_KERNEL); | ||
263 | if (!mad_agent_priv) { | ||
264 | ret = ERR_PTR(-ENOMEM); | ||
265 | goto error1; | ||
266 | } | ||
267 | |||
268 | if (mad_reg_req) { | ||
269 | reg_req = kmalloc(sizeof *reg_req, GFP_KERNEL); | ||
270 | if (!reg_req) { | ||
271 | ret = ERR_PTR(-ENOMEM); | ||
272 | goto error2; | ||
273 | } | ||
274 | /* Make a copy of the MAD registration request */ | ||
275 | memcpy(reg_req, mad_reg_req, sizeof *reg_req); | ||
276 | } | ||
277 | |||
278 | /* Now, fill in the various structures */ | ||
279 | memset(mad_agent_priv, 0, sizeof *mad_agent_priv); | ||
280 | mad_agent_priv->qp_info = &port_priv->qp_info[qpn]; | ||
281 | mad_agent_priv->reg_req = reg_req; | ||
282 | mad_agent_priv->rmpp_version = rmpp_version; | ||
283 | mad_agent_priv->agent.device = device; | ||
284 | mad_agent_priv->agent.recv_handler = recv_handler; | ||
285 | mad_agent_priv->agent.send_handler = send_handler; | ||
286 | mad_agent_priv->agent.context = context; | ||
287 | mad_agent_priv->agent.qp = port_priv->qp_info[qpn].qp; | ||
288 | mad_agent_priv->agent.port_num = port_num; | ||
289 | |||
290 | spin_lock_irqsave(&port_priv->reg_lock, flags); | ||
291 | mad_agent_priv->agent.hi_tid = ++ib_mad_client_id; | ||
292 | |||
293 | /* | ||
294 | * Make sure MAD registration (if supplied) | ||
295 | * is non overlapping with any existing ones | ||
296 | */ | ||
297 | if (mad_reg_req) { | ||
298 | mgmt_class = convert_mgmt_class(mad_reg_req->mgmt_class); | ||
299 | if (!is_vendor_class(mgmt_class)) { | ||
300 | class = port_priv->version[mad_reg_req-> | ||
301 | mgmt_class_version].class; | ||
302 | if (class) { | ||
303 | method = class->method_table[mgmt_class]; | ||
304 | if (method) { | ||
305 | if (method_in_use(&method, | ||
306 | mad_reg_req)) | ||
307 | goto error3; | ||
308 | } | ||
309 | } | ||
310 | ret2 = add_nonoui_reg_req(mad_reg_req, mad_agent_priv, | ||
311 | mgmt_class); | ||
312 | } else { | ||
313 | /* "New" vendor class range */ | ||
314 | vendor = port_priv->version[mad_reg_req-> | ||
315 | mgmt_class_version].vendor; | ||
316 | if (vendor) { | ||
317 | vclass = vendor_class_index(mgmt_class); | ||
318 | vendor_class = vendor->vendor_class[vclass]; | ||
319 | if (vendor_class) { | ||
320 | if (is_vendor_method_in_use( | ||
321 | vendor_class, | ||
322 | mad_reg_req)) | ||
323 | goto error3; | ||
324 | } | ||
325 | } | ||
326 | ret2 = add_oui_reg_req(mad_reg_req, mad_agent_priv); | ||
327 | } | ||
328 | if (ret2) { | ||
329 | ret = ERR_PTR(ret2); | ||
330 | goto error3; | ||
331 | } | ||
332 | } | ||
333 | |||
334 | /* Add mad agent into port's agent list */ | ||
335 | list_add_tail(&mad_agent_priv->agent_list, &port_priv->agent_list); | ||
336 | spin_unlock_irqrestore(&port_priv->reg_lock, flags); | ||
337 | |||
338 | spin_lock_init(&mad_agent_priv->lock); | ||
339 | INIT_LIST_HEAD(&mad_agent_priv->send_list); | ||
340 | INIT_LIST_HEAD(&mad_agent_priv->wait_list); | ||
341 | INIT_WORK(&mad_agent_priv->timed_work, timeout_sends, mad_agent_priv); | ||
342 | INIT_LIST_HEAD(&mad_agent_priv->local_list); | ||
343 | INIT_WORK(&mad_agent_priv->local_work, local_completions, | ||
344 | mad_agent_priv); | ||
345 | INIT_LIST_HEAD(&mad_agent_priv->canceled_list); | ||
346 | INIT_WORK(&mad_agent_priv->canceled_work, cancel_sends, mad_agent_priv); | ||
347 | atomic_set(&mad_agent_priv->refcount, 1); | ||
348 | init_waitqueue_head(&mad_agent_priv->wait); | ||
349 | |||
350 | return &mad_agent_priv->agent; | ||
351 | |||
352 | error3: | ||
353 | spin_unlock_irqrestore(&port_priv->reg_lock, flags); | ||
354 | kfree(reg_req); | ||
355 | error2: | ||
356 | kfree(mad_agent_priv); | ||
357 | error1: | ||
358 | return ret; | ||
359 | } | ||
360 | EXPORT_SYMBOL(ib_register_mad_agent); | ||
361 | |||
362 | static inline int is_snooping_sends(int mad_snoop_flags) | ||
363 | { | ||
364 | return (mad_snoop_flags & | ||
365 | (/*IB_MAD_SNOOP_POSTED_SENDS | | ||
366 | IB_MAD_SNOOP_RMPP_SENDS |*/ | ||
367 | IB_MAD_SNOOP_SEND_COMPLETIONS /*| | ||
368 | IB_MAD_SNOOP_RMPP_SEND_COMPLETIONS*/)); | ||
369 | } | ||
370 | |||
371 | static inline int is_snooping_recvs(int mad_snoop_flags) | ||
372 | { | ||
373 | return (mad_snoop_flags & | ||
374 | (IB_MAD_SNOOP_RECVS /*| | ||
375 | IB_MAD_SNOOP_RMPP_RECVS*/)); | ||
376 | } | ||
377 | |||
378 | static int register_snoop_agent(struct ib_mad_qp_info *qp_info, | ||
379 | struct ib_mad_snoop_private *mad_snoop_priv) | ||
380 | { | ||
381 | struct ib_mad_snoop_private **new_snoop_table; | ||
382 | unsigned long flags; | ||
383 | int i; | ||
384 | |||
385 | spin_lock_irqsave(&qp_info->snoop_lock, flags); | ||
386 | /* Check for empty slot in array. */ | ||
387 | for (i = 0; i < qp_info->snoop_table_size; i++) | ||
388 | if (!qp_info->snoop_table[i]) | ||
389 | break; | ||
390 | |||
391 | if (i == qp_info->snoop_table_size) { | ||
392 | /* Grow table. */ | ||
393 | new_snoop_table = kmalloc(sizeof mad_snoop_priv * | ||
394 | qp_info->snoop_table_size + 1, | ||
395 | GFP_ATOMIC); | ||
396 | if (!new_snoop_table) { | ||
397 | i = -ENOMEM; | ||
398 | goto out; | ||
399 | } | ||
400 | if (qp_info->snoop_table) { | ||
401 | memcpy(new_snoop_table, qp_info->snoop_table, | ||
402 | sizeof mad_snoop_priv * | ||
403 | qp_info->snoop_table_size); | ||
404 | kfree(qp_info->snoop_table); | ||
405 | } | ||
406 | qp_info->snoop_table = new_snoop_table; | ||
407 | qp_info->snoop_table_size++; | ||
408 | } | ||
409 | qp_info->snoop_table[i] = mad_snoop_priv; | ||
410 | atomic_inc(&qp_info->snoop_count); | ||
411 | out: | ||
412 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | ||
413 | return i; | ||
414 | } | ||
415 | |||
416 | struct ib_mad_agent *ib_register_mad_snoop(struct ib_device *device, | ||
417 | u8 port_num, | ||
418 | enum ib_qp_type qp_type, | ||
419 | int mad_snoop_flags, | ||
420 | ib_mad_snoop_handler snoop_handler, | ||
421 | ib_mad_recv_handler recv_handler, | ||
422 | void *context) | ||
423 | { | ||
424 | struct ib_mad_port_private *port_priv; | ||
425 | struct ib_mad_agent *ret; | ||
426 | struct ib_mad_snoop_private *mad_snoop_priv; | ||
427 | int qpn; | ||
428 | |||
429 | /* Validate parameters */ | ||
430 | if ((is_snooping_sends(mad_snoop_flags) && !snoop_handler) || | ||
431 | (is_snooping_recvs(mad_snoop_flags) && !recv_handler)) { | ||
432 | ret = ERR_PTR(-EINVAL); | ||
433 | goto error1; | ||
434 | } | ||
435 | qpn = get_spl_qp_index(qp_type); | ||
436 | if (qpn == -1) { | ||
437 | ret = ERR_PTR(-EINVAL); | ||
438 | goto error1; | ||
439 | } | ||
440 | port_priv = ib_get_mad_port(device, port_num); | ||
441 | if (!port_priv) { | ||
442 | ret = ERR_PTR(-ENODEV); | ||
443 | goto error1; | ||
444 | } | ||
445 | /* Allocate structures */ | ||
446 | mad_snoop_priv = kmalloc(sizeof *mad_snoop_priv, GFP_KERNEL); | ||
447 | if (!mad_snoop_priv) { | ||
448 | ret = ERR_PTR(-ENOMEM); | ||
449 | goto error1; | ||
450 | } | ||
451 | |||
452 | /* Now, fill in the various structures */ | ||
453 | memset(mad_snoop_priv, 0, sizeof *mad_snoop_priv); | ||
454 | mad_snoop_priv->qp_info = &port_priv->qp_info[qpn]; | ||
455 | mad_snoop_priv->agent.device = device; | ||
456 | mad_snoop_priv->agent.recv_handler = recv_handler; | ||
457 | mad_snoop_priv->agent.snoop_handler = snoop_handler; | ||
458 | mad_snoop_priv->agent.context = context; | ||
459 | mad_snoop_priv->agent.qp = port_priv->qp_info[qpn].qp; | ||
460 | mad_snoop_priv->agent.port_num = port_num; | ||
461 | mad_snoop_priv->mad_snoop_flags = mad_snoop_flags; | ||
462 | init_waitqueue_head(&mad_snoop_priv->wait); | ||
463 | mad_snoop_priv->snoop_index = register_snoop_agent( | ||
464 | &port_priv->qp_info[qpn], | ||
465 | mad_snoop_priv); | ||
466 | if (mad_snoop_priv->snoop_index < 0) { | ||
467 | ret = ERR_PTR(mad_snoop_priv->snoop_index); | ||
468 | goto error2; | ||
469 | } | ||
470 | |||
471 | atomic_set(&mad_snoop_priv->refcount, 1); | ||
472 | return &mad_snoop_priv->agent; | ||
473 | |||
474 | error2: | ||
475 | kfree(mad_snoop_priv); | ||
476 | error1: | ||
477 | return ret; | ||
478 | } | ||
479 | EXPORT_SYMBOL(ib_register_mad_snoop); | ||
480 | |||
481 | static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv) | ||
482 | { | ||
483 | struct ib_mad_port_private *port_priv; | ||
484 | unsigned long flags; | ||
485 | |||
486 | /* Note that we could still be handling received MADs */ | ||
487 | |||
488 | /* | ||
489 | * Canceling all sends results in dropping received response | ||
490 | * MADs, preventing us from queuing additional work | ||
491 | */ | ||
492 | cancel_mads(mad_agent_priv); | ||
493 | |||
494 | port_priv = mad_agent_priv->qp_info->port_priv; | ||
495 | |||
496 | cancel_delayed_work(&mad_agent_priv->timed_work); | ||
497 | flush_workqueue(port_priv->wq); | ||
498 | |||
499 | spin_lock_irqsave(&port_priv->reg_lock, flags); | ||
500 | remove_mad_reg_req(mad_agent_priv); | ||
501 | list_del(&mad_agent_priv->agent_list); | ||
502 | spin_unlock_irqrestore(&port_priv->reg_lock, flags); | ||
503 | |||
504 | /* XXX: Cleanup pending RMPP receives for this agent */ | ||
505 | |||
506 | atomic_dec(&mad_agent_priv->refcount); | ||
507 | wait_event(mad_agent_priv->wait, | ||
508 | !atomic_read(&mad_agent_priv->refcount)); | ||
509 | |||
510 | if (mad_agent_priv->reg_req) | ||
511 | kfree(mad_agent_priv->reg_req); | ||
512 | kfree(mad_agent_priv); | ||
513 | } | ||
514 | |||
515 | static void unregister_mad_snoop(struct ib_mad_snoop_private *mad_snoop_priv) | ||
516 | { | ||
517 | struct ib_mad_qp_info *qp_info; | ||
518 | unsigned long flags; | ||
519 | |||
520 | qp_info = mad_snoop_priv->qp_info; | ||
521 | spin_lock_irqsave(&qp_info->snoop_lock, flags); | ||
522 | qp_info->snoop_table[mad_snoop_priv->snoop_index] = NULL; | ||
523 | atomic_dec(&qp_info->snoop_count); | ||
524 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | ||
525 | |||
526 | atomic_dec(&mad_snoop_priv->refcount); | ||
527 | wait_event(mad_snoop_priv->wait, | ||
528 | !atomic_read(&mad_snoop_priv->refcount)); | ||
529 | |||
530 | kfree(mad_snoop_priv); | ||
531 | } | ||
532 | |||
533 | /* | ||
534 | * ib_unregister_mad_agent - Unregisters a client from using MAD services | ||
535 | */ | ||
536 | int ib_unregister_mad_agent(struct ib_mad_agent *mad_agent) | ||
537 | { | ||
538 | struct ib_mad_agent_private *mad_agent_priv; | ||
539 | struct ib_mad_snoop_private *mad_snoop_priv; | ||
540 | |||
541 | /* If the TID is zero, the agent can only snoop. */ | ||
542 | if (mad_agent->hi_tid) { | ||
543 | mad_agent_priv = container_of(mad_agent, | ||
544 | struct ib_mad_agent_private, | ||
545 | agent); | ||
546 | unregister_mad_agent(mad_agent_priv); | ||
547 | } else { | ||
548 | mad_snoop_priv = container_of(mad_agent, | ||
549 | struct ib_mad_snoop_private, | ||
550 | agent); | ||
551 | unregister_mad_snoop(mad_snoop_priv); | ||
552 | } | ||
553 | return 0; | ||
554 | } | ||
555 | EXPORT_SYMBOL(ib_unregister_mad_agent); | ||
556 | |||
557 | static void dequeue_mad(struct ib_mad_list_head *mad_list) | ||
558 | { | ||
559 | struct ib_mad_queue *mad_queue; | ||
560 | unsigned long flags; | ||
561 | |||
562 | BUG_ON(!mad_list->mad_queue); | ||
563 | mad_queue = mad_list->mad_queue; | ||
564 | spin_lock_irqsave(&mad_queue->lock, flags); | ||
565 | list_del(&mad_list->list); | ||
566 | mad_queue->count--; | ||
567 | spin_unlock_irqrestore(&mad_queue->lock, flags); | ||
568 | } | ||
569 | |||
570 | static void snoop_send(struct ib_mad_qp_info *qp_info, | ||
571 | struct ib_send_wr *send_wr, | ||
572 | struct ib_mad_send_wc *mad_send_wc, | ||
573 | int mad_snoop_flags) | ||
574 | { | ||
575 | struct ib_mad_snoop_private *mad_snoop_priv; | ||
576 | unsigned long flags; | ||
577 | int i; | ||
578 | |||
579 | spin_lock_irqsave(&qp_info->snoop_lock, flags); | ||
580 | for (i = 0; i < qp_info->snoop_table_size; i++) { | ||
581 | mad_snoop_priv = qp_info->snoop_table[i]; | ||
582 | if (!mad_snoop_priv || | ||
583 | !(mad_snoop_priv->mad_snoop_flags & mad_snoop_flags)) | ||
584 | continue; | ||
585 | |||
586 | atomic_inc(&mad_snoop_priv->refcount); | ||
587 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | ||
588 | mad_snoop_priv->agent.snoop_handler(&mad_snoop_priv->agent, | ||
589 | send_wr, mad_send_wc); | ||
590 | if (atomic_dec_and_test(&mad_snoop_priv->refcount)) | ||
591 | wake_up(&mad_snoop_priv->wait); | ||
592 | spin_lock_irqsave(&qp_info->snoop_lock, flags); | ||
593 | } | ||
594 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | ||
595 | } | ||
596 | |||
597 | static void snoop_recv(struct ib_mad_qp_info *qp_info, | ||
598 | struct ib_mad_recv_wc *mad_recv_wc, | ||
599 | int mad_snoop_flags) | ||
600 | { | ||
601 | struct ib_mad_snoop_private *mad_snoop_priv; | ||
602 | unsigned long flags; | ||
603 | int i; | ||
604 | |||
605 | spin_lock_irqsave(&qp_info->snoop_lock, flags); | ||
606 | for (i = 0; i < qp_info->snoop_table_size; i++) { | ||
607 | mad_snoop_priv = qp_info->snoop_table[i]; | ||
608 | if (!mad_snoop_priv || | ||
609 | !(mad_snoop_priv->mad_snoop_flags & mad_snoop_flags)) | ||
610 | continue; | ||
611 | |||
612 | atomic_inc(&mad_snoop_priv->refcount); | ||
613 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | ||
614 | mad_snoop_priv->agent.recv_handler(&mad_snoop_priv->agent, | ||
615 | mad_recv_wc); | ||
616 | if (atomic_dec_and_test(&mad_snoop_priv->refcount)) | ||
617 | wake_up(&mad_snoop_priv->wait); | ||
618 | spin_lock_irqsave(&qp_info->snoop_lock, flags); | ||
619 | } | ||
620 | spin_unlock_irqrestore(&qp_info->snoop_lock, flags); | ||
621 | } | ||
622 | |||
623 | static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num, | ||
624 | struct ib_wc *wc) | ||
625 | { | ||
626 | memset(wc, 0, sizeof *wc); | ||
627 | wc->wr_id = wr_id; | ||
628 | wc->status = IB_WC_SUCCESS; | ||
629 | wc->opcode = IB_WC_RECV; | ||
630 | wc->pkey_index = pkey_index; | ||
631 | wc->byte_len = sizeof(struct ib_mad) + sizeof(struct ib_grh); | ||
632 | wc->src_qp = IB_QP0; | ||
633 | wc->qp_num = IB_QP0; | ||
634 | wc->slid = slid; | ||
635 | wc->sl = 0; | ||
636 | wc->dlid_path_bits = 0; | ||
637 | wc->port_num = port_num; | ||
638 | } | ||
639 | |||
640 | /* | ||
641 | * Return 0 if SMP is to be sent | ||
642 | * Return 1 if SMP was consumed locally (whether or not solicited) | ||
643 | * Return < 0 if error | ||
644 | */ | ||
645 | static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, | ||
646 | struct ib_smp *smp, | ||
647 | struct ib_send_wr *send_wr) | ||
648 | { | ||
649 | int ret, solicited; | ||
650 | unsigned long flags; | ||
651 | struct ib_mad_local_private *local; | ||
652 | struct ib_mad_private *mad_priv; | ||
653 | struct ib_mad_port_private *port_priv; | ||
654 | struct ib_mad_agent_private *recv_mad_agent = NULL; | ||
655 | struct ib_device *device = mad_agent_priv->agent.device; | ||
656 | u8 port_num = mad_agent_priv->agent.port_num; | ||
657 | struct ib_wc mad_wc; | ||
658 | |||
659 | if (!smi_handle_dr_smp_send(smp, device->node_type, port_num)) { | ||
660 | ret = -EINVAL; | ||
661 | printk(KERN_ERR PFX "Invalid directed route\n"); | ||
662 | goto out; | ||
663 | } | ||
664 | /* Check to post send on QP or process locally */ | ||
665 | ret = smi_check_local_dr_smp(smp, device, port_num); | ||
666 | if (!ret || !device->process_mad) | ||
667 | goto out; | ||
668 | |||
669 | local = kmalloc(sizeof *local, GFP_ATOMIC); | ||
670 | if (!local) { | ||
671 | ret = -ENOMEM; | ||
672 | printk(KERN_ERR PFX "No memory for ib_mad_local_private\n"); | ||
673 | goto out; | ||
674 | } | ||
675 | local->mad_priv = NULL; | ||
676 | local->recv_mad_agent = NULL; | ||
677 | mad_priv = kmem_cache_alloc(ib_mad_cache, GFP_ATOMIC); | ||
678 | if (!mad_priv) { | ||
679 | ret = -ENOMEM; | ||
680 | printk(KERN_ERR PFX "No memory for local response MAD\n"); | ||
681 | kfree(local); | ||
682 | goto out; | ||
683 | } | ||
684 | |||
685 | build_smp_wc(send_wr->wr_id, smp->dr_slid, send_wr->wr.ud.pkey_index, | ||
686 | send_wr->wr.ud.port_num, &mad_wc); | ||
687 | |||
688 | /* No GRH for DR SMP */ | ||
689 | ret = device->process_mad(device, 0, port_num, &mad_wc, NULL, | ||
690 | (struct ib_mad *)smp, | ||
691 | (struct ib_mad *)&mad_priv->mad); | ||
692 | switch (ret) | ||
693 | { | ||
694 | case IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY: | ||
695 | /* | ||
696 | * See if response is solicited and | ||
697 | * there is a recv handler | ||
698 | */ | ||
699 | if (solicited_mad(&mad_priv->mad.mad) && | ||
700 | mad_agent_priv->agent.recv_handler) { | ||
701 | local->mad_priv = mad_priv; | ||
702 | local->recv_mad_agent = mad_agent_priv; | ||
703 | /* | ||
704 | * Reference MAD agent until receive | ||
705 | * side of local completion handled | ||
706 | */ | ||
707 | atomic_inc(&mad_agent_priv->refcount); | ||
708 | } else | ||
709 | kmem_cache_free(ib_mad_cache, mad_priv); | ||
710 | break; | ||
711 | case IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED: | ||
712 | kmem_cache_free(ib_mad_cache, mad_priv); | ||
713 | break; | ||
714 | case IB_MAD_RESULT_SUCCESS: | ||
715 | /* Treat like an incoming receive MAD */ | ||
716 | solicited = solicited_mad(&mad_priv->mad.mad); | ||
717 | port_priv = ib_get_mad_port(mad_agent_priv->agent.device, | ||
718 | mad_agent_priv->agent.port_num); | ||
719 | if (port_priv) { | ||
720 | mad_priv->mad.mad.mad_hdr.tid = | ||
721 | ((struct ib_mad *)smp)->mad_hdr.tid; | ||
722 | recv_mad_agent = find_mad_agent(port_priv, | ||
723 | &mad_priv->mad.mad, | ||
724 | solicited); | ||
725 | } | ||
726 | if (!port_priv || !recv_mad_agent) { | ||
727 | kmem_cache_free(ib_mad_cache, mad_priv); | ||
728 | kfree(local); | ||
729 | ret = 0; | ||
730 | goto out; | ||
731 | } | ||
732 | local->mad_priv = mad_priv; | ||
733 | local->recv_mad_agent = recv_mad_agent; | ||
734 | break; | ||
735 | default: | ||
736 | kmem_cache_free(ib_mad_cache, mad_priv); | ||
737 | kfree(local); | ||
738 | ret = -EINVAL; | ||
739 | goto out; | ||
740 | } | ||
741 | |||
742 | local->send_wr = *send_wr; | ||
743 | local->send_wr.sg_list = local->sg_list; | ||
744 | memcpy(local->sg_list, send_wr->sg_list, | ||
745 | sizeof *send_wr->sg_list * send_wr->num_sge); | ||
746 | local->send_wr.next = NULL; | ||
747 | local->tid = send_wr->wr.ud.mad_hdr->tid; | ||
748 | local->wr_id = send_wr->wr_id; | ||
749 | /* Reference MAD agent until send side of local completion handled */ | ||
750 | atomic_inc(&mad_agent_priv->refcount); | ||
751 | /* Queue local completion to local list */ | ||
752 | spin_lock_irqsave(&mad_agent_priv->lock, flags); | ||
753 | list_add_tail(&local->completion_list, &mad_agent_priv->local_list); | ||
754 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
755 | queue_work(mad_agent_priv->qp_info->port_priv->wq, | ||
756 | &mad_agent_priv->local_work); | ||
757 | ret = 1; | ||
758 | out: | ||
759 | return ret; | ||
760 | } | ||
761 | |||
762 | static int ib_send_mad(struct ib_mad_agent_private *mad_agent_priv, | ||
763 | struct ib_mad_send_wr_private *mad_send_wr) | ||
764 | { | ||
765 | struct ib_mad_qp_info *qp_info; | ||
766 | struct ib_send_wr *bad_send_wr; | ||
767 | unsigned long flags; | ||
768 | int ret; | ||
769 | |||
770 | /* Replace user's WR ID with our own to find WR upon completion */ | ||
771 | qp_info = mad_agent_priv->qp_info; | ||
772 | mad_send_wr->wr_id = mad_send_wr->send_wr.wr_id; | ||
773 | mad_send_wr->send_wr.wr_id = (unsigned long)&mad_send_wr->mad_list; | ||
774 | mad_send_wr->mad_list.mad_queue = &qp_info->send_queue; | ||
775 | |||
776 | spin_lock_irqsave(&qp_info->send_queue.lock, flags); | ||
777 | if (qp_info->send_queue.count++ < qp_info->send_queue.max_active) { | ||
778 | list_add_tail(&mad_send_wr->mad_list.list, | ||
779 | &qp_info->send_queue.list); | ||
780 | spin_unlock_irqrestore(&qp_info->send_queue.lock, flags); | ||
781 | ret = ib_post_send(mad_agent_priv->agent.qp, | ||
782 | &mad_send_wr->send_wr, &bad_send_wr); | ||
783 | if (ret) { | ||
784 | printk(KERN_ERR PFX "ib_post_send failed: %d\n", ret); | ||
785 | dequeue_mad(&mad_send_wr->mad_list); | ||
786 | } | ||
787 | } else { | ||
788 | list_add_tail(&mad_send_wr->mad_list.list, | ||
789 | &qp_info->overflow_list); | ||
790 | spin_unlock_irqrestore(&qp_info->send_queue.lock, flags); | ||
791 | ret = 0; | ||
792 | } | ||
793 | return ret; | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * ib_post_send_mad - Posts MAD(s) to the send queue of the QP associated | ||
798 | * with the registered client | ||
799 | */ | ||
800 | int ib_post_send_mad(struct ib_mad_agent *mad_agent, | ||
801 | struct ib_send_wr *send_wr, | ||
802 | struct ib_send_wr **bad_send_wr) | ||
803 | { | ||
804 | int ret = -EINVAL; | ||
805 | struct ib_mad_agent_private *mad_agent_priv; | ||
806 | |||
807 | /* Validate supplied parameters */ | ||
808 | if (!bad_send_wr) | ||
809 | goto error1; | ||
810 | |||
811 | if (!mad_agent || !send_wr) | ||
812 | goto error2; | ||
813 | |||
814 | if (!mad_agent->send_handler) | ||
815 | goto error2; | ||
816 | |||
817 | mad_agent_priv = container_of(mad_agent, | ||
818 | struct ib_mad_agent_private, | ||
819 | agent); | ||
820 | |||
821 | /* Walk list of send WRs and post each on send list */ | ||
822 | while (send_wr) { | ||
823 | unsigned long flags; | ||
824 | struct ib_send_wr *next_send_wr; | ||
825 | struct ib_mad_send_wr_private *mad_send_wr; | ||
826 | struct ib_smp *smp; | ||
827 | |||
828 | /* Validate more parameters */ | ||
829 | if (send_wr->num_sge > IB_MAD_SEND_REQ_MAX_SG) | ||
830 | goto error2; | ||
831 | |||
832 | if (send_wr->wr.ud.timeout_ms && !mad_agent->recv_handler) | ||
833 | goto error2; | ||
834 | |||
835 | if (!send_wr->wr.ud.mad_hdr) { | ||
836 | printk(KERN_ERR PFX "MAD header must be supplied " | ||
837 | "in WR %p\n", send_wr); | ||
838 | goto error2; | ||
839 | } | ||
840 | |||
841 | /* | ||
842 | * Save pointer to next work request to post in case the | ||
843 | * current one completes, and the user modifies the work | ||
844 | * request associated with the completion | ||
845 | */ | ||
846 | next_send_wr = (struct ib_send_wr *)send_wr->next; | ||
847 | |||
848 | smp = (struct ib_smp *)send_wr->wr.ud.mad_hdr; | ||
849 | if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { | ||
850 | ret = handle_outgoing_dr_smp(mad_agent_priv, smp, | ||
851 | send_wr); | ||
852 | if (ret < 0) /* error */ | ||
853 | goto error2; | ||
854 | else if (ret == 1) /* locally consumed */ | ||
855 | goto next; | ||
856 | } | ||
857 | |||
858 | /* Allocate MAD send WR tracking structure */ | ||
859 | mad_send_wr = kmalloc(sizeof *mad_send_wr, GFP_ATOMIC); | ||
860 | if (!mad_send_wr) { | ||
861 | printk(KERN_ERR PFX "No memory for " | ||
862 | "ib_mad_send_wr_private\n"); | ||
863 | ret = -ENOMEM; | ||
864 | goto error2; | ||
865 | } | ||
866 | |||
867 | mad_send_wr->send_wr = *send_wr; | ||
868 | mad_send_wr->send_wr.sg_list = mad_send_wr->sg_list; | ||
869 | memcpy(mad_send_wr->sg_list, send_wr->sg_list, | ||
870 | sizeof *send_wr->sg_list * send_wr->num_sge); | ||
871 | mad_send_wr->send_wr.next = NULL; | ||
872 | mad_send_wr->tid = send_wr->wr.ud.mad_hdr->tid; | ||
873 | mad_send_wr->agent = mad_agent; | ||
874 | /* Timeout will be updated after send completes */ | ||
875 | mad_send_wr->timeout = msecs_to_jiffies(send_wr->wr. | ||
876 | ud.timeout_ms); | ||
877 | mad_send_wr->retry = 0; | ||
878 | /* One reference for each work request to QP + response */ | ||
879 | mad_send_wr->refcount = 1 + (mad_send_wr->timeout > 0); | ||
880 | mad_send_wr->status = IB_WC_SUCCESS; | ||
881 | |||
882 | /* Reference MAD agent until send completes */ | ||
883 | atomic_inc(&mad_agent_priv->refcount); | ||
884 | spin_lock_irqsave(&mad_agent_priv->lock, flags); | ||
885 | list_add_tail(&mad_send_wr->agent_list, | ||
886 | &mad_agent_priv->send_list); | ||
887 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
888 | |||
889 | ret = ib_send_mad(mad_agent_priv, mad_send_wr); | ||
890 | if (ret) { | ||
891 | /* Fail send request */ | ||
892 | spin_lock_irqsave(&mad_agent_priv->lock, flags); | ||
893 | list_del(&mad_send_wr->agent_list); | ||
894 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
895 | atomic_dec(&mad_agent_priv->refcount); | ||
896 | goto error2; | ||
897 | } | ||
898 | next: | ||
899 | send_wr = next_send_wr; | ||
900 | } | ||
901 | return 0; | ||
902 | |||
903 | error2: | ||
904 | *bad_send_wr = send_wr; | ||
905 | error1: | ||
906 | return ret; | ||
907 | } | ||
908 | EXPORT_SYMBOL(ib_post_send_mad); | ||
909 | |||
910 | /* | ||
911 | * ib_free_recv_mad - Returns data buffers used to receive | ||
912 | * a MAD to the access layer | ||
913 | */ | ||
914 | void ib_free_recv_mad(struct ib_mad_recv_wc *mad_recv_wc) | ||
915 | { | ||
916 | struct ib_mad_recv_buf *entry; | ||
917 | struct ib_mad_private_header *mad_priv_hdr; | ||
918 | struct ib_mad_private *priv; | ||
919 | |||
920 | mad_priv_hdr = container_of(mad_recv_wc, | ||
921 | struct ib_mad_private_header, | ||
922 | recv_wc); | ||
923 | priv = container_of(mad_priv_hdr, struct ib_mad_private, header); | ||
924 | |||
925 | /* | ||
926 | * Walk receive buffer list associated with this WC | ||
927 | * No need to remove them from list of receive buffers | ||
928 | */ | ||
929 | list_for_each_entry(entry, &mad_recv_wc->recv_buf.list, list) { | ||
930 | /* Free previous receive buffer */ | ||
931 | kmem_cache_free(ib_mad_cache, priv); | ||
932 | mad_priv_hdr = container_of(mad_recv_wc, | ||
933 | struct ib_mad_private_header, | ||
934 | recv_wc); | ||
935 | priv = container_of(mad_priv_hdr, struct ib_mad_private, | ||
936 | header); | ||
937 | } | ||
938 | |||
939 | /* Free last buffer */ | ||
940 | kmem_cache_free(ib_mad_cache, priv); | ||
941 | } | ||
942 | EXPORT_SYMBOL(ib_free_recv_mad); | ||
943 | |||
944 | void ib_coalesce_recv_mad(struct ib_mad_recv_wc *mad_recv_wc, | ||
945 | void *buf) | ||
946 | { | ||
947 | printk(KERN_ERR PFX "ib_coalesce_recv_mad() not implemented yet\n"); | ||
948 | } | ||
949 | EXPORT_SYMBOL(ib_coalesce_recv_mad); | ||
950 | |||
951 | struct ib_mad_agent *ib_redirect_mad_qp(struct ib_qp *qp, | ||
952 | u8 rmpp_version, | ||
953 | ib_mad_send_handler send_handler, | ||
954 | ib_mad_recv_handler recv_handler, | ||
955 | void *context) | ||
956 | { | ||
957 | return ERR_PTR(-EINVAL); /* XXX: for now */ | ||
958 | } | ||
959 | EXPORT_SYMBOL(ib_redirect_mad_qp); | ||
960 | |||
961 | int ib_process_mad_wc(struct ib_mad_agent *mad_agent, | ||
962 | struct ib_wc *wc) | ||
963 | { | ||
964 | printk(KERN_ERR PFX "ib_process_mad_wc() not implemented yet\n"); | ||
965 | return 0; | ||
966 | } | ||
967 | EXPORT_SYMBOL(ib_process_mad_wc); | ||
968 | |||
969 | static int method_in_use(struct ib_mad_mgmt_method_table **method, | ||
970 | struct ib_mad_reg_req *mad_reg_req) | ||
971 | { | ||
972 | int i; | ||
973 | |||
974 | for (i = find_first_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS); | ||
975 | i < IB_MGMT_MAX_METHODS; | ||
976 | i = find_next_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS, | ||
977 | 1+i)) { | ||
978 | if ((*method)->agent[i]) { | ||
979 | printk(KERN_ERR PFX "Method %d already in use\n", i); | ||
980 | return -EINVAL; | ||
981 | } | ||
982 | } | ||
983 | return 0; | ||
984 | } | ||
985 | |||
986 | static int allocate_method_table(struct ib_mad_mgmt_method_table **method) | ||
987 | { | ||
988 | /* Allocate management method table */ | ||
989 | *method = kmalloc(sizeof **method, GFP_ATOMIC); | ||
990 | if (!*method) { | ||
991 | printk(KERN_ERR PFX "No memory for " | ||
992 | "ib_mad_mgmt_method_table\n"); | ||
993 | return -ENOMEM; | ||
994 | } | ||
995 | /* Clear management method table */ | ||
996 | memset(*method, 0, sizeof **method); | ||
997 | |||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | /* | ||
1002 | * Check to see if there are any methods still in use | ||
1003 | */ | ||
1004 | static int check_method_table(struct ib_mad_mgmt_method_table *method) | ||
1005 | { | ||
1006 | int i; | ||
1007 | |||
1008 | for (i = 0; i < IB_MGMT_MAX_METHODS; i++) | ||
1009 | if (method->agent[i]) | ||
1010 | return 1; | ||
1011 | return 0; | ||
1012 | } | ||
1013 | |||
1014 | /* | ||
1015 | * Check to see if there are any method tables for this class still in use | ||
1016 | */ | ||
1017 | static int check_class_table(struct ib_mad_mgmt_class_table *class) | ||
1018 | { | ||
1019 | int i; | ||
1020 | |||
1021 | for (i = 0; i < MAX_MGMT_CLASS; i++) | ||
1022 | if (class->method_table[i]) | ||
1023 | return 1; | ||
1024 | return 0; | ||
1025 | } | ||
1026 | |||
1027 | static int check_vendor_class(struct ib_mad_mgmt_vendor_class *vendor_class) | ||
1028 | { | ||
1029 | int i; | ||
1030 | |||
1031 | for (i = 0; i < MAX_MGMT_OUI; i++) | ||
1032 | if (vendor_class->method_table[i]) | ||
1033 | return 1; | ||
1034 | return 0; | ||
1035 | } | ||
1036 | |||
1037 | static int find_vendor_oui(struct ib_mad_mgmt_vendor_class *vendor_class, | ||
1038 | char *oui) | ||
1039 | { | ||
1040 | int i; | ||
1041 | |||
1042 | for (i = 0; i < MAX_MGMT_OUI; i++) | ||
1043 | /* Is there matching OUI for this vendor class ? */ | ||
1044 | if (!memcmp(vendor_class->oui[i], oui, 3)) | ||
1045 | return i; | ||
1046 | |||
1047 | return -1; | ||
1048 | } | ||
1049 | |||
1050 | static int check_vendor_table(struct ib_mad_mgmt_vendor_class_table *vendor) | ||
1051 | { | ||
1052 | int i; | ||
1053 | |||
1054 | for (i = 0; i < MAX_MGMT_VENDOR_RANGE2; i++) | ||
1055 | if (vendor->vendor_class[i]) | ||
1056 | return 1; | ||
1057 | |||
1058 | return 0; | ||
1059 | } | ||
1060 | |||
1061 | static void remove_methods_mad_agent(struct ib_mad_mgmt_method_table *method, | ||
1062 | struct ib_mad_agent_private *agent) | ||
1063 | { | ||
1064 | int i; | ||
1065 | |||
1066 | /* Remove any methods for this mad agent */ | ||
1067 | for (i = 0; i < IB_MGMT_MAX_METHODS; i++) { | ||
1068 | if (method->agent[i] == agent) { | ||
1069 | method->agent[i] = NULL; | ||
1070 | } | ||
1071 | } | ||
1072 | } | ||
1073 | |||
1074 | static int add_nonoui_reg_req(struct ib_mad_reg_req *mad_reg_req, | ||
1075 | struct ib_mad_agent_private *agent_priv, | ||
1076 | u8 mgmt_class) | ||
1077 | { | ||
1078 | struct ib_mad_port_private *port_priv; | ||
1079 | struct ib_mad_mgmt_class_table **class; | ||
1080 | struct ib_mad_mgmt_method_table **method; | ||
1081 | int i, ret; | ||
1082 | |||
1083 | port_priv = agent_priv->qp_info->port_priv; | ||
1084 | class = &port_priv->version[mad_reg_req->mgmt_class_version].class; | ||
1085 | if (!*class) { | ||
1086 | /* Allocate management class table for "new" class version */ | ||
1087 | *class = kmalloc(sizeof **class, GFP_ATOMIC); | ||
1088 | if (!*class) { | ||
1089 | printk(KERN_ERR PFX "No memory for " | ||
1090 | "ib_mad_mgmt_class_table\n"); | ||
1091 | ret = -ENOMEM; | ||
1092 | goto error1; | ||
1093 | } | ||
1094 | /* Clear management class table */ | ||
1095 | memset(*class, 0, sizeof(**class)); | ||
1096 | /* Allocate method table for this management class */ | ||
1097 | method = &(*class)->method_table[mgmt_class]; | ||
1098 | if ((ret = allocate_method_table(method))) | ||
1099 | goto error2; | ||
1100 | } else { | ||
1101 | method = &(*class)->method_table[mgmt_class]; | ||
1102 | if (!*method) { | ||
1103 | /* Allocate method table for this management class */ | ||
1104 | if ((ret = allocate_method_table(method))) | ||
1105 | goto error1; | ||
1106 | } | ||
1107 | } | ||
1108 | |||
1109 | /* Now, make sure methods are not already in use */ | ||
1110 | if (method_in_use(method, mad_reg_req)) | ||
1111 | goto error3; | ||
1112 | |||
1113 | /* Finally, add in methods being registered */ | ||
1114 | for (i = find_first_bit(mad_reg_req->method_mask, | ||
1115 | IB_MGMT_MAX_METHODS); | ||
1116 | i < IB_MGMT_MAX_METHODS; | ||
1117 | i = find_next_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS, | ||
1118 | 1+i)) { | ||
1119 | (*method)->agent[i] = agent_priv; | ||
1120 | } | ||
1121 | return 0; | ||
1122 | |||
1123 | error3: | ||
1124 | /* Remove any methods for this mad agent */ | ||
1125 | remove_methods_mad_agent(*method, agent_priv); | ||
1126 | /* Now, check to see if there are any methods in use */ | ||
1127 | if (!check_method_table(*method)) { | ||
1128 | /* If not, release management method table */ | ||
1129 | kfree(*method); | ||
1130 | *method = NULL; | ||
1131 | } | ||
1132 | ret = -EINVAL; | ||
1133 | goto error1; | ||
1134 | error2: | ||
1135 | kfree(*class); | ||
1136 | *class = NULL; | ||
1137 | error1: | ||
1138 | return ret; | ||
1139 | } | ||
1140 | |||
1141 | static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req, | ||
1142 | struct ib_mad_agent_private *agent_priv) | ||
1143 | { | ||
1144 | struct ib_mad_port_private *port_priv; | ||
1145 | struct ib_mad_mgmt_vendor_class_table **vendor_table; | ||
1146 | struct ib_mad_mgmt_vendor_class_table *vendor = NULL; | ||
1147 | struct ib_mad_mgmt_vendor_class *vendor_class = NULL; | ||
1148 | struct ib_mad_mgmt_method_table **method; | ||
1149 | int i, ret = -ENOMEM; | ||
1150 | u8 vclass; | ||
1151 | |||
1152 | /* "New" vendor (with OUI) class */ | ||
1153 | vclass = vendor_class_index(mad_reg_req->mgmt_class); | ||
1154 | port_priv = agent_priv->qp_info->port_priv; | ||
1155 | vendor_table = &port_priv->version[ | ||
1156 | mad_reg_req->mgmt_class_version].vendor; | ||
1157 | if (!*vendor_table) { | ||
1158 | /* Allocate mgmt vendor class table for "new" class version */ | ||
1159 | vendor = kmalloc(sizeof *vendor, GFP_ATOMIC); | ||
1160 | if (!vendor) { | ||
1161 | printk(KERN_ERR PFX "No memory for " | ||
1162 | "ib_mad_mgmt_vendor_class_table\n"); | ||
1163 | goto error1; | ||
1164 | } | ||
1165 | /* Clear management vendor class table */ | ||
1166 | memset(vendor, 0, sizeof(*vendor)); | ||
1167 | *vendor_table = vendor; | ||
1168 | } | ||
1169 | if (!(*vendor_table)->vendor_class[vclass]) { | ||
1170 | /* Allocate table for this management vendor class */ | ||
1171 | vendor_class = kmalloc(sizeof *vendor_class, GFP_ATOMIC); | ||
1172 | if (!vendor_class) { | ||
1173 | printk(KERN_ERR PFX "No memory for " | ||
1174 | "ib_mad_mgmt_vendor_class\n"); | ||
1175 | goto error2; | ||
1176 | } | ||
1177 | memset(vendor_class, 0, sizeof(*vendor_class)); | ||
1178 | (*vendor_table)->vendor_class[vclass] = vendor_class; | ||
1179 | } | ||
1180 | for (i = 0; i < MAX_MGMT_OUI; i++) { | ||
1181 | /* Is there matching OUI for this vendor class ? */ | ||
1182 | if (!memcmp((*vendor_table)->vendor_class[vclass]->oui[i], | ||
1183 | mad_reg_req->oui, 3)) { | ||
1184 | method = &(*vendor_table)->vendor_class[ | ||
1185 | vclass]->method_table[i]; | ||
1186 | BUG_ON(!*method); | ||
1187 | goto check_in_use; | ||
1188 | } | ||
1189 | } | ||
1190 | for (i = 0; i < MAX_MGMT_OUI; i++) { | ||
1191 | /* OUI slot available ? */ | ||
1192 | if (!is_vendor_oui((*vendor_table)->vendor_class[ | ||
1193 | vclass]->oui[i])) { | ||
1194 | method = &(*vendor_table)->vendor_class[ | ||
1195 | vclass]->method_table[i]; | ||
1196 | BUG_ON(*method); | ||
1197 | /* Allocate method table for this OUI */ | ||
1198 | if ((ret = allocate_method_table(method))) | ||
1199 | goto error3; | ||
1200 | memcpy((*vendor_table)->vendor_class[vclass]->oui[i], | ||
1201 | mad_reg_req->oui, 3); | ||
1202 | goto check_in_use; | ||
1203 | } | ||
1204 | } | ||
1205 | printk(KERN_ERR PFX "All OUI slots in use\n"); | ||
1206 | goto error3; | ||
1207 | |||
1208 | check_in_use: | ||
1209 | /* Now, make sure methods are not already in use */ | ||
1210 | if (method_in_use(method, mad_reg_req)) | ||
1211 | goto error4; | ||
1212 | |||
1213 | /* Finally, add in methods being registered */ | ||
1214 | for (i = find_first_bit(mad_reg_req->method_mask, | ||
1215 | IB_MGMT_MAX_METHODS); | ||
1216 | i < IB_MGMT_MAX_METHODS; | ||
1217 | i = find_next_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS, | ||
1218 | 1+i)) { | ||
1219 | (*method)->agent[i] = agent_priv; | ||
1220 | } | ||
1221 | return 0; | ||
1222 | |||
1223 | error4: | ||
1224 | /* Remove any methods for this mad agent */ | ||
1225 | remove_methods_mad_agent(*method, agent_priv); | ||
1226 | /* Now, check to see if there are any methods in use */ | ||
1227 | if (!check_method_table(*method)) { | ||
1228 | /* If not, release management method table */ | ||
1229 | kfree(*method); | ||
1230 | *method = NULL; | ||
1231 | } | ||
1232 | ret = -EINVAL; | ||
1233 | error3: | ||
1234 | if (vendor_class) { | ||
1235 | (*vendor_table)->vendor_class[vclass] = NULL; | ||
1236 | kfree(vendor_class); | ||
1237 | } | ||
1238 | error2: | ||
1239 | if (vendor) { | ||
1240 | *vendor_table = NULL; | ||
1241 | kfree(vendor); | ||
1242 | } | ||
1243 | error1: | ||
1244 | return ret; | ||
1245 | } | ||
1246 | |||
1247 | static void remove_mad_reg_req(struct ib_mad_agent_private *agent_priv) | ||
1248 | { | ||
1249 | struct ib_mad_port_private *port_priv; | ||
1250 | struct ib_mad_mgmt_class_table *class; | ||
1251 | struct ib_mad_mgmt_method_table *method; | ||
1252 | struct ib_mad_mgmt_vendor_class_table *vendor; | ||
1253 | struct ib_mad_mgmt_vendor_class *vendor_class; | ||
1254 | int index; | ||
1255 | u8 mgmt_class; | ||
1256 | |||
1257 | /* | ||
1258 | * Was MAD registration request supplied | ||
1259 | * with original registration ? | ||
1260 | */ | ||
1261 | if (!agent_priv->reg_req) { | ||
1262 | goto out; | ||
1263 | } | ||
1264 | |||
1265 | port_priv = agent_priv->qp_info->port_priv; | ||
1266 | mgmt_class = convert_mgmt_class(agent_priv->reg_req->mgmt_class); | ||
1267 | class = port_priv->version[ | ||
1268 | agent_priv->reg_req->mgmt_class_version].class; | ||
1269 | if (!class) | ||
1270 | goto vendor_check; | ||
1271 | |||
1272 | method = class->method_table[mgmt_class]; | ||
1273 | if (method) { | ||
1274 | /* Remove any methods for this mad agent */ | ||
1275 | remove_methods_mad_agent(method, agent_priv); | ||
1276 | /* Now, check to see if there are any methods still in use */ | ||
1277 | if (!check_method_table(method)) { | ||
1278 | /* If not, release management method table */ | ||
1279 | kfree(method); | ||
1280 | class->method_table[mgmt_class] = NULL; | ||
1281 | /* Any management classes left ? */ | ||
1282 | if (!check_class_table(class)) { | ||
1283 | /* If not, release management class table */ | ||
1284 | kfree(class); | ||
1285 | port_priv->version[ | ||
1286 | agent_priv->reg_req-> | ||
1287 | mgmt_class_version].class = NULL; | ||
1288 | } | ||
1289 | } | ||
1290 | } | ||
1291 | |||
1292 | vendor_check: | ||
1293 | if (!is_vendor_class(mgmt_class)) | ||
1294 | goto out; | ||
1295 | |||
1296 | /* normalize mgmt_class to vendor range 2 */ | ||
1297 | mgmt_class = vendor_class_index(agent_priv->reg_req->mgmt_class); | ||
1298 | vendor = port_priv->version[ | ||
1299 | agent_priv->reg_req->mgmt_class_version].vendor; | ||
1300 | |||
1301 | if (!vendor) | ||
1302 | goto out; | ||
1303 | |||
1304 | vendor_class = vendor->vendor_class[mgmt_class]; | ||
1305 | if (vendor_class) { | ||
1306 | index = find_vendor_oui(vendor_class, agent_priv->reg_req->oui); | ||
1307 | if (index < 0) | ||
1308 | goto out; | ||
1309 | method = vendor_class->method_table[index]; | ||
1310 | if (method) { | ||
1311 | /* Remove any methods for this mad agent */ | ||
1312 | remove_methods_mad_agent(method, agent_priv); | ||
1313 | /* | ||
1314 | * Now, check to see if there are | ||
1315 | * any methods still in use | ||
1316 | */ | ||
1317 | if (!check_method_table(method)) { | ||
1318 | /* If not, release management method table */ | ||
1319 | kfree(method); | ||
1320 | vendor_class->method_table[index] = NULL; | ||
1321 | memset(vendor_class->oui[index], 0, 3); | ||
1322 | /* Any OUIs left ? */ | ||
1323 | if (!check_vendor_class(vendor_class)) { | ||
1324 | /* If not, release vendor class table */ | ||
1325 | kfree(vendor_class); | ||
1326 | vendor->vendor_class[mgmt_class] = NULL; | ||
1327 | /* Any other vendor classes left ? */ | ||
1328 | if (!check_vendor_table(vendor)) { | ||
1329 | kfree(vendor); | ||
1330 | port_priv->version[ | ||
1331 | agent_priv->reg_req-> | ||
1332 | mgmt_class_version]. | ||
1333 | vendor = NULL; | ||
1334 | } | ||
1335 | } | ||
1336 | } | ||
1337 | } | ||
1338 | } | ||
1339 | |||
1340 | out: | ||
1341 | return; | ||
1342 | } | ||
1343 | |||
1344 | static int response_mad(struct ib_mad *mad) | ||
1345 | { | ||
1346 | /* Trap represses are responses although response bit is reset */ | ||
1347 | return ((mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) || | ||
1348 | (mad->mad_hdr.method & IB_MGMT_METHOD_RESP)); | ||
1349 | } | ||
1350 | |||
1351 | static int solicited_mad(struct ib_mad *mad) | ||
1352 | { | ||
1353 | /* CM MADs are never solicited */ | ||
1354 | if (mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_CM) { | ||
1355 | return 0; | ||
1356 | } | ||
1357 | |||
1358 | /* XXX: Determine whether MAD is using RMPP */ | ||
1359 | |||
1360 | /* Not using RMPP */ | ||
1361 | /* Is this MAD a response to a previous MAD ? */ | ||
1362 | return response_mad(mad); | ||
1363 | } | ||
1364 | |||
1365 | static struct ib_mad_agent_private * | ||
1366 | find_mad_agent(struct ib_mad_port_private *port_priv, | ||
1367 | struct ib_mad *mad, | ||
1368 | int solicited) | ||
1369 | { | ||
1370 | struct ib_mad_agent_private *mad_agent = NULL; | ||
1371 | unsigned long flags; | ||
1372 | |||
1373 | spin_lock_irqsave(&port_priv->reg_lock, flags); | ||
1374 | |||
1375 | /* | ||
1376 | * Whether MAD was solicited determines type of routing to | ||
1377 | * MAD client. | ||
1378 | */ | ||
1379 | if (solicited) { | ||
1380 | u32 hi_tid; | ||
1381 | struct ib_mad_agent_private *entry; | ||
1382 | |||
1383 | /* | ||
1384 | * Routing is based on high 32 bits of transaction ID | ||
1385 | * of MAD. | ||
1386 | */ | ||
1387 | hi_tid = be64_to_cpu(mad->mad_hdr.tid) >> 32; | ||
1388 | list_for_each_entry(entry, &port_priv->agent_list, | ||
1389 | agent_list) { | ||
1390 | if (entry->agent.hi_tid == hi_tid) { | ||
1391 | mad_agent = entry; | ||
1392 | break; | ||
1393 | } | ||
1394 | } | ||
1395 | } else { | ||
1396 | struct ib_mad_mgmt_class_table *class; | ||
1397 | struct ib_mad_mgmt_method_table *method; | ||
1398 | struct ib_mad_mgmt_vendor_class_table *vendor; | ||
1399 | struct ib_mad_mgmt_vendor_class *vendor_class; | ||
1400 | struct ib_vendor_mad *vendor_mad; | ||
1401 | int index; | ||
1402 | |||
1403 | /* | ||
1404 | * Routing is based on version, class, and method | ||
1405 | * For "newer" vendor MADs, also based on OUI | ||
1406 | */ | ||
1407 | if (mad->mad_hdr.class_version >= MAX_MGMT_VERSION) | ||
1408 | goto out; | ||
1409 | if (!is_vendor_class(mad->mad_hdr.mgmt_class)) { | ||
1410 | class = port_priv->version[ | ||
1411 | mad->mad_hdr.class_version].class; | ||
1412 | if (!class) | ||
1413 | goto out; | ||
1414 | method = class->method_table[convert_mgmt_class( | ||
1415 | mad->mad_hdr.mgmt_class)]; | ||
1416 | if (method) | ||
1417 | mad_agent = method->agent[mad->mad_hdr.method & | ||
1418 | ~IB_MGMT_METHOD_RESP]; | ||
1419 | } else { | ||
1420 | vendor = port_priv->version[ | ||
1421 | mad->mad_hdr.class_version].vendor; | ||
1422 | if (!vendor) | ||
1423 | goto out; | ||
1424 | vendor_class = vendor->vendor_class[vendor_class_index( | ||
1425 | mad->mad_hdr.mgmt_class)]; | ||
1426 | if (!vendor_class) | ||
1427 | goto out; | ||
1428 | /* Find matching OUI */ | ||
1429 | vendor_mad = (struct ib_vendor_mad *)mad; | ||
1430 | index = find_vendor_oui(vendor_class, vendor_mad->oui); | ||
1431 | if (index == -1) | ||
1432 | goto out; | ||
1433 | method = vendor_class->method_table[index]; | ||
1434 | if (method) { | ||
1435 | mad_agent = method->agent[mad->mad_hdr.method & | ||
1436 | ~IB_MGMT_METHOD_RESP]; | ||
1437 | } | ||
1438 | } | ||
1439 | } | ||
1440 | |||
1441 | if (mad_agent) { | ||
1442 | if (mad_agent->agent.recv_handler) | ||
1443 | atomic_inc(&mad_agent->refcount); | ||
1444 | else { | ||
1445 | printk(KERN_NOTICE PFX "No receive handler for client " | ||
1446 | "%p on port %d\n", | ||
1447 | &mad_agent->agent, port_priv->port_num); | ||
1448 | mad_agent = NULL; | ||
1449 | } | ||
1450 | } | ||
1451 | out: | ||
1452 | spin_unlock_irqrestore(&port_priv->reg_lock, flags); | ||
1453 | |||
1454 | return mad_agent; | ||
1455 | } | ||
1456 | |||
1457 | static int validate_mad(struct ib_mad *mad, u32 qp_num) | ||
1458 | { | ||
1459 | int valid = 0; | ||
1460 | |||
1461 | /* Make sure MAD base version is understood */ | ||
1462 | if (mad->mad_hdr.base_version != IB_MGMT_BASE_VERSION) { | ||
1463 | printk(KERN_ERR PFX "MAD received with unsupported base " | ||
1464 | "version %d\n", mad->mad_hdr.base_version); | ||
1465 | goto out; | ||
1466 | } | ||
1467 | |||
1468 | /* Filter SMI packets sent to other than QP0 */ | ||
1469 | if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED) || | ||
1470 | (mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)) { | ||
1471 | if (qp_num == 0) | ||
1472 | valid = 1; | ||
1473 | } else { | ||
1474 | /* Filter GSI packets sent to QP0 */ | ||
1475 | if (qp_num != 0) | ||
1476 | valid = 1; | ||
1477 | } | ||
1478 | |||
1479 | out: | ||
1480 | return valid; | ||
1481 | } | ||
1482 | |||
1483 | /* | ||
1484 | * Return start of fully reassembled MAD, or NULL, if MAD isn't assembled yet | ||
1485 | */ | ||
1486 | static struct ib_mad_private * | ||
1487 | reassemble_recv(struct ib_mad_agent_private *mad_agent_priv, | ||
1488 | struct ib_mad_private *recv) | ||
1489 | { | ||
1490 | /* Until we have RMPP, all receives are reassembled!... */ | ||
1491 | INIT_LIST_HEAD(&recv->header.recv_wc.recv_buf.list); | ||
1492 | return recv; | ||
1493 | } | ||
1494 | |||
1495 | static struct ib_mad_send_wr_private* | ||
1496 | find_send_req(struct ib_mad_agent_private *mad_agent_priv, | ||
1497 | u64 tid) | ||
1498 | { | ||
1499 | struct ib_mad_send_wr_private *mad_send_wr; | ||
1500 | |||
1501 | list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list, | ||
1502 | agent_list) { | ||
1503 | if (mad_send_wr->tid == tid) | ||
1504 | return mad_send_wr; | ||
1505 | } | ||
1506 | |||
1507 | /* | ||
1508 | * It's possible to receive the response before we've | ||
1509 | * been notified that the send has completed | ||
1510 | */ | ||
1511 | list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list, | ||
1512 | agent_list) { | ||
1513 | if (mad_send_wr->tid == tid && mad_send_wr->timeout) { | ||
1514 | /* Verify request has not been canceled */ | ||
1515 | return (mad_send_wr->status == IB_WC_SUCCESS) ? | ||
1516 | mad_send_wr : NULL; | ||
1517 | } | ||
1518 | } | ||
1519 | return NULL; | ||
1520 | } | ||
1521 | |||
1522 | static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, | ||
1523 | struct ib_mad_private *recv, | ||
1524 | int solicited) | ||
1525 | { | ||
1526 | struct ib_mad_send_wr_private *mad_send_wr; | ||
1527 | struct ib_mad_send_wc mad_send_wc; | ||
1528 | unsigned long flags; | ||
1529 | |||
1530 | /* Fully reassemble receive before processing */ | ||
1531 | recv = reassemble_recv(mad_agent_priv, recv); | ||
1532 | if (!recv) { | ||
1533 | if (atomic_dec_and_test(&mad_agent_priv->refcount)) | ||
1534 | wake_up(&mad_agent_priv->wait); | ||
1535 | return; | ||
1536 | } | ||
1537 | |||
1538 | /* Complete corresponding request */ | ||
1539 | if (solicited) { | ||
1540 | spin_lock_irqsave(&mad_agent_priv->lock, flags); | ||
1541 | mad_send_wr = find_send_req(mad_agent_priv, | ||
1542 | recv->mad.mad.mad_hdr.tid); | ||
1543 | if (!mad_send_wr) { | ||
1544 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
1545 | ib_free_recv_mad(&recv->header.recv_wc); | ||
1546 | if (atomic_dec_and_test(&mad_agent_priv->refcount)) | ||
1547 | wake_up(&mad_agent_priv->wait); | ||
1548 | return; | ||
1549 | } | ||
1550 | /* Timeout = 0 means that we won't wait for a response */ | ||
1551 | mad_send_wr->timeout = 0; | ||
1552 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
1553 | |||
1554 | /* Defined behavior is to complete response before request */ | ||
1555 | recv->header.recv_wc.wc->wr_id = mad_send_wr->wr_id; | ||
1556 | mad_agent_priv->agent.recv_handler( | ||
1557 | &mad_agent_priv->agent, | ||
1558 | &recv->header.recv_wc); | ||
1559 | atomic_dec(&mad_agent_priv->refcount); | ||
1560 | |||
1561 | mad_send_wc.status = IB_WC_SUCCESS; | ||
1562 | mad_send_wc.vendor_err = 0; | ||
1563 | mad_send_wc.wr_id = mad_send_wr->wr_id; | ||
1564 | ib_mad_complete_send_wr(mad_send_wr, &mad_send_wc); | ||
1565 | } else { | ||
1566 | mad_agent_priv->agent.recv_handler( | ||
1567 | &mad_agent_priv->agent, | ||
1568 | &recv->header.recv_wc); | ||
1569 | if (atomic_dec_and_test(&mad_agent_priv->refcount)) | ||
1570 | wake_up(&mad_agent_priv->wait); | ||
1571 | } | ||
1572 | } | ||
1573 | |||
1574 | static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv, | ||
1575 | struct ib_wc *wc) | ||
1576 | { | ||
1577 | struct ib_mad_qp_info *qp_info; | ||
1578 | struct ib_mad_private_header *mad_priv_hdr; | ||
1579 | struct ib_mad_private *recv, *response; | ||
1580 | struct ib_mad_list_head *mad_list; | ||
1581 | struct ib_mad_agent_private *mad_agent; | ||
1582 | int solicited; | ||
1583 | |||
1584 | response = kmem_cache_alloc(ib_mad_cache, GFP_KERNEL); | ||
1585 | if (!response) | ||
1586 | printk(KERN_ERR PFX "ib_mad_recv_done_handler no memory " | ||
1587 | "for response buffer\n"); | ||
1588 | |||
1589 | mad_list = (struct ib_mad_list_head *)(unsigned long)wc->wr_id; | ||
1590 | qp_info = mad_list->mad_queue->qp_info; | ||
1591 | dequeue_mad(mad_list); | ||
1592 | |||
1593 | mad_priv_hdr = container_of(mad_list, struct ib_mad_private_header, | ||
1594 | mad_list); | ||
1595 | recv = container_of(mad_priv_hdr, struct ib_mad_private, header); | ||
1596 | dma_unmap_single(port_priv->device->dma_device, | ||
1597 | pci_unmap_addr(&recv->header, mapping), | ||
1598 | sizeof(struct ib_mad_private) - | ||
1599 | sizeof(struct ib_mad_private_header), | ||
1600 | DMA_FROM_DEVICE); | ||
1601 | |||
1602 | /* Setup MAD receive work completion from "normal" work completion */ | ||
1603 | recv->header.recv_wc.wc = wc; | ||
1604 | recv->header.recv_wc.mad_len = sizeof(struct ib_mad); | ||
1605 | recv->header.recv_wc.recv_buf.mad = &recv->mad.mad; | ||
1606 | recv->header.recv_wc.recv_buf.grh = &recv->grh; | ||
1607 | |||
1608 | if (atomic_read(&qp_info->snoop_count)) | ||
1609 | snoop_recv(qp_info, &recv->header.recv_wc, IB_MAD_SNOOP_RECVS); | ||
1610 | |||
1611 | /* Validate MAD */ | ||
1612 | if (!validate_mad(&recv->mad.mad, qp_info->qp->qp_num)) | ||
1613 | goto out; | ||
1614 | |||
1615 | if (recv->mad.mad.mad_hdr.mgmt_class == | ||
1616 | IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { | ||
1617 | if (!smi_handle_dr_smp_recv(&recv->mad.smp, | ||
1618 | port_priv->device->node_type, | ||
1619 | port_priv->port_num, | ||
1620 | port_priv->device->phys_port_cnt)) | ||
1621 | goto out; | ||
1622 | if (!smi_check_forward_dr_smp(&recv->mad.smp)) | ||
1623 | goto local; | ||
1624 | if (!smi_handle_dr_smp_send(&recv->mad.smp, | ||
1625 | port_priv->device->node_type, | ||
1626 | port_priv->port_num)) | ||
1627 | goto out; | ||
1628 | if (!smi_check_local_dr_smp(&recv->mad.smp, | ||
1629 | port_priv->device, | ||
1630 | port_priv->port_num)) | ||
1631 | goto out; | ||
1632 | } | ||
1633 | |||
1634 | local: | ||
1635 | /* Give driver "right of first refusal" on incoming MAD */ | ||
1636 | if (port_priv->device->process_mad) { | ||
1637 | int ret; | ||
1638 | |||
1639 | if (!response) { | ||
1640 | printk(KERN_ERR PFX "No memory for response MAD\n"); | ||
1641 | /* | ||
1642 | * Is it better to assume that | ||
1643 | * it wouldn't be processed ? | ||
1644 | */ | ||
1645 | goto out; | ||
1646 | } | ||
1647 | |||
1648 | ret = port_priv->device->process_mad(port_priv->device, 0, | ||
1649 | port_priv->port_num, | ||
1650 | wc, &recv->grh, | ||
1651 | &recv->mad.mad, | ||
1652 | &response->mad.mad); | ||
1653 | if (ret & IB_MAD_RESULT_SUCCESS) { | ||
1654 | if (ret & IB_MAD_RESULT_CONSUMED) | ||
1655 | goto out; | ||
1656 | if (ret & IB_MAD_RESULT_REPLY) { | ||
1657 | /* Send response */ | ||
1658 | if (!agent_send(response, &recv->grh, wc, | ||
1659 | port_priv->device, | ||
1660 | port_priv->port_num)) | ||
1661 | response = NULL; | ||
1662 | goto out; | ||
1663 | } | ||
1664 | } | ||
1665 | } | ||
1666 | |||
1667 | /* Determine corresponding MAD agent for incoming receive MAD */ | ||
1668 | solicited = solicited_mad(&recv->mad.mad); | ||
1669 | mad_agent = find_mad_agent(port_priv, &recv->mad.mad, solicited); | ||
1670 | if (mad_agent) { | ||
1671 | ib_mad_complete_recv(mad_agent, recv, solicited); | ||
1672 | /* | ||
1673 | * recv is freed up in error cases in ib_mad_complete_recv | ||
1674 | * or via recv_handler in ib_mad_complete_recv() | ||
1675 | */ | ||
1676 | recv = NULL; | ||
1677 | } | ||
1678 | |||
1679 | out: | ||
1680 | /* Post another receive request for this QP */ | ||
1681 | if (response) { | ||
1682 | ib_mad_post_receive_mads(qp_info, response); | ||
1683 | if (recv) | ||
1684 | kmem_cache_free(ib_mad_cache, recv); | ||
1685 | } else | ||
1686 | ib_mad_post_receive_mads(qp_info, recv); | ||
1687 | } | ||
1688 | |||
1689 | static void adjust_timeout(struct ib_mad_agent_private *mad_agent_priv) | ||
1690 | { | ||
1691 | struct ib_mad_send_wr_private *mad_send_wr; | ||
1692 | unsigned long delay; | ||
1693 | |||
1694 | if (list_empty(&mad_agent_priv->wait_list)) { | ||
1695 | cancel_delayed_work(&mad_agent_priv->timed_work); | ||
1696 | } else { | ||
1697 | mad_send_wr = list_entry(mad_agent_priv->wait_list.next, | ||
1698 | struct ib_mad_send_wr_private, | ||
1699 | agent_list); | ||
1700 | |||
1701 | if (time_after(mad_agent_priv->timeout, | ||
1702 | mad_send_wr->timeout)) { | ||
1703 | mad_agent_priv->timeout = mad_send_wr->timeout; | ||
1704 | cancel_delayed_work(&mad_agent_priv->timed_work); | ||
1705 | delay = mad_send_wr->timeout - jiffies; | ||
1706 | if ((long)delay <= 0) | ||
1707 | delay = 1; | ||
1708 | queue_delayed_work(mad_agent_priv->qp_info-> | ||
1709 | port_priv->wq, | ||
1710 | &mad_agent_priv->timed_work, delay); | ||
1711 | } | ||
1712 | } | ||
1713 | } | ||
1714 | |||
1715 | static void wait_for_response(struct ib_mad_agent_private *mad_agent_priv, | ||
1716 | struct ib_mad_send_wr_private *mad_send_wr ) | ||
1717 | { | ||
1718 | struct ib_mad_send_wr_private *temp_mad_send_wr; | ||
1719 | struct list_head *list_item; | ||
1720 | unsigned long delay; | ||
1721 | |||
1722 | list_del(&mad_send_wr->agent_list); | ||
1723 | |||
1724 | delay = mad_send_wr->timeout; | ||
1725 | mad_send_wr->timeout += jiffies; | ||
1726 | |||
1727 | list_for_each_prev(list_item, &mad_agent_priv->wait_list) { | ||
1728 | temp_mad_send_wr = list_entry(list_item, | ||
1729 | struct ib_mad_send_wr_private, | ||
1730 | agent_list); | ||
1731 | if (time_after(mad_send_wr->timeout, | ||
1732 | temp_mad_send_wr->timeout)) | ||
1733 | break; | ||
1734 | } | ||
1735 | list_add(&mad_send_wr->agent_list, list_item); | ||
1736 | |||
1737 | /* Reschedule a work item if we have a shorter timeout */ | ||
1738 | if (mad_agent_priv->wait_list.next == &mad_send_wr->agent_list) { | ||
1739 | cancel_delayed_work(&mad_agent_priv->timed_work); | ||
1740 | queue_delayed_work(mad_agent_priv->qp_info->port_priv->wq, | ||
1741 | &mad_agent_priv->timed_work, delay); | ||
1742 | } | ||
1743 | } | ||
1744 | |||
1745 | /* | ||
1746 | * Process a send work completion | ||
1747 | */ | ||
1748 | static void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr, | ||
1749 | struct ib_mad_send_wc *mad_send_wc) | ||
1750 | { | ||
1751 | struct ib_mad_agent_private *mad_agent_priv; | ||
1752 | unsigned long flags; | ||
1753 | |||
1754 | mad_agent_priv = container_of(mad_send_wr->agent, | ||
1755 | struct ib_mad_agent_private, agent); | ||
1756 | |||
1757 | spin_lock_irqsave(&mad_agent_priv->lock, flags); | ||
1758 | if (mad_send_wc->status != IB_WC_SUCCESS && | ||
1759 | mad_send_wr->status == IB_WC_SUCCESS) { | ||
1760 | mad_send_wr->status = mad_send_wc->status; | ||
1761 | mad_send_wr->refcount -= (mad_send_wr->timeout > 0); | ||
1762 | } | ||
1763 | |||
1764 | if (--mad_send_wr->refcount > 0) { | ||
1765 | if (mad_send_wr->refcount == 1 && mad_send_wr->timeout && | ||
1766 | mad_send_wr->status == IB_WC_SUCCESS) { | ||
1767 | wait_for_response(mad_agent_priv, mad_send_wr); | ||
1768 | } | ||
1769 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
1770 | return; | ||
1771 | } | ||
1772 | |||
1773 | /* Remove send from MAD agent and notify client of completion */ | ||
1774 | list_del(&mad_send_wr->agent_list); | ||
1775 | adjust_timeout(mad_agent_priv); | ||
1776 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
1777 | |||
1778 | if (mad_send_wr->status != IB_WC_SUCCESS ) | ||
1779 | mad_send_wc->status = mad_send_wr->status; | ||
1780 | mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, | ||
1781 | mad_send_wc); | ||
1782 | |||
1783 | /* Release reference on agent taken when sending */ | ||
1784 | if (atomic_dec_and_test(&mad_agent_priv->refcount)) | ||
1785 | wake_up(&mad_agent_priv->wait); | ||
1786 | |||
1787 | kfree(mad_send_wr); | ||
1788 | } | ||
1789 | |||
1790 | static void ib_mad_send_done_handler(struct ib_mad_port_private *port_priv, | ||
1791 | struct ib_wc *wc) | ||
1792 | { | ||
1793 | struct ib_mad_send_wr_private *mad_send_wr, *queued_send_wr; | ||
1794 | struct ib_mad_list_head *mad_list; | ||
1795 | struct ib_mad_qp_info *qp_info; | ||
1796 | struct ib_mad_queue *send_queue; | ||
1797 | struct ib_send_wr *bad_send_wr; | ||
1798 | unsigned long flags; | ||
1799 | int ret; | ||
1800 | |||
1801 | mad_list = (struct ib_mad_list_head *)(unsigned long)wc->wr_id; | ||
1802 | mad_send_wr = container_of(mad_list, struct ib_mad_send_wr_private, | ||
1803 | mad_list); | ||
1804 | send_queue = mad_list->mad_queue; | ||
1805 | qp_info = send_queue->qp_info; | ||
1806 | |||
1807 | retry: | ||
1808 | queued_send_wr = NULL; | ||
1809 | spin_lock_irqsave(&send_queue->lock, flags); | ||
1810 | list_del(&mad_list->list); | ||
1811 | |||
1812 | /* Move queued send to the send queue */ | ||
1813 | if (send_queue->count-- > send_queue->max_active) { | ||
1814 | mad_list = container_of(qp_info->overflow_list.next, | ||
1815 | struct ib_mad_list_head, list); | ||
1816 | queued_send_wr = container_of(mad_list, | ||
1817 | struct ib_mad_send_wr_private, | ||
1818 | mad_list); | ||
1819 | list_del(&mad_list->list); | ||
1820 | list_add_tail(&mad_list->list, &send_queue->list); | ||
1821 | } | ||
1822 | spin_unlock_irqrestore(&send_queue->lock, flags); | ||
1823 | |||
1824 | /* Restore client wr_id in WC and complete send */ | ||
1825 | wc->wr_id = mad_send_wr->wr_id; | ||
1826 | if (atomic_read(&qp_info->snoop_count)) | ||
1827 | snoop_send(qp_info, &mad_send_wr->send_wr, | ||
1828 | (struct ib_mad_send_wc *)wc, | ||
1829 | IB_MAD_SNOOP_SEND_COMPLETIONS); | ||
1830 | ib_mad_complete_send_wr(mad_send_wr, (struct ib_mad_send_wc *)wc); | ||
1831 | |||
1832 | if (queued_send_wr) { | ||
1833 | ret = ib_post_send(qp_info->qp, &queued_send_wr->send_wr, | ||
1834 | &bad_send_wr); | ||
1835 | if (ret) { | ||
1836 | printk(KERN_ERR PFX "ib_post_send failed: %d\n", ret); | ||
1837 | mad_send_wr = queued_send_wr; | ||
1838 | wc->status = IB_WC_LOC_QP_OP_ERR; | ||
1839 | goto retry; | ||
1840 | } | ||
1841 | } | ||
1842 | } | ||
1843 | |||
1844 | static void mark_sends_for_retry(struct ib_mad_qp_info *qp_info) | ||
1845 | { | ||
1846 | struct ib_mad_send_wr_private *mad_send_wr; | ||
1847 | struct ib_mad_list_head *mad_list; | ||
1848 | unsigned long flags; | ||
1849 | |||
1850 | spin_lock_irqsave(&qp_info->send_queue.lock, flags); | ||
1851 | list_for_each_entry(mad_list, &qp_info->send_queue.list, list) { | ||
1852 | mad_send_wr = container_of(mad_list, | ||
1853 | struct ib_mad_send_wr_private, | ||
1854 | mad_list); | ||
1855 | mad_send_wr->retry = 1; | ||
1856 | } | ||
1857 | spin_unlock_irqrestore(&qp_info->send_queue.lock, flags); | ||
1858 | } | ||
1859 | |||
1860 | static void mad_error_handler(struct ib_mad_port_private *port_priv, | ||
1861 | struct ib_wc *wc) | ||
1862 | { | ||
1863 | struct ib_mad_list_head *mad_list; | ||
1864 | struct ib_mad_qp_info *qp_info; | ||
1865 | struct ib_mad_send_wr_private *mad_send_wr; | ||
1866 | int ret; | ||
1867 | |||
1868 | /* Determine if failure was a send or receive */ | ||
1869 | mad_list = (struct ib_mad_list_head *)(unsigned long)wc->wr_id; | ||
1870 | qp_info = mad_list->mad_queue->qp_info; | ||
1871 | if (mad_list->mad_queue == &qp_info->recv_queue) | ||
1872 | /* | ||
1873 | * Receive errors indicate that the QP has entered the error | ||
1874 | * state - error handling/shutdown code will cleanup | ||
1875 | */ | ||
1876 | return; | ||
1877 | |||
1878 | /* | ||
1879 | * Send errors will transition the QP to SQE - move | ||
1880 | * QP to RTS and repost flushed work requests | ||
1881 | */ | ||
1882 | mad_send_wr = container_of(mad_list, struct ib_mad_send_wr_private, | ||
1883 | mad_list); | ||
1884 | if (wc->status == IB_WC_WR_FLUSH_ERR) { | ||
1885 | if (mad_send_wr->retry) { | ||
1886 | /* Repost send */ | ||
1887 | struct ib_send_wr *bad_send_wr; | ||
1888 | |||
1889 | mad_send_wr->retry = 0; | ||
1890 | ret = ib_post_send(qp_info->qp, &mad_send_wr->send_wr, | ||
1891 | &bad_send_wr); | ||
1892 | if (ret) | ||
1893 | ib_mad_send_done_handler(port_priv, wc); | ||
1894 | } else | ||
1895 | ib_mad_send_done_handler(port_priv, wc); | ||
1896 | } else { | ||
1897 | struct ib_qp_attr *attr; | ||
1898 | |||
1899 | /* Transition QP to RTS and fail offending send */ | ||
1900 | attr = kmalloc(sizeof *attr, GFP_KERNEL); | ||
1901 | if (attr) { | ||
1902 | attr->qp_state = IB_QPS_RTS; | ||
1903 | attr->cur_qp_state = IB_QPS_SQE; | ||
1904 | ret = ib_modify_qp(qp_info->qp, attr, | ||
1905 | IB_QP_STATE | IB_QP_CUR_STATE); | ||
1906 | kfree(attr); | ||
1907 | if (ret) | ||
1908 | printk(KERN_ERR PFX "mad_error_handler - " | ||
1909 | "ib_modify_qp to RTS : %d\n", ret); | ||
1910 | else | ||
1911 | mark_sends_for_retry(qp_info); | ||
1912 | } | ||
1913 | ib_mad_send_done_handler(port_priv, wc); | ||
1914 | } | ||
1915 | } | ||
1916 | |||
1917 | /* | ||
1918 | * IB MAD completion callback | ||
1919 | */ | ||
1920 | static void ib_mad_completion_handler(void *data) | ||
1921 | { | ||
1922 | struct ib_mad_port_private *port_priv; | ||
1923 | struct ib_wc wc; | ||
1924 | |||
1925 | port_priv = (struct ib_mad_port_private *)data; | ||
1926 | ib_req_notify_cq(port_priv->cq, IB_CQ_NEXT_COMP); | ||
1927 | |||
1928 | while (ib_poll_cq(port_priv->cq, 1, &wc) == 1) { | ||
1929 | if (wc.status == IB_WC_SUCCESS) { | ||
1930 | switch (wc.opcode) { | ||
1931 | case IB_WC_SEND: | ||
1932 | ib_mad_send_done_handler(port_priv, &wc); | ||
1933 | break; | ||
1934 | case IB_WC_RECV: | ||
1935 | ib_mad_recv_done_handler(port_priv, &wc); | ||
1936 | break; | ||
1937 | default: | ||
1938 | BUG_ON(1); | ||
1939 | break; | ||
1940 | } | ||
1941 | } else | ||
1942 | mad_error_handler(port_priv, &wc); | ||
1943 | } | ||
1944 | } | ||
1945 | |||
1946 | static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv) | ||
1947 | { | ||
1948 | unsigned long flags; | ||
1949 | struct ib_mad_send_wr_private *mad_send_wr, *temp_mad_send_wr; | ||
1950 | struct ib_mad_send_wc mad_send_wc; | ||
1951 | struct list_head cancel_list; | ||
1952 | |||
1953 | INIT_LIST_HEAD(&cancel_list); | ||
1954 | |||
1955 | spin_lock_irqsave(&mad_agent_priv->lock, flags); | ||
1956 | list_for_each_entry_safe(mad_send_wr, temp_mad_send_wr, | ||
1957 | &mad_agent_priv->send_list, agent_list) { | ||
1958 | if (mad_send_wr->status == IB_WC_SUCCESS) { | ||
1959 | mad_send_wr->status = IB_WC_WR_FLUSH_ERR; | ||
1960 | mad_send_wr->refcount -= (mad_send_wr->timeout > 0); | ||
1961 | } | ||
1962 | } | ||
1963 | |||
1964 | /* Empty wait list to prevent receives from finding a request */ | ||
1965 | list_splice_init(&mad_agent_priv->wait_list, &cancel_list); | ||
1966 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
1967 | |||
1968 | /* Report all cancelled requests */ | ||
1969 | mad_send_wc.status = IB_WC_WR_FLUSH_ERR; | ||
1970 | mad_send_wc.vendor_err = 0; | ||
1971 | |||
1972 | list_for_each_entry_safe(mad_send_wr, temp_mad_send_wr, | ||
1973 | &cancel_list, agent_list) { | ||
1974 | mad_send_wc.wr_id = mad_send_wr->wr_id; | ||
1975 | mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, | ||
1976 | &mad_send_wc); | ||
1977 | |||
1978 | list_del(&mad_send_wr->agent_list); | ||
1979 | kfree(mad_send_wr); | ||
1980 | atomic_dec(&mad_agent_priv->refcount); | ||
1981 | } | ||
1982 | } | ||
1983 | |||
1984 | static struct ib_mad_send_wr_private* | ||
1985 | find_send_by_wr_id(struct ib_mad_agent_private *mad_agent_priv, | ||
1986 | u64 wr_id) | ||
1987 | { | ||
1988 | struct ib_mad_send_wr_private *mad_send_wr; | ||
1989 | |||
1990 | list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list, | ||
1991 | agent_list) { | ||
1992 | if (mad_send_wr->wr_id == wr_id) | ||
1993 | return mad_send_wr; | ||
1994 | } | ||
1995 | |||
1996 | list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list, | ||
1997 | agent_list) { | ||
1998 | if (mad_send_wr->wr_id == wr_id) | ||
1999 | return mad_send_wr; | ||
2000 | } | ||
2001 | return NULL; | ||
2002 | } | ||
2003 | |||
2004 | void cancel_sends(void *data) | ||
2005 | { | ||
2006 | struct ib_mad_agent_private *mad_agent_priv; | ||
2007 | struct ib_mad_send_wr_private *mad_send_wr; | ||
2008 | struct ib_mad_send_wc mad_send_wc; | ||
2009 | unsigned long flags; | ||
2010 | |||
2011 | mad_agent_priv = data; | ||
2012 | |||
2013 | mad_send_wc.status = IB_WC_WR_FLUSH_ERR; | ||
2014 | mad_send_wc.vendor_err = 0; | ||
2015 | |||
2016 | spin_lock_irqsave(&mad_agent_priv->lock, flags); | ||
2017 | while (!list_empty(&mad_agent_priv->canceled_list)) { | ||
2018 | mad_send_wr = list_entry(mad_agent_priv->canceled_list.next, | ||
2019 | struct ib_mad_send_wr_private, | ||
2020 | agent_list); | ||
2021 | |||
2022 | list_del(&mad_send_wr->agent_list); | ||
2023 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
2024 | |||
2025 | mad_send_wc.wr_id = mad_send_wr->wr_id; | ||
2026 | mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, | ||
2027 | &mad_send_wc); | ||
2028 | |||
2029 | kfree(mad_send_wr); | ||
2030 | if (atomic_dec_and_test(&mad_agent_priv->refcount)) | ||
2031 | wake_up(&mad_agent_priv->wait); | ||
2032 | spin_lock_irqsave(&mad_agent_priv->lock, flags); | ||
2033 | } | ||
2034 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
2035 | } | ||
2036 | |||
2037 | void ib_cancel_mad(struct ib_mad_agent *mad_agent, | ||
2038 | u64 wr_id) | ||
2039 | { | ||
2040 | struct ib_mad_agent_private *mad_agent_priv; | ||
2041 | struct ib_mad_send_wr_private *mad_send_wr; | ||
2042 | unsigned long flags; | ||
2043 | |||
2044 | mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private, | ||
2045 | agent); | ||
2046 | spin_lock_irqsave(&mad_agent_priv->lock, flags); | ||
2047 | mad_send_wr = find_send_by_wr_id(mad_agent_priv, wr_id); | ||
2048 | if (!mad_send_wr) { | ||
2049 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
2050 | goto out; | ||
2051 | } | ||
2052 | |||
2053 | if (mad_send_wr->status == IB_WC_SUCCESS) | ||
2054 | mad_send_wr->refcount -= (mad_send_wr->timeout > 0); | ||
2055 | |||
2056 | if (mad_send_wr->refcount != 0) { | ||
2057 | mad_send_wr->status = IB_WC_WR_FLUSH_ERR; | ||
2058 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
2059 | goto out; | ||
2060 | } | ||
2061 | |||
2062 | list_del(&mad_send_wr->agent_list); | ||
2063 | list_add_tail(&mad_send_wr->agent_list, &mad_agent_priv->canceled_list); | ||
2064 | adjust_timeout(mad_agent_priv); | ||
2065 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
2066 | |||
2067 | queue_work(mad_agent_priv->qp_info->port_priv->wq, | ||
2068 | &mad_agent_priv->canceled_work); | ||
2069 | out: | ||
2070 | return; | ||
2071 | } | ||
2072 | EXPORT_SYMBOL(ib_cancel_mad); | ||
2073 | |||
2074 | static void local_completions(void *data) | ||
2075 | { | ||
2076 | struct ib_mad_agent_private *mad_agent_priv; | ||
2077 | struct ib_mad_local_private *local; | ||
2078 | struct ib_mad_agent_private *recv_mad_agent; | ||
2079 | unsigned long flags; | ||
2080 | struct ib_wc wc; | ||
2081 | struct ib_mad_send_wc mad_send_wc; | ||
2082 | |||
2083 | mad_agent_priv = (struct ib_mad_agent_private *)data; | ||
2084 | |||
2085 | spin_lock_irqsave(&mad_agent_priv->lock, flags); | ||
2086 | while (!list_empty(&mad_agent_priv->local_list)) { | ||
2087 | local = list_entry(mad_agent_priv->local_list.next, | ||
2088 | struct ib_mad_local_private, | ||
2089 | completion_list); | ||
2090 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
2091 | if (local->mad_priv) { | ||
2092 | recv_mad_agent = local->recv_mad_agent; | ||
2093 | if (!recv_mad_agent) { | ||
2094 | printk(KERN_ERR PFX "No receive MAD agent for local completion\n"); | ||
2095 | kmem_cache_free(ib_mad_cache, local->mad_priv); | ||
2096 | goto local_send_completion; | ||
2097 | } | ||
2098 | |||
2099 | /* | ||
2100 | * Defined behavior is to complete response | ||
2101 | * before request | ||
2102 | */ | ||
2103 | build_smp_wc(local->wr_id, IB_LID_PERMISSIVE, | ||
2104 | 0 /* pkey index */, | ||
2105 | recv_mad_agent->agent.port_num, &wc); | ||
2106 | |||
2107 | local->mad_priv->header.recv_wc.wc = &wc; | ||
2108 | local->mad_priv->header.recv_wc.mad_len = | ||
2109 | sizeof(struct ib_mad); | ||
2110 | INIT_LIST_HEAD(&local->mad_priv->header.recv_wc.recv_buf.list); | ||
2111 | local->mad_priv->header.recv_wc.recv_buf.grh = NULL; | ||
2112 | local->mad_priv->header.recv_wc.recv_buf.mad = | ||
2113 | &local->mad_priv->mad.mad; | ||
2114 | if (atomic_read(&recv_mad_agent->qp_info->snoop_count)) | ||
2115 | snoop_recv(recv_mad_agent->qp_info, | ||
2116 | &local->mad_priv->header.recv_wc, | ||
2117 | IB_MAD_SNOOP_RECVS); | ||
2118 | recv_mad_agent->agent.recv_handler( | ||
2119 | &recv_mad_agent->agent, | ||
2120 | &local->mad_priv->header.recv_wc); | ||
2121 | spin_lock_irqsave(&recv_mad_agent->lock, flags); | ||
2122 | atomic_dec(&recv_mad_agent->refcount); | ||
2123 | spin_unlock_irqrestore(&recv_mad_agent->lock, flags); | ||
2124 | } | ||
2125 | |||
2126 | local_send_completion: | ||
2127 | /* Complete send */ | ||
2128 | mad_send_wc.status = IB_WC_SUCCESS; | ||
2129 | mad_send_wc.vendor_err = 0; | ||
2130 | mad_send_wc.wr_id = local->wr_id; | ||
2131 | if (atomic_read(&mad_agent_priv->qp_info->snoop_count)) | ||
2132 | snoop_send(mad_agent_priv->qp_info, &local->send_wr, | ||
2133 | &mad_send_wc, | ||
2134 | IB_MAD_SNOOP_SEND_COMPLETIONS); | ||
2135 | mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, | ||
2136 | &mad_send_wc); | ||
2137 | |||
2138 | spin_lock_irqsave(&mad_agent_priv->lock, flags); | ||
2139 | list_del(&local->completion_list); | ||
2140 | atomic_dec(&mad_agent_priv->refcount); | ||
2141 | kfree(local); | ||
2142 | } | ||
2143 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
2144 | } | ||
2145 | |||
2146 | static void timeout_sends(void *data) | ||
2147 | { | ||
2148 | struct ib_mad_agent_private *mad_agent_priv; | ||
2149 | struct ib_mad_send_wr_private *mad_send_wr; | ||
2150 | struct ib_mad_send_wc mad_send_wc; | ||
2151 | unsigned long flags, delay; | ||
2152 | |||
2153 | mad_agent_priv = (struct ib_mad_agent_private *)data; | ||
2154 | |||
2155 | mad_send_wc.status = IB_WC_RESP_TIMEOUT_ERR; | ||
2156 | mad_send_wc.vendor_err = 0; | ||
2157 | |||
2158 | spin_lock_irqsave(&mad_agent_priv->lock, flags); | ||
2159 | while (!list_empty(&mad_agent_priv->wait_list)) { | ||
2160 | mad_send_wr = list_entry(mad_agent_priv->wait_list.next, | ||
2161 | struct ib_mad_send_wr_private, | ||
2162 | agent_list); | ||
2163 | |||
2164 | if (time_after(mad_send_wr->timeout, jiffies)) { | ||
2165 | delay = mad_send_wr->timeout - jiffies; | ||
2166 | if ((long)delay <= 0) | ||
2167 | delay = 1; | ||
2168 | queue_delayed_work(mad_agent_priv->qp_info-> | ||
2169 | port_priv->wq, | ||
2170 | &mad_agent_priv->timed_work, delay); | ||
2171 | break; | ||
2172 | } | ||
2173 | |||
2174 | list_del(&mad_send_wr->agent_list); | ||
2175 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
2176 | |||
2177 | mad_send_wc.wr_id = mad_send_wr->wr_id; | ||
2178 | mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, | ||
2179 | &mad_send_wc); | ||
2180 | |||
2181 | kfree(mad_send_wr); | ||
2182 | atomic_dec(&mad_agent_priv->refcount); | ||
2183 | spin_lock_irqsave(&mad_agent_priv->lock, flags); | ||
2184 | } | ||
2185 | spin_unlock_irqrestore(&mad_agent_priv->lock, flags); | ||
2186 | } | ||
2187 | |||
2188 | static void ib_mad_thread_completion_handler(struct ib_cq *cq) | ||
2189 | { | ||
2190 | struct ib_mad_port_private *port_priv = cq->cq_context; | ||
2191 | |||
2192 | queue_work(port_priv->wq, &port_priv->work); | ||
2193 | } | ||
2194 | |||
2195 | /* | ||
2196 | * Allocate receive MADs and post receive WRs for them | ||
2197 | */ | ||
2198 | static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info, | ||
2199 | struct ib_mad_private *mad) | ||
2200 | { | ||
2201 | unsigned long flags; | ||
2202 | int post, ret; | ||
2203 | struct ib_mad_private *mad_priv; | ||
2204 | struct ib_sge sg_list; | ||
2205 | struct ib_recv_wr recv_wr, *bad_recv_wr; | ||
2206 | struct ib_mad_queue *recv_queue = &qp_info->recv_queue; | ||
2207 | |||
2208 | /* Initialize common scatter list fields */ | ||
2209 | sg_list.length = sizeof *mad_priv - sizeof mad_priv->header; | ||
2210 | sg_list.lkey = (*qp_info->port_priv->mr).lkey; | ||
2211 | |||
2212 | /* Initialize common receive WR fields */ | ||
2213 | recv_wr.next = NULL; | ||
2214 | recv_wr.sg_list = &sg_list; | ||
2215 | recv_wr.num_sge = 1; | ||
2216 | |||
2217 | do { | ||
2218 | /* Allocate and map receive buffer */ | ||
2219 | if (mad) { | ||
2220 | mad_priv = mad; | ||
2221 | mad = NULL; | ||
2222 | } else { | ||
2223 | mad_priv = kmem_cache_alloc(ib_mad_cache, GFP_KERNEL); | ||
2224 | if (!mad_priv) { | ||
2225 | printk(KERN_ERR PFX "No memory for receive buffer\n"); | ||
2226 | ret = -ENOMEM; | ||
2227 | break; | ||
2228 | } | ||
2229 | } | ||
2230 | sg_list.addr = dma_map_single(qp_info->port_priv-> | ||
2231 | device->dma_device, | ||
2232 | &mad_priv->grh, | ||
2233 | sizeof *mad_priv - | ||
2234 | sizeof mad_priv->header, | ||
2235 | DMA_FROM_DEVICE); | ||
2236 | pci_unmap_addr_set(&mad_priv->header, mapping, sg_list.addr); | ||
2237 | recv_wr.wr_id = (unsigned long)&mad_priv->header.mad_list; | ||
2238 | mad_priv->header.mad_list.mad_queue = recv_queue; | ||
2239 | |||
2240 | /* Post receive WR */ | ||
2241 | spin_lock_irqsave(&recv_queue->lock, flags); | ||
2242 | post = (++recv_queue->count < recv_queue->max_active); | ||
2243 | list_add_tail(&mad_priv->header.mad_list.list, &recv_queue->list); | ||
2244 | spin_unlock_irqrestore(&recv_queue->lock, flags); | ||
2245 | ret = ib_post_recv(qp_info->qp, &recv_wr, &bad_recv_wr); | ||
2246 | if (ret) { | ||
2247 | spin_lock_irqsave(&recv_queue->lock, flags); | ||
2248 | list_del(&mad_priv->header.mad_list.list); | ||
2249 | recv_queue->count--; | ||
2250 | spin_unlock_irqrestore(&recv_queue->lock, flags); | ||
2251 | dma_unmap_single(qp_info->port_priv->device->dma_device, | ||
2252 | pci_unmap_addr(&mad_priv->header, | ||
2253 | mapping), | ||
2254 | sizeof *mad_priv - | ||
2255 | sizeof mad_priv->header, | ||
2256 | DMA_FROM_DEVICE); | ||
2257 | kmem_cache_free(ib_mad_cache, mad_priv); | ||
2258 | printk(KERN_ERR PFX "ib_post_recv failed: %d\n", ret); | ||
2259 | break; | ||
2260 | } | ||
2261 | } while (post); | ||
2262 | |||
2263 | return ret; | ||
2264 | } | ||
2265 | |||
2266 | /* | ||
2267 | * Return all the posted receive MADs | ||
2268 | */ | ||
2269 | static void cleanup_recv_queue(struct ib_mad_qp_info *qp_info) | ||
2270 | { | ||
2271 | struct ib_mad_private_header *mad_priv_hdr; | ||
2272 | struct ib_mad_private *recv; | ||
2273 | struct ib_mad_list_head *mad_list; | ||
2274 | |||
2275 | while (!list_empty(&qp_info->recv_queue.list)) { | ||
2276 | |||
2277 | mad_list = list_entry(qp_info->recv_queue.list.next, | ||
2278 | struct ib_mad_list_head, list); | ||
2279 | mad_priv_hdr = container_of(mad_list, | ||
2280 | struct ib_mad_private_header, | ||
2281 | mad_list); | ||
2282 | recv = container_of(mad_priv_hdr, struct ib_mad_private, | ||
2283 | header); | ||
2284 | |||
2285 | /* Remove from posted receive MAD list */ | ||
2286 | list_del(&mad_list->list); | ||
2287 | |||
2288 | /* Undo PCI mapping */ | ||
2289 | dma_unmap_single(qp_info->port_priv->device->dma_device, | ||
2290 | pci_unmap_addr(&recv->header, mapping), | ||
2291 | sizeof(struct ib_mad_private) - | ||
2292 | sizeof(struct ib_mad_private_header), | ||
2293 | DMA_FROM_DEVICE); | ||
2294 | kmem_cache_free(ib_mad_cache, recv); | ||
2295 | } | ||
2296 | |||
2297 | qp_info->recv_queue.count = 0; | ||
2298 | } | ||
2299 | |||
2300 | /* | ||
2301 | * Start the port | ||
2302 | */ | ||
2303 | static int ib_mad_port_start(struct ib_mad_port_private *port_priv) | ||
2304 | { | ||
2305 | int ret, i; | ||
2306 | struct ib_qp_attr *attr; | ||
2307 | struct ib_qp *qp; | ||
2308 | |||
2309 | attr = kmalloc(sizeof *attr, GFP_KERNEL); | ||
2310 | if (!attr) { | ||
2311 | printk(KERN_ERR PFX "Couldn't kmalloc ib_qp_attr\n"); | ||
2312 | return -ENOMEM; | ||
2313 | } | ||
2314 | |||
2315 | for (i = 0; i < IB_MAD_QPS_CORE; i++) { | ||
2316 | qp = port_priv->qp_info[i].qp; | ||
2317 | /* | ||
2318 | * PKey index for QP1 is irrelevant but | ||
2319 | * one is needed for the Reset to Init transition | ||
2320 | */ | ||
2321 | attr->qp_state = IB_QPS_INIT; | ||
2322 | attr->pkey_index = 0; | ||
2323 | attr->qkey = (qp->qp_num == 0) ? 0 : IB_QP1_QKEY; | ||
2324 | ret = ib_modify_qp(qp, attr, IB_QP_STATE | | ||
2325 | IB_QP_PKEY_INDEX | IB_QP_QKEY); | ||
2326 | if (ret) { | ||
2327 | printk(KERN_ERR PFX "Couldn't change QP%d state to " | ||
2328 | "INIT: %d\n", i, ret); | ||
2329 | goto out; | ||
2330 | } | ||
2331 | |||
2332 | attr->qp_state = IB_QPS_RTR; | ||
2333 | ret = ib_modify_qp(qp, attr, IB_QP_STATE); | ||
2334 | if (ret) { | ||
2335 | printk(KERN_ERR PFX "Couldn't change QP%d state to " | ||
2336 | "RTR: %d\n", i, ret); | ||
2337 | goto out; | ||
2338 | } | ||
2339 | |||
2340 | attr->qp_state = IB_QPS_RTS; | ||
2341 | attr->sq_psn = IB_MAD_SEND_Q_PSN; | ||
2342 | ret = ib_modify_qp(qp, attr, IB_QP_STATE | IB_QP_SQ_PSN); | ||
2343 | if (ret) { | ||
2344 | printk(KERN_ERR PFX "Couldn't change QP%d state to " | ||
2345 | "RTS: %d\n", i, ret); | ||
2346 | goto out; | ||
2347 | } | ||
2348 | } | ||
2349 | |||
2350 | ret = ib_req_notify_cq(port_priv->cq, IB_CQ_NEXT_COMP); | ||
2351 | if (ret) { | ||
2352 | printk(KERN_ERR PFX "Failed to request completion " | ||
2353 | "notification: %d\n", ret); | ||
2354 | goto out; | ||
2355 | } | ||
2356 | |||
2357 | for (i = 0; i < IB_MAD_QPS_CORE; i++) { | ||
2358 | ret = ib_mad_post_receive_mads(&port_priv->qp_info[i], NULL); | ||
2359 | if (ret) { | ||
2360 | printk(KERN_ERR PFX "Couldn't post receive WRs\n"); | ||
2361 | goto out; | ||
2362 | } | ||
2363 | } | ||
2364 | out: | ||
2365 | kfree(attr); | ||
2366 | return ret; | ||
2367 | } | ||
2368 | |||
2369 | static void qp_event_handler(struct ib_event *event, void *qp_context) | ||
2370 | { | ||
2371 | struct ib_mad_qp_info *qp_info = qp_context; | ||
2372 | |||
2373 | /* It's worse than that! He's dead, Jim! */ | ||
2374 | printk(KERN_ERR PFX "Fatal error (%d) on MAD QP (%d)\n", | ||
2375 | event->event, qp_info->qp->qp_num); | ||
2376 | } | ||
2377 | |||
2378 | static void init_mad_queue(struct ib_mad_qp_info *qp_info, | ||
2379 | struct ib_mad_queue *mad_queue) | ||
2380 | { | ||
2381 | mad_queue->qp_info = qp_info; | ||
2382 | mad_queue->count = 0; | ||
2383 | spin_lock_init(&mad_queue->lock); | ||
2384 | INIT_LIST_HEAD(&mad_queue->list); | ||
2385 | } | ||
2386 | |||
2387 | static void init_mad_qp(struct ib_mad_port_private *port_priv, | ||
2388 | struct ib_mad_qp_info *qp_info) | ||
2389 | { | ||
2390 | qp_info->port_priv = port_priv; | ||
2391 | init_mad_queue(qp_info, &qp_info->send_queue); | ||
2392 | init_mad_queue(qp_info, &qp_info->recv_queue); | ||
2393 | INIT_LIST_HEAD(&qp_info->overflow_list); | ||
2394 | spin_lock_init(&qp_info->snoop_lock); | ||
2395 | qp_info->snoop_table = NULL; | ||
2396 | qp_info->snoop_table_size = 0; | ||
2397 | atomic_set(&qp_info->snoop_count, 0); | ||
2398 | } | ||
2399 | |||
2400 | static int create_mad_qp(struct ib_mad_qp_info *qp_info, | ||
2401 | enum ib_qp_type qp_type) | ||
2402 | { | ||
2403 | struct ib_qp_init_attr qp_init_attr; | ||
2404 | int ret; | ||
2405 | |||
2406 | memset(&qp_init_attr, 0, sizeof qp_init_attr); | ||
2407 | qp_init_attr.send_cq = qp_info->port_priv->cq; | ||
2408 | qp_init_attr.recv_cq = qp_info->port_priv->cq; | ||
2409 | qp_init_attr.sq_sig_type = IB_SIGNAL_ALL_WR; | ||
2410 | qp_init_attr.cap.max_send_wr = IB_MAD_QP_SEND_SIZE; | ||
2411 | qp_init_attr.cap.max_recv_wr = IB_MAD_QP_RECV_SIZE; | ||
2412 | qp_init_attr.cap.max_send_sge = IB_MAD_SEND_REQ_MAX_SG; | ||
2413 | qp_init_attr.cap.max_recv_sge = IB_MAD_RECV_REQ_MAX_SG; | ||
2414 | qp_init_attr.qp_type = qp_type; | ||
2415 | qp_init_attr.port_num = qp_info->port_priv->port_num; | ||
2416 | qp_init_attr.qp_context = qp_info; | ||
2417 | qp_init_attr.event_handler = qp_event_handler; | ||
2418 | qp_info->qp = ib_create_qp(qp_info->port_priv->pd, &qp_init_attr); | ||
2419 | if (IS_ERR(qp_info->qp)) { | ||
2420 | printk(KERN_ERR PFX "Couldn't create ib_mad QP%d\n", | ||
2421 | get_spl_qp_index(qp_type)); | ||
2422 | ret = PTR_ERR(qp_info->qp); | ||
2423 | goto error; | ||
2424 | } | ||
2425 | /* Use minimum queue sizes unless the CQ is resized */ | ||
2426 | qp_info->send_queue.max_active = IB_MAD_QP_SEND_SIZE; | ||
2427 | qp_info->recv_queue.max_active = IB_MAD_QP_RECV_SIZE; | ||
2428 | return 0; | ||
2429 | |||
2430 | error: | ||
2431 | return ret; | ||
2432 | } | ||
2433 | |||
2434 | static void destroy_mad_qp(struct ib_mad_qp_info *qp_info) | ||
2435 | { | ||
2436 | ib_destroy_qp(qp_info->qp); | ||
2437 | if (qp_info->snoop_table) | ||
2438 | kfree(qp_info->snoop_table); | ||
2439 | } | ||
2440 | |||
2441 | /* | ||
2442 | * Open the port | ||
2443 | * Create the QP, PD, MR, and CQ if needed | ||
2444 | */ | ||
2445 | static int ib_mad_port_open(struct ib_device *device, | ||
2446 | int port_num) | ||
2447 | { | ||
2448 | int ret, cq_size; | ||
2449 | struct ib_mad_port_private *port_priv; | ||
2450 | unsigned long flags; | ||
2451 | char name[sizeof "ib_mad123"]; | ||
2452 | |||
2453 | /* First, check if port already open at MAD layer */ | ||
2454 | port_priv = ib_get_mad_port(device, port_num); | ||
2455 | if (port_priv) { | ||
2456 | printk(KERN_DEBUG PFX "%s port %d already open\n", | ||
2457 | device->name, port_num); | ||
2458 | return 0; | ||
2459 | } | ||
2460 | |||
2461 | /* Create new device info */ | ||
2462 | port_priv = kmalloc(sizeof *port_priv, GFP_KERNEL); | ||
2463 | if (!port_priv) { | ||
2464 | printk(KERN_ERR PFX "No memory for ib_mad_port_private\n"); | ||
2465 | return -ENOMEM; | ||
2466 | } | ||
2467 | memset(port_priv, 0, sizeof *port_priv); | ||
2468 | port_priv->device = device; | ||
2469 | port_priv->port_num = port_num; | ||
2470 | spin_lock_init(&port_priv->reg_lock); | ||
2471 | INIT_LIST_HEAD(&port_priv->agent_list); | ||
2472 | init_mad_qp(port_priv, &port_priv->qp_info[0]); | ||
2473 | init_mad_qp(port_priv, &port_priv->qp_info[1]); | ||
2474 | |||
2475 | cq_size = (IB_MAD_QP_SEND_SIZE + IB_MAD_QP_RECV_SIZE) * 2; | ||
2476 | port_priv->cq = ib_create_cq(port_priv->device, | ||
2477 | (ib_comp_handler) | ||
2478 | ib_mad_thread_completion_handler, | ||
2479 | NULL, port_priv, cq_size); | ||
2480 | if (IS_ERR(port_priv->cq)) { | ||
2481 | printk(KERN_ERR PFX "Couldn't create ib_mad CQ\n"); | ||
2482 | ret = PTR_ERR(port_priv->cq); | ||
2483 | goto error3; | ||
2484 | } | ||
2485 | |||
2486 | port_priv->pd = ib_alloc_pd(device); | ||
2487 | if (IS_ERR(port_priv->pd)) { | ||
2488 | printk(KERN_ERR PFX "Couldn't create ib_mad PD\n"); | ||
2489 | ret = PTR_ERR(port_priv->pd); | ||
2490 | goto error4; | ||
2491 | } | ||
2492 | |||
2493 | port_priv->mr = ib_get_dma_mr(port_priv->pd, IB_ACCESS_LOCAL_WRITE); | ||
2494 | if (IS_ERR(port_priv->mr)) { | ||
2495 | printk(KERN_ERR PFX "Couldn't get ib_mad DMA MR\n"); | ||
2496 | ret = PTR_ERR(port_priv->mr); | ||
2497 | goto error5; | ||
2498 | } | ||
2499 | |||
2500 | ret = create_mad_qp(&port_priv->qp_info[0], IB_QPT_SMI); | ||
2501 | if (ret) | ||
2502 | goto error6; | ||
2503 | ret = create_mad_qp(&port_priv->qp_info[1], IB_QPT_GSI); | ||
2504 | if (ret) | ||
2505 | goto error7; | ||
2506 | |||
2507 | snprintf(name, sizeof name, "ib_mad%d", port_num); | ||
2508 | port_priv->wq = create_singlethread_workqueue(name); | ||
2509 | if (!port_priv->wq) { | ||
2510 | ret = -ENOMEM; | ||
2511 | goto error8; | ||
2512 | } | ||
2513 | INIT_WORK(&port_priv->work, ib_mad_completion_handler, port_priv); | ||
2514 | |||
2515 | ret = ib_mad_port_start(port_priv); | ||
2516 | if (ret) { | ||
2517 | printk(KERN_ERR PFX "Couldn't start port\n"); | ||
2518 | goto error9; | ||
2519 | } | ||
2520 | |||
2521 | spin_lock_irqsave(&ib_mad_port_list_lock, flags); | ||
2522 | list_add_tail(&port_priv->port_list, &ib_mad_port_list); | ||
2523 | spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); | ||
2524 | return 0; | ||
2525 | |||
2526 | error9: | ||
2527 | destroy_workqueue(port_priv->wq); | ||
2528 | error8: | ||
2529 | destroy_mad_qp(&port_priv->qp_info[1]); | ||
2530 | error7: | ||
2531 | destroy_mad_qp(&port_priv->qp_info[0]); | ||
2532 | error6: | ||
2533 | ib_dereg_mr(port_priv->mr); | ||
2534 | error5: | ||
2535 | ib_dealloc_pd(port_priv->pd); | ||
2536 | error4: | ||
2537 | ib_destroy_cq(port_priv->cq); | ||
2538 | cleanup_recv_queue(&port_priv->qp_info[1]); | ||
2539 | cleanup_recv_queue(&port_priv->qp_info[0]); | ||
2540 | error3: | ||
2541 | kfree(port_priv); | ||
2542 | |||
2543 | return ret; | ||
2544 | } | ||
2545 | |||
2546 | /* | ||
2547 | * Close the port | ||
2548 | * If there are no classes using the port, free the port | ||
2549 | * resources (CQ, MR, PD, QP) and remove the port's info structure | ||
2550 | */ | ||
2551 | static int ib_mad_port_close(struct ib_device *device, int port_num) | ||
2552 | { | ||
2553 | struct ib_mad_port_private *port_priv; | ||
2554 | unsigned long flags; | ||
2555 | |||
2556 | spin_lock_irqsave(&ib_mad_port_list_lock, flags); | ||
2557 | port_priv = __ib_get_mad_port(device, port_num); | ||
2558 | if (port_priv == NULL) { | ||
2559 | spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); | ||
2560 | printk(KERN_ERR PFX "Port %d not found\n", port_num); | ||
2561 | return -ENODEV; | ||
2562 | } | ||
2563 | list_del(&port_priv->port_list); | ||
2564 | spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); | ||
2565 | |||
2566 | /* Stop processing completions. */ | ||
2567 | flush_workqueue(port_priv->wq); | ||
2568 | destroy_workqueue(port_priv->wq); | ||
2569 | destroy_mad_qp(&port_priv->qp_info[1]); | ||
2570 | destroy_mad_qp(&port_priv->qp_info[0]); | ||
2571 | ib_dereg_mr(port_priv->mr); | ||
2572 | ib_dealloc_pd(port_priv->pd); | ||
2573 | ib_destroy_cq(port_priv->cq); | ||
2574 | cleanup_recv_queue(&port_priv->qp_info[1]); | ||
2575 | cleanup_recv_queue(&port_priv->qp_info[0]); | ||
2576 | /* XXX: Handle deallocation of MAD registration tables */ | ||
2577 | |||
2578 | kfree(port_priv); | ||
2579 | |||
2580 | return 0; | ||
2581 | } | ||
2582 | |||
2583 | static void ib_mad_init_device(struct ib_device *device) | ||
2584 | { | ||
2585 | int ret, num_ports, cur_port, i, ret2; | ||
2586 | |||
2587 | if (device->node_type == IB_NODE_SWITCH) { | ||
2588 | num_ports = 1; | ||
2589 | cur_port = 0; | ||
2590 | } else { | ||
2591 | num_ports = device->phys_port_cnt; | ||
2592 | cur_port = 1; | ||
2593 | } | ||
2594 | for (i = 0; i < num_ports; i++, cur_port++) { | ||
2595 | ret = ib_mad_port_open(device, cur_port); | ||
2596 | if (ret) { | ||
2597 | printk(KERN_ERR PFX "Couldn't open %s port %d\n", | ||
2598 | device->name, cur_port); | ||
2599 | goto error_device_open; | ||
2600 | } | ||
2601 | ret = ib_agent_port_open(device, cur_port); | ||
2602 | if (ret) { | ||
2603 | printk(KERN_ERR PFX "Couldn't open %s port %d " | ||
2604 | "for agents\n", | ||
2605 | device->name, cur_port); | ||
2606 | goto error_device_open; | ||
2607 | } | ||
2608 | } | ||
2609 | |||
2610 | goto error_device_query; | ||
2611 | |||
2612 | error_device_open: | ||
2613 | while (i > 0) { | ||
2614 | cur_port--; | ||
2615 | ret2 = ib_agent_port_close(device, cur_port); | ||
2616 | if (ret2) { | ||
2617 | printk(KERN_ERR PFX "Couldn't close %s port %d " | ||
2618 | "for agents\n", | ||
2619 | device->name, cur_port); | ||
2620 | } | ||
2621 | ret2 = ib_mad_port_close(device, cur_port); | ||
2622 | if (ret2) { | ||
2623 | printk(KERN_ERR PFX "Couldn't close %s port %d\n", | ||
2624 | device->name, cur_port); | ||
2625 | } | ||
2626 | i--; | ||
2627 | } | ||
2628 | |||
2629 | error_device_query: | ||
2630 | return; | ||
2631 | } | ||
2632 | |||
2633 | static void ib_mad_remove_device(struct ib_device *device) | ||
2634 | { | ||
2635 | int ret = 0, i, num_ports, cur_port, ret2; | ||
2636 | |||
2637 | if (device->node_type == IB_NODE_SWITCH) { | ||
2638 | num_ports = 1; | ||
2639 | cur_port = 0; | ||
2640 | } else { | ||
2641 | num_ports = device->phys_port_cnt; | ||
2642 | cur_port = 1; | ||
2643 | } | ||
2644 | for (i = 0; i < num_ports; i++, cur_port++) { | ||
2645 | ret2 = ib_agent_port_close(device, cur_port); | ||
2646 | if (ret2) { | ||
2647 | printk(KERN_ERR PFX "Couldn't close %s port %d " | ||
2648 | "for agents\n", | ||
2649 | device->name, cur_port); | ||
2650 | if (!ret) | ||
2651 | ret = ret2; | ||
2652 | } | ||
2653 | ret2 = ib_mad_port_close(device, cur_port); | ||
2654 | if (ret2) { | ||
2655 | printk(KERN_ERR PFX "Couldn't close %s port %d\n", | ||
2656 | device->name, cur_port); | ||
2657 | if (!ret) | ||
2658 | ret = ret2; | ||
2659 | } | ||
2660 | } | ||
2661 | } | ||
2662 | |||
2663 | static struct ib_client mad_client = { | ||
2664 | .name = "mad", | ||
2665 | .add = ib_mad_init_device, | ||
2666 | .remove = ib_mad_remove_device | ||
2667 | }; | ||
2668 | |||
2669 | static int __init ib_mad_init_module(void) | ||
2670 | { | ||
2671 | int ret; | ||
2672 | |||
2673 | spin_lock_init(&ib_mad_port_list_lock); | ||
2674 | spin_lock_init(&ib_agent_port_list_lock); | ||
2675 | |||
2676 | ib_mad_cache = kmem_cache_create("ib_mad", | ||
2677 | sizeof(struct ib_mad_private), | ||
2678 | 0, | ||
2679 | SLAB_HWCACHE_ALIGN, | ||
2680 | NULL, | ||
2681 | NULL); | ||
2682 | if (!ib_mad_cache) { | ||
2683 | printk(KERN_ERR PFX "Couldn't create ib_mad cache\n"); | ||
2684 | ret = -ENOMEM; | ||
2685 | goto error1; | ||
2686 | } | ||
2687 | |||
2688 | INIT_LIST_HEAD(&ib_mad_port_list); | ||
2689 | |||
2690 | if (ib_register_client(&mad_client)) { | ||
2691 | printk(KERN_ERR PFX "Couldn't register ib_mad client\n"); | ||
2692 | ret = -EINVAL; | ||
2693 | goto error2; | ||
2694 | } | ||
2695 | |||
2696 | return 0; | ||
2697 | |||
2698 | error2: | ||
2699 | kmem_cache_destroy(ib_mad_cache); | ||
2700 | error1: | ||
2701 | return ret; | ||
2702 | } | ||
2703 | |||
2704 | static void __exit ib_mad_cleanup_module(void) | ||
2705 | { | ||
2706 | ib_unregister_client(&mad_client); | ||
2707 | |||
2708 | if (kmem_cache_destroy(ib_mad_cache)) { | ||
2709 | printk(KERN_DEBUG PFX "Failed to destroy ib_mad cache\n"); | ||
2710 | } | ||
2711 | } | ||
2712 | |||
2713 | module_init(ib_mad_init_module); | ||
2714 | module_exit(ib_mad_cleanup_module); | ||
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h new file mode 100644 index 000000000000..4ba9f726bf1d --- /dev/null +++ b/drivers/infiniband/core/mad_priv.h | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004, 2005, Voltaire, Inc. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | * $Id: mad_priv.h 1389 2004-12-27 22:56:47Z roland $ | ||
33 | */ | ||
34 | |||
35 | #ifndef __IB_MAD_PRIV_H__ | ||
36 | #define __IB_MAD_PRIV_H__ | ||
37 | |||
38 | #include <linux/pci.h> | ||
39 | #include <linux/kthread.h> | ||
40 | #include <linux/workqueue.h> | ||
41 | #include <ib_mad.h> | ||
42 | #include <ib_smi.h> | ||
43 | |||
44 | |||
45 | #define PFX "ib_mad: " | ||
46 | |||
47 | #define IB_MAD_QPS_CORE 2 /* Always QP0 and QP1 as a minimum */ | ||
48 | |||
49 | /* QP and CQ parameters */ | ||
50 | #define IB_MAD_QP_SEND_SIZE 128 | ||
51 | #define IB_MAD_QP_RECV_SIZE 512 | ||
52 | #define IB_MAD_SEND_REQ_MAX_SG 2 | ||
53 | #define IB_MAD_RECV_REQ_MAX_SG 1 | ||
54 | |||
55 | #define IB_MAD_SEND_Q_PSN 0 | ||
56 | |||
57 | /* Registration table sizes */ | ||
58 | #define MAX_MGMT_CLASS 80 | ||
59 | #define MAX_MGMT_VERSION 8 | ||
60 | #define MAX_MGMT_OUI 8 | ||
61 | #define MAX_MGMT_VENDOR_RANGE2 (IB_MGMT_CLASS_VENDOR_RANGE2_END - \ | ||
62 | IB_MGMT_CLASS_VENDOR_RANGE2_START + 1) | ||
63 | |||
64 | struct ib_mad_list_head { | ||
65 | struct list_head list; | ||
66 | struct ib_mad_queue *mad_queue; | ||
67 | }; | ||
68 | |||
69 | struct ib_mad_private_header { | ||
70 | struct ib_mad_list_head mad_list; | ||
71 | struct ib_mad_recv_wc recv_wc; | ||
72 | DECLARE_PCI_UNMAP_ADDR(mapping) | ||
73 | } __attribute__ ((packed)); | ||
74 | |||
75 | struct ib_mad_private { | ||
76 | struct ib_mad_private_header header; | ||
77 | struct ib_grh grh; | ||
78 | union { | ||
79 | struct ib_mad mad; | ||
80 | struct ib_rmpp_mad rmpp_mad; | ||
81 | struct ib_smp smp; | ||
82 | } mad; | ||
83 | } __attribute__ ((packed)); | ||
84 | |||
85 | struct ib_mad_agent_private { | ||
86 | struct list_head agent_list; | ||
87 | struct ib_mad_agent agent; | ||
88 | struct ib_mad_reg_req *reg_req; | ||
89 | struct ib_mad_qp_info *qp_info; | ||
90 | |||
91 | spinlock_t lock; | ||
92 | struct list_head send_list; | ||
93 | struct list_head wait_list; | ||
94 | struct work_struct timed_work; | ||
95 | unsigned long timeout; | ||
96 | struct list_head local_list; | ||
97 | struct work_struct local_work; | ||
98 | struct list_head canceled_list; | ||
99 | struct work_struct canceled_work; | ||
100 | |||
101 | atomic_t refcount; | ||
102 | wait_queue_head_t wait; | ||
103 | u8 rmpp_version; | ||
104 | }; | ||
105 | |||
106 | struct ib_mad_snoop_private { | ||
107 | struct ib_mad_agent agent; | ||
108 | struct ib_mad_qp_info *qp_info; | ||
109 | int snoop_index; | ||
110 | int mad_snoop_flags; | ||
111 | atomic_t refcount; | ||
112 | wait_queue_head_t wait; | ||
113 | }; | ||
114 | |||
115 | struct ib_mad_send_wr_private { | ||
116 | struct ib_mad_list_head mad_list; | ||
117 | struct list_head agent_list; | ||
118 | struct ib_mad_agent *agent; | ||
119 | struct ib_send_wr send_wr; | ||
120 | struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG]; | ||
121 | u64 wr_id; /* client WR ID */ | ||
122 | u64 tid; | ||
123 | unsigned long timeout; | ||
124 | int retry; | ||
125 | int refcount; | ||
126 | enum ib_wc_status status; | ||
127 | }; | ||
128 | |||
129 | struct ib_mad_local_private { | ||
130 | struct list_head completion_list; | ||
131 | struct ib_mad_private *mad_priv; | ||
132 | struct ib_mad_agent_private *recv_mad_agent; | ||
133 | struct ib_send_wr send_wr; | ||
134 | struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG]; | ||
135 | u64 wr_id; /* client WR ID */ | ||
136 | u64 tid; | ||
137 | }; | ||
138 | |||
139 | struct ib_mad_mgmt_method_table { | ||
140 | struct ib_mad_agent_private *agent[IB_MGMT_MAX_METHODS]; | ||
141 | }; | ||
142 | |||
143 | struct ib_mad_mgmt_class_table { | ||
144 | struct ib_mad_mgmt_method_table *method_table[MAX_MGMT_CLASS]; | ||
145 | }; | ||
146 | |||
147 | struct ib_mad_mgmt_vendor_class { | ||
148 | u8 oui[MAX_MGMT_OUI][3]; | ||
149 | struct ib_mad_mgmt_method_table *method_table[MAX_MGMT_OUI]; | ||
150 | }; | ||
151 | |||
152 | struct ib_mad_mgmt_vendor_class_table { | ||
153 | struct ib_mad_mgmt_vendor_class *vendor_class[MAX_MGMT_VENDOR_RANGE2]; | ||
154 | }; | ||
155 | |||
156 | struct ib_mad_mgmt_version_table { | ||
157 | struct ib_mad_mgmt_class_table *class; | ||
158 | struct ib_mad_mgmt_vendor_class_table *vendor; | ||
159 | }; | ||
160 | |||
161 | struct ib_mad_queue { | ||
162 | spinlock_t lock; | ||
163 | struct list_head list; | ||
164 | int count; | ||
165 | int max_active; | ||
166 | struct ib_mad_qp_info *qp_info; | ||
167 | }; | ||
168 | |||
169 | struct ib_mad_qp_info { | ||
170 | struct ib_mad_port_private *port_priv; | ||
171 | struct ib_qp *qp; | ||
172 | struct ib_mad_queue send_queue; | ||
173 | struct ib_mad_queue recv_queue; | ||
174 | struct list_head overflow_list; | ||
175 | spinlock_t snoop_lock; | ||
176 | struct ib_mad_snoop_private **snoop_table; | ||
177 | int snoop_table_size; | ||
178 | atomic_t snoop_count; | ||
179 | }; | ||
180 | |||
181 | struct ib_mad_port_private { | ||
182 | struct list_head port_list; | ||
183 | struct ib_device *device; | ||
184 | int port_num; | ||
185 | struct ib_cq *cq; | ||
186 | struct ib_pd *pd; | ||
187 | struct ib_mr *mr; | ||
188 | |||
189 | spinlock_t reg_lock; | ||
190 | struct ib_mad_mgmt_version_table version[MAX_MGMT_VERSION]; | ||
191 | struct list_head agent_list; | ||
192 | struct workqueue_struct *wq; | ||
193 | struct work_struct work; | ||
194 | struct ib_mad_qp_info qp_info[IB_MAD_QPS_CORE]; | ||
195 | }; | ||
196 | |||
197 | extern kmem_cache_t *ib_mad_cache; | ||
198 | |||
199 | #endif /* __IB_MAD_PRIV_H__ */ | ||
diff --git a/drivers/infiniband/core/packer.c b/drivers/infiniband/core/packer.c new file mode 100644 index 000000000000..5f15feffeae2 --- /dev/null +++ b/drivers/infiniband/core/packer.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Topspin Corporation. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | * $Id: packer.c 1349 2004-12-16 21:09:43Z roland $ | ||
33 | */ | ||
34 | |||
35 | #include <ib_pack.h> | ||
36 | |||
37 | static u64 value_read(int offset, int size, void *structure) | ||
38 | { | ||
39 | switch (size) { | ||
40 | case 1: return *(u8 *) (structure + offset); | ||
41 | case 2: return be16_to_cpup((__be16 *) (structure + offset)); | ||
42 | case 4: return be32_to_cpup((__be32 *) (structure + offset)); | ||
43 | case 8: return be64_to_cpup((__be64 *) (structure + offset)); | ||
44 | default: | ||
45 | printk(KERN_WARNING "Field size %d bits not handled\n", size * 8); | ||
46 | return 0; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * ib_pack - Pack a structure into a buffer | ||
52 | * @desc:Array of structure field descriptions | ||
53 | * @desc_len:Number of entries in @desc | ||
54 | * @structure:Structure to pack from | ||
55 | * @buf:Buffer to pack into | ||
56 | * | ||
57 | * ib_pack() packs a list of structure fields into a buffer, | ||
58 | * controlled by the array of fields in @desc. | ||
59 | */ | ||
60 | void ib_pack(const struct ib_field *desc, | ||
61 | int desc_len, | ||
62 | void *structure, | ||
63 | void *buf) | ||
64 | { | ||
65 | int i; | ||
66 | |||
67 | for (i = 0; i < desc_len; ++i) { | ||
68 | if (desc[i].size_bits <= 32) { | ||
69 | int shift; | ||
70 | u32 val; | ||
71 | __be32 mask; | ||
72 | __be32 *addr; | ||
73 | |||
74 | shift = 32 - desc[i].offset_bits - desc[i].size_bits; | ||
75 | if (desc[i].struct_size_bytes) | ||
76 | val = value_read(desc[i].struct_offset_bytes, | ||
77 | desc[i].struct_size_bytes, | ||
78 | structure) << shift; | ||
79 | else | ||
80 | val = 0; | ||
81 | |||
82 | mask = cpu_to_be32(((1ull << desc[i].size_bits) - 1) << shift); | ||
83 | addr = (__be32 *) buf + desc[i].offset_words; | ||
84 | *addr = (*addr & ~mask) | (cpu_to_be32(val) & mask); | ||
85 | } else if (desc[i].size_bits <= 64) { | ||
86 | int shift; | ||
87 | u64 val; | ||
88 | __be64 mask; | ||
89 | __be64 *addr; | ||
90 | |||
91 | shift = 64 - desc[i].offset_bits - desc[i].size_bits; | ||
92 | if (desc[i].struct_size_bytes) | ||
93 | val = value_read(desc[i].struct_offset_bytes, | ||
94 | desc[i].struct_size_bytes, | ||
95 | structure) << shift; | ||
96 | else | ||
97 | val = 0; | ||
98 | |||
99 | mask = cpu_to_be64(((1ull << desc[i].size_bits) - 1) << shift); | ||
100 | addr = (__be64 *) ((__be32 *) buf + desc[i].offset_words); | ||
101 | *addr = (*addr & ~mask) | (cpu_to_be64(val) & mask); | ||
102 | } else { | ||
103 | if (desc[i].offset_bits % 8 || | ||
104 | desc[i].size_bits % 8) { | ||
105 | printk(KERN_WARNING "Structure field %s of size %d " | ||
106 | "bits is not byte-aligned\n", | ||
107 | desc[i].field_name, desc[i].size_bits); | ||
108 | } | ||
109 | |||
110 | if (desc[i].struct_size_bytes) | ||
111 | memcpy(buf + desc[i].offset_words * 4 + | ||
112 | desc[i].offset_bits / 8, | ||
113 | structure + desc[i].struct_offset_bytes, | ||
114 | desc[i].size_bits / 8); | ||
115 | else | ||
116 | memset(buf + desc[i].offset_words * 4 + | ||
117 | desc[i].offset_bits / 8, | ||
118 | 0, | ||
119 | desc[i].size_bits / 8); | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | EXPORT_SYMBOL(ib_pack); | ||
124 | |||
125 | static void value_write(int offset, int size, u64 val, void *structure) | ||
126 | { | ||
127 | switch (size * 8) { | ||
128 | case 8: *( u8 *) (structure + offset) = val; break; | ||
129 | case 16: *(__be16 *) (structure + offset) = cpu_to_be16(val); break; | ||
130 | case 32: *(__be32 *) (structure + offset) = cpu_to_be32(val); break; | ||
131 | case 64: *(__be64 *) (structure + offset) = cpu_to_be64(val); break; | ||
132 | default: | ||
133 | printk(KERN_WARNING "Field size %d bits not handled\n", size * 8); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /** | ||
138 | * ib_unpack - Unpack a buffer into a structure | ||
139 | * @desc:Array of structure field descriptions | ||
140 | * @desc_len:Number of entries in @desc | ||
141 | * @buf:Buffer to unpack from | ||
142 | * @structure:Structure to unpack into | ||
143 | * | ||
144 | * ib_pack() unpacks a list of structure fields from a buffer, | ||
145 | * controlled by the array of fields in @desc. | ||
146 | */ | ||
147 | void ib_unpack(const struct ib_field *desc, | ||
148 | int desc_len, | ||
149 | void *buf, | ||
150 | void *structure) | ||
151 | { | ||
152 | int i; | ||
153 | |||
154 | for (i = 0; i < desc_len; ++i) { | ||
155 | if (!desc[i].struct_size_bytes) | ||
156 | continue; | ||
157 | |||
158 | if (desc[i].size_bits <= 32) { | ||
159 | int shift; | ||
160 | u32 val; | ||
161 | u32 mask; | ||
162 | __be32 *addr; | ||
163 | |||
164 | shift = 32 - desc[i].offset_bits - desc[i].size_bits; | ||
165 | mask = ((1ull << desc[i].size_bits) - 1) << shift; | ||
166 | addr = (__be32 *) buf + desc[i].offset_words; | ||
167 | val = (be32_to_cpup(addr) & mask) >> shift; | ||
168 | value_write(desc[i].struct_offset_bytes, | ||
169 | desc[i].struct_size_bytes, | ||
170 | val, | ||
171 | structure); | ||
172 | } else if (desc[i].size_bits <= 64) { | ||
173 | int shift; | ||
174 | u64 val; | ||
175 | u64 mask; | ||
176 | __be64 *addr; | ||
177 | |||
178 | shift = 64 - desc[i].offset_bits - desc[i].size_bits; | ||
179 | mask = ((1ull << desc[i].size_bits) - 1) << shift; | ||
180 | addr = (__be64 *) buf + desc[i].offset_words; | ||
181 | val = (be64_to_cpup(addr) & mask) >> shift; | ||
182 | value_write(desc[i].struct_offset_bytes, | ||
183 | desc[i].struct_size_bytes, | ||
184 | val, | ||
185 | structure); | ||
186 | } else { | ||
187 | if (desc[i].offset_bits % 8 || | ||
188 | desc[i].size_bits % 8) { | ||
189 | printk(KERN_WARNING "Structure field %s of size %d " | ||
190 | "bits is not byte-aligned\n", | ||
191 | desc[i].field_name, desc[i].size_bits); | ||
192 | } | ||
193 | |||
194 | memcpy(structure + desc[i].struct_offset_bytes, | ||
195 | buf + desc[i].offset_words * 4 + | ||
196 | desc[i].offset_bits / 8, | ||
197 | desc[i].size_bits / 8); | ||
198 | } | ||
199 | } | ||
200 | } | ||
201 | EXPORT_SYMBOL(ib_unpack); | ||
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c new file mode 100644 index 000000000000..d4233ee61c35 --- /dev/null +++ b/drivers/infiniband/core/sa_query.c | |||
@@ -0,0 +1,866 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | * $Id: sa_query.c 1389 2004-12-27 22:56:47Z roland $ | ||
33 | */ | ||
34 | |||
35 | #include <linux/module.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/err.h> | ||
38 | #include <linux/random.h> | ||
39 | #include <linux/spinlock.h> | ||
40 | #include <linux/slab.h> | ||
41 | #include <linux/pci.h> | ||
42 | #include <linux/dma-mapping.h> | ||
43 | #include <linux/kref.h> | ||
44 | #include <linux/idr.h> | ||
45 | |||
46 | #include <ib_pack.h> | ||
47 | #include <ib_sa.h> | ||
48 | |||
49 | MODULE_AUTHOR("Roland Dreier"); | ||
50 | MODULE_DESCRIPTION("InfiniBand subnet administration query support"); | ||
51 | MODULE_LICENSE("Dual BSD/GPL"); | ||
52 | |||
53 | /* | ||
54 | * These two structures must be packed because they have 64-bit fields | ||
55 | * that are only 32-bit aligned. 64-bit architectures will lay them | ||
56 | * out wrong otherwise. (And unfortunately they are sent on the wire | ||
57 | * so we can't change the layout) | ||
58 | */ | ||
59 | struct ib_sa_hdr { | ||
60 | u64 sm_key; | ||
61 | u16 attr_offset; | ||
62 | u16 reserved; | ||
63 | ib_sa_comp_mask comp_mask; | ||
64 | } __attribute__ ((packed)); | ||
65 | |||
66 | struct ib_sa_mad { | ||
67 | struct ib_mad_hdr mad_hdr; | ||
68 | struct ib_rmpp_hdr rmpp_hdr; | ||
69 | struct ib_sa_hdr sa_hdr; | ||
70 | u8 data[200]; | ||
71 | } __attribute__ ((packed)); | ||
72 | |||
73 | struct ib_sa_sm_ah { | ||
74 | struct ib_ah *ah; | ||
75 | struct kref ref; | ||
76 | }; | ||
77 | |||
78 | struct ib_sa_port { | ||
79 | struct ib_mad_agent *agent; | ||
80 | struct ib_mr *mr; | ||
81 | struct ib_sa_sm_ah *sm_ah; | ||
82 | struct work_struct update_task; | ||
83 | spinlock_t ah_lock; | ||
84 | u8 port_num; | ||
85 | }; | ||
86 | |||
87 | struct ib_sa_device { | ||
88 | int start_port, end_port; | ||
89 | struct ib_event_handler event_handler; | ||
90 | struct ib_sa_port port[0]; | ||
91 | }; | ||
92 | |||
93 | struct ib_sa_query { | ||
94 | void (*callback)(struct ib_sa_query *, int, struct ib_sa_mad *); | ||
95 | void (*release)(struct ib_sa_query *); | ||
96 | struct ib_sa_port *port; | ||
97 | struct ib_sa_mad *mad; | ||
98 | struct ib_sa_sm_ah *sm_ah; | ||
99 | DECLARE_PCI_UNMAP_ADDR(mapping) | ||
100 | int id; | ||
101 | }; | ||
102 | |||
103 | struct ib_sa_path_query { | ||
104 | void (*callback)(int, struct ib_sa_path_rec *, void *); | ||
105 | void *context; | ||
106 | struct ib_sa_query sa_query; | ||
107 | }; | ||
108 | |||
109 | struct ib_sa_mcmember_query { | ||
110 | void (*callback)(int, struct ib_sa_mcmember_rec *, void *); | ||
111 | void *context; | ||
112 | struct ib_sa_query sa_query; | ||
113 | }; | ||
114 | |||
115 | static void ib_sa_add_one(struct ib_device *device); | ||
116 | static void ib_sa_remove_one(struct ib_device *device); | ||
117 | |||
118 | static struct ib_client sa_client = { | ||
119 | .name = "sa", | ||
120 | .add = ib_sa_add_one, | ||
121 | .remove = ib_sa_remove_one | ||
122 | }; | ||
123 | |||
124 | static spinlock_t idr_lock; | ||
125 | static DEFINE_IDR(query_idr); | ||
126 | |||
127 | static spinlock_t tid_lock; | ||
128 | static u32 tid; | ||
129 | |||
130 | enum { | ||
131 | IB_SA_ATTR_CLASS_PORTINFO = 0x01, | ||
132 | IB_SA_ATTR_NOTICE = 0x02, | ||
133 | IB_SA_ATTR_INFORM_INFO = 0x03, | ||
134 | IB_SA_ATTR_NODE_REC = 0x11, | ||
135 | IB_SA_ATTR_PORT_INFO_REC = 0x12, | ||
136 | IB_SA_ATTR_SL2VL_REC = 0x13, | ||
137 | IB_SA_ATTR_SWITCH_REC = 0x14, | ||
138 | IB_SA_ATTR_LINEAR_FDB_REC = 0x15, | ||
139 | IB_SA_ATTR_RANDOM_FDB_REC = 0x16, | ||
140 | IB_SA_ATTR_MCAST_FDB_REC = 0x17, | ||
141 | IB_SA_ATTR_SM_INFO_REC = 0x18, | ||
142 | IB_SA_ATTR_LINK_REC = 0x20, | ||
143 | IB_SA_ATTR_GUID_INFO_REC = 0x30, | ||
144 | IB_SA_ATTR_SERVICE_REC = 0x31, | ||
145 | IB_SA_ATTR_PARTITION_REC = 0x33, | ||
146 | IB_SA_ATTR_RANGE_REC = 0x34, | ||
147 | IB_SA_ATTR_PATH_REC = 0x35, | ||
148 | IB_SA_ATTR_VL_ARB_REC = 0x36, | ||
149 | IB_SA_ATTR_MC_GROUP_REC = 0x37, | ||
150 | IB_SA_ATTR_MC_MEMBER_REC = 0x38, | ||
151 | IB_SA_ATTR_TRACE_REC = 0x39, | ||
152 | IB_SA_ATTR_MULTI_PATH_REC = 0x3a, | ||
153 | IB_SA_ATTR_SERVICE_ASSOC_REC = 0x3b | ||
154 | }; | ||
155 | |||
156 | #define PATH_REC_FIELD(field) \ | ||
157 | .struct_offset_bytes = offsetof(struct ib_sa_path_rec, field), \ | ||
158 | .struct_size_bytes = sizeof ((struct ib_sa_path_rec *) 0)->field, \ | ||
159 | .field_name = "sa_path_rec:" #field | ||
160 | |||
161 | static const struct ib_field path_rec_table[] = { | ||
162 | { RESERVED, | ||
163 | .offset_words = 0, | ||
164 | .offset_bits = 0, | ||
165 | .size_bits = 32 }, | ||
166 | { RESERVED, | ||
167 | .offset_words = 1, | ||
168 | .offset_bits = 0, | ||
169 | .size_bits = 32 }, | ||
170 | { PATH_REC_FIELD(dgid), | ||
171 | .offset_words = 2, | ||
172 | .offset_bits = 0, | ||
173 | .size_bits = 128 }, | ||
174 | { PATH_REC_FIELD(sgid), | ||
175 | .offset_words = 6, | ||
176 | .offset_bits = 0, | ||
177 | .size_bits = 128 }, | ||
178 | { PATH_REC_FIELD(dlid), | ||
179 | .offset_words = 10, | ||
180 | .offset_bits = 0, | ||
181 | .size_bits = 16 }, | ||
182 | { PATH_REC_FIELD(slid), | ||
183 | .offset_words = 10, | ||
184 | .offset_bits = 16, | ||
185 | .size_bits = 16 }, | ||
186 | { PATH_REC_FIELD(raw_traffic), | ||
187 | .offset_words = 11, | ||
188 | .offset_bits = 0, | ||
189 | .size_bits = 1 }, | ||
190 | { RESERVED, | ||
191 | .offset_words = 11, | ||
192 | .offset_bits = 1, | ||
193 | .size_bits = 3 }, | ||
194 | { PATH_REC_FIELD(flow_label), | ||
195 | .offset_words = 11, | ||
196 | .offset_bits = 4, | ||
197 | .size_bits = 20 }, | ||
198 | { PATH_REC_FIELD(hop_limit), | ||
199 | .offset_words = 11, | ||
200 | .offset_bits = 24, | ||
201 | .size_bits = 8 }, | ||
202 | { PATH_REC_FIELD(traffic_class), | ||
203 | .offset_words = 12, | ||
204 | .offset_bits = 0, | ||
205 | .size_bits = 8 }, | ||
206 | { PATH_REC_FIELD(reversible), | ||
207 | .offset_words = 12, | ||
208 | .offset_bits = 8, | ||
209 | .size_bits = 1 }, | ||
210 | { PATH_REC_FIELD(numb_path), | ||
211 | .offset_words = 12, | ||
212 | .offset_bits = 9, | ||
213 | .size_bits = 7 }, | ||
214 | { PATH_REC_FIELD(pkey), | ||
215 | .offset_words = 12, | ||
216 | .offset_bits = 16, | ||
217 | .size_bits = 16 }, | ||
218 | { RESERVED, | ||
219 | .offset_words = 13, | ||
220 | .offset_bits = 0, | ||
221 | .size_bits = 12 }, | ||
222 | { PATH_REC_FIELD(sl), | ||
223 | .offset_words = 13, | ||
224 | .offset_bits = 12, | ||
225 | .size_bits = 4 }, | ||
226 | { PATH_REC_FIELD(mtu_selector), | ||
227 | .offset_words = 13, | ||
228 | .offset_bits = 16, | ||
229 | .size_bits = 2 }, | ||
230 | { PATH_REC_FIELD(mtu), | ||
231 | .offset_words = 13, | ||
232 | .offset_bits = 18, | ||
233 | .size_bits = 6 }, | ||
234 | { PATH_REC_FIELD(rate_selector), | ||
235 | .offset_words = 13, | ||
236 | .offset_bits = 24, | ||
237 | .size_bits = 2 }, | ||
238 | { PATH_REC_FIELD(rate), | ||
239 | .offset_words = 13, | ||
240 | .offset_bits = 26, | ||
241 | .size_bits = 6 }, | ||
242 | { PATH_REC_FIELD(packet_life_time_selector), | ||
243 | .offset_words = 14, | ||
244 | .offset_bits = 0, | ||
245 | .size_bits = 2 }, | ||
246 | { PATH_REC_FIELD(packet_life_time), | ||
247 | .offset_words = 14, | ||
248 | .offset_bits = 2, | ||
249 | .size_bits = 6 }, | ||
250 | { PATH_REC_FIELD(preference), | ||
251 | .offset_words = 14, | ||
252 | .offset_bits = 8, | ||
253 | .size_bits = 8 }, | ||
254 | { RESERVED, | ||
255 | .offset_words = 14, | ||
256 | .offset_bits = 16, | ||
257 | .size_bits = 48 }, | ||
258 | }; | ||
259 | |||
260 | #define MCMEMBER_REC_FIELD(field) \ | ||
261 | .struct_offset_bytes = offsetof(struct ib_sa_mcmember_rec, field), \ | ||
262 | .struct_size_bytes = sizeof ((struct ib_sa_mcmember_rec *) 0)->field, \ | ||
263 | .field_name = "sa_mcmember_rec:" #field | ||
264 | |||
265 | static const struct ib_field mcmember_rec_table[] = { | ||
266 | { MCMEMBER_REC_FIELD(mgid), | ||
267 | .offset_words = 0, | ||
268 | .offset_bits = 0, | ||
269 | .size_bits = 128 }, | ||
270 | { MCMEMBER_REC_FIELD(port_gid), | ||
271 | .offset_words = 4, | ||
272 | .offset_bits = 0, | ||
273 | .size_bits = 128 }, | ||
274 | { MCMEMBER_REC_FIELD(qkey), | ||
275 | .offset_words = 8, | ||
276 | .offset_bits = 0, | ||
277 | .size_bits = 32 }, | ||
278 | { MCMEMBER_REC_FIELD(mlid), | ||
279 | .offset_words = 9, | ||
280 | .offset_bits = 0, | ||
281 | .size_bits = 16 }, | ||
282 | { MCMEMBER_REC_FIELD(mtu_selector), | ||
283 | .offset_words = 9, | ||
284 | .offset_bits = 16, | ||
285 | .size_bits = 2 }, | ||
286 | { MCMEMBER_REC_FIELD(mtu), | ||
287 | .offset_words = 9, | ||
288 | .offset_bits = 18, | ||
289 | .size_bits = 6 }, | ||
290 | { MCMEMBER_REC_FIELD(traffic_class), | ||
291 | .offset_words = 9, | ||
292 | .offset_bits = 24, | ||
293 | .size_bits = 8 }, | ||
294 | { MCMEMBER_REC_FIELD(pkey), | ||
295 | .offset_words = 10, | ||
296 | .offset_bits = 0, | ||
297 | .size_bits = 16 }, | ||
298 | { MCMEMBER_REC_FIELD(rate_selector), | ||
299 | .offset_words = 10, | ||
300 | .offset_bits = 16, | ||
301 | .size_bits = 2 }, | ||
302 | { MCMEMBER_REC_FIELD(rate), | ||
303 | .offset_words = 10, | ||
304 | .offset_bits = 18, | ||
305 | .size_bits = 6 }, | ||
306 | { MCMEMBER_REC_FIELD(packet_life_time_selector), | ||
307 | .offset_words = 10, | ||
308 | .offset_bits = 24, | ||
309 | .size_bits = 2 }, | ||
310 | { MCMEMBER_REC_FIELD(packet_life_time), | ||
311 | .offset_words = 10, | ||
312 | .offset_bits = 26, | ||
313 | .size_bits = 6 }, | ||
314 | { MCMEMBER_REC_FIELD(sl), | ||
315 | .offset_words = 11, | ||
316 | .offset_bits = 0, | ||
317 | .size_bits = 4 }, | ||
318 | { MCMEMBER_REC_FIELD(flow_label), | ||
319 | .offset_words = 11, | ||
320 | .offset_bits = 4, | ||
321 | .size_bits = 20 }, | ||
322 | { MCMEMBER_REC_FIELD(hop_limit), | ||
323 | .offset_words = 11, | ||
324 | .offset_bits = 24, | ||
325 | .size_bits = 8 }, | ||
326 | { MCMEMBER_REC_FIELD(scope), | ||
327 | .offset_words = 12, | ||
328 | .offset_bits = 0, | ||
329 | .size_bits = 4 }, | ||
330 | { MCMEMBER_REC_FIELD(join_state), | ||
331 | .offset_words = 12, | ||
332 | .offset_bits = 4, | ||
333 | .size_bits = 4 }, | ||
334 | { MCMEMBER_REC_FIELD(proxy_join), | ||
335 | .offset_words = 12, | ||
336 | .offset_bits = 8, | ||
337 | .size_bits = 1 }, | ||
338 | { RESERVED, | ||
339 | .offset_words = 12, | ||
340 | .offset_bits = 9, | ||
341 | .size_bits = 23 }, | ||
342 | }; | ||
343 | |||
344 | static void free_sm_ah(struct kref *kref) | ||
345 | { | ||
346 | struct ib_sa_sm_ah *sm_ah = container_of(kref, struct ib_sa_sm_ah, ref); | ||
347 | |||
348 | ib_destroy_ah(sm_ah->ah); | ||
349 | kfree(sm_ah); | ||
350 | } | ||
351 | |||
352 | static void update_sm_ah(void *port_ptr) | ||
353 | { | ||
354 | struct ib_sa_port *port = port_ptr; | ||
355 | struct ib_sa_sm_ah *new_ah, *old_ah; | ||
356 | struct ib_port_attr port_attr; | ||
357 | struct ib_ah_attr ah_attr; | ||
358 | |||
359 | if (ib_query_port(port->agent->device, port->port_num, &port_attr)) { | ||
360 | printk(KERN_WARNING "Couldn't query port\n"); | ||
361 | return; | ||
362 | } | ||
363 | |||
364 | new_ah = kmalloc(sizeof *new_ah, GFP_KERNEL); | ||
365 | if (!new_ah) { | ||
366 | printk(KERN_WARNING "Couldn't allocate new SM AH\n"); | ||
367 | return; | ||
368 | } | ||
369 | |||
370 | kref_init(&new_ah->ref); | ||
371 | |||
372 | memset(&ah_attr, 0, sizeof ah_attr); | ||
373 | ah_attr.dlid = port_attr.sm_lid; | ||
374 | ah_attr.sl = port_attr.sm_sl; | ||
375 | ah_attr.port_num = port->port_num; | ||
376 | |||
377 | new_ah->ah = ib_create_ah(port->agent->qp->pd, &ah_attr); | ||
378 | if (IS_ERR(new_ah->ah)) { | ||
379 | printk(KERN_WARNING "Couldn't create new SM AH\n"); | ||
380 | kfree(new_ah); | ||
381 | return; | ||
382 | } | ||
383 | |||
384 | spin_lock_irq(&port->ah_lock); | ||
385 | old_ah = port->sm_ah; | ||
386 | port->sm_ah = new_ah; | ||
387 | spin_unlock_irq(&port->ah_lock); | ||
388 | |||
389 | if (old_ah) | ||
390 | kref_put(&old_ah->ref, free_sm_ah); | ||
391 | } | ||
392 | |||
393 | static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event) | ||
394 | { | ||
395 | if (event->event == IB_EVENT_PORT_ERR || | ||
396 | event->event == IB_EVENT_PORT_ACTIVE || | ||
397 | event->event == IB_EVENT_LID_CHANGE || | ||
398 | event->event == IB_EVENT_PKEY_CHANGE || | ||
399 | event->event == IB_EVENT_SM_CHANGE) { | ||
400 | struct ib_sa_device *sa_dev = | ||
401 | ib_get_client_data(event->device, &sa_client); | ||
402 | |||
403 | schedule_work(&sa_dev->port[event->element.port_num - | ||
404 | sa_dev->start_port].update_task); | ||
405 | } | ||
406 | } | ||
407 | |||
408 | /** | ||
409 | * ib_sa_cancel_query - try to cancel an SA query | ||
410 | * @id:ID of query to cancel | ||
411 | * @query:query pointer to cancel | ||
412 | * | ||
413 | * Try to cancel an SA query. If the id and query don't match up or | ||
414 | * the query has already completed, nothing is done. Otherwise the | ||
415 | * query is canceled and will complete with a status of -EINTR. | ||
416 | */ | ||
417 | void ib_sa_cancel_query(int id, struct ib_sa_query *query) | ||
418 | { | ||
419 | unsigned long flags; | ||
420 | struct ib_mad_agent *agent; | ||
421 | |||
422 | spin_lock_irqsave(&idr_lock, flags); | ||
423 | if (idr_find(&query_idr, id) != query) { | ||
424 | spin_unlock_irqrestore(&idr_lock, flags); | ||
425 | return; | ||
426 | } | ||
427 | agent = query->port->agent; | ||
428 | spin_unlock_irqrestore(&idr_lock, flags); | ||
429 | |||
430 | ib_cancel_mad(agent, id); | ||
431 | } | ||
432 | EXPORT_SYMBOL(ib_sa_cancel_query); | ||
433 | |||
434 | static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent) | ||
435 | { | ||
436 | unsigned long flags; | ||
437 | |||
438 | memset(mad, 0, sizeof *mad); | ||
439 | |||
440 | mad->mad_hdr.base_version = IB_MGMT_BASE_VERSION; | ||
441 | mad->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM; | ||
442 | mad->mad_hdr.class_version = IB_SA_CLASS_VERSION; | ||
443 | |||
444 | spin_lock_irqsave(&tid_lock, flags); | ||
445 | mad->mad_hdr.tid = | ||
446 | cpu_to_be64(((u64) agent->hi_tid) << 32 | tid++); | ||
447 | spin_unlock_irqrestore(&tid_lock, flags); | ||
448 | } | ||
449 | |||
450 | static int send_mad(struct ib_sa_query *query, int timeout_ms) | ||
451 | { | ||
452 | struct ib_sa_port *port = query->port; | ||
453 | unsigned long flags; | ||
454 | int ret; | ||
455 | struct ib_sge gather_list; | ||
456 | struct ib_send_wr *bad_wr, wr = { | ||
457 | .opcode = IB_WR_SEND, | ||
458 | .sg_list = &gather_list, | ||
459 | .num_sge = 1, | ||
460 | .send_flags = IB_SEND_SIGNALED, | ||
461 | .wr = { | ||
462 | .ud = { | ||
463 | .mad_hdr = &query->mad->mad_hdr, | ||
464 | .remote_qpn = 1, | ||
465 | .remote_qkey = IB_QP1_QKEY, | ||
466 | .timeout_ms = timeout_ms | ||
467 | } | ||
468 | } | ||
469 | }; | ||
470 | |||
471 | retry: | ||
472 | if (!idr_pre_get(&query_idr, GFP_ATOMIC)) | ||
473 | return -ENOMEM; | ||
474 | spin_lock_irqsave(&idr_lock, flags); | ||
475 | ret = idr_get_new(&query_idr, query, &query->id); | ||
476 | spin_unlock_irqrestore(&idr_lock, flags); | ||
477 | if (ret == -EAGAIN) | ||
478 | goto retry; | ||
479 | if (ret) | ||
480 | return ret; | ||
481 | |||
482 | wr.wr_id = query->id; | ||
483 | |||
484 | spin_lock_irqsave(&port->ah_lock, flags); | ||
485 | kref_get(&port->sm_ah->ref); | ||
486 | query->sm_ah = port->sm_ah; | ||
487 | wr.wr.ud.ah = port->sm_ah->ah; | ||
488 | spin_unlock_irqrestore(&port->ah_lock, flags); | ||
489 | |||
490 | gather_list.addr = dma_map_single(port->agent->device->dma_device, | ||
491 | query->mad, | ||
492 | sizeof (struct ib_sa_mad), | ||
493 | DMA_TO_DEVICE); | ||
494 | gather_list.length = sizeof (struct ib_sa_mad); | ||
495 | gather_list.lkey = port->mr->lkey; | ||
496 | pci_unmap_addr_set(query, mapping, gather_list.addr); | ||
497 | |||
498 | ret = ib_post_send_mad(port->agent, &wr, &bad_wr); | ||
499 | if (ret) { | ||
500 | dma_unmap_single(port->agent->device->dma_device, | ||
501 | pci_unmap_addr(query, mapping), | ||
502 | sizeof (struct ib_sa_mad), | ||
503 | DMA_TO_DEVICE); | ||
504 | kref_put(&query->sm_ah->ref, free_sm_ah); | ||
505 | spin_lock_irqsave(&idr_lock, flags); | ||
506 | idr_remove(&query_idr, query->id); | ||
507 | spin_unlock_irqrestore(&idr_lock, flags); | ||
508 | } | ||
509 | |||
510 | return ret; | ||
511 | } | ||
512 | |||
513 | static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query, | ||
514 | int status, | ||
515 | struct ib_sa_mad *mad) | ||
516 | { | ||
517 | struct ib_sa_path_query *query = | ||
518 | container_of(sa_query, struct ib_sa_path_query, sa_query); | ||
519 | |||
520 | if (mad) { | ||
521 | struct ib_sa_path_rec rec; | ||
522 | |||
523 | ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table), | ||
524 | mad->data, &rec); | ||
525 | query->callback(status, &rec, query->context); | ||
526 | } else | ||
527 | query->callback(status, NULL, query->context); | ||
528 | } | ||
529 | |||
530 | static void ib_sa_path_rec_release(struct ib_sa_query *sa_query) | ||
531 | { | ||
532 | kfree(sa_query->mad); | ||
533 | kfree(container_of(sa_query, struct ib_sa_path_query, sa_query)); | ||
534 | } | ||
535 | |||
536 | /** | ||
537 | * ib_sa_path_rec_get - Start a Path get query | ||
538 | * @device:device to send query on | ||
539 | * @port_num: port number to send query on | ||
540 | * @rec:Path Record to send in query | ||
541 | * @comp_mask:component mask to send in query | ||
542 | * @timeout_ms:time to wait for response | ||
543 | * @gfp_mask:GFP mask to use for internal allocations | ||
544 | * @callback:function called when query completes, times out or is | ||
545 | * canceled | ||
546 | * @context:opaque user context passed to callback | ||
547 | * @sa_query:query context, used to cancel query | ||
548 | * | ||
549 | * Send a Path Record Get query to the SA to look up a path. The | ||
550 | * callback function will be called when the query completes (or | ||
551 | * fails); status is 0 for a successful response, -EINTR if the query | ||
552 | * is canceled, -ETIMEDOUT is the query timed out, or -EIO if an error | ||
553 | * occurred sending the query. The resp parameter of the callback is | ||
554 | * only valid if status is 0. | ||
555 | * | ||
556 | * If the return value of ib_sa_path_rec_get() is negative, it is an | ||
557 | * error code. Otherwise it is a query ID that can be used to cancel | ||
558 | * the query. | ||
559 | */ | ||
560 | int ib_sa_path_rec_get(struct ib_device *device, u8 port_num, | ||
561 | struct ib_sa_path_rec *rec, | ||
562 | ib_sa_comp_mask comp_mask, | ||
563 | int timeout_ms, int gfp_mask, | ||
564 | void (*callback)(int status, | ||
565 | struct ib_sa_path_rec *resp, | ||
566 | void *context), | ||
567 | void *context, | ||
568 | struct ib_sa_query **sa_query) | ||
569 | { | ||
570 | struct ib_sa_path_query *query; | ||
571 | struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); | ||
572 | struct ib_sa_port *port = &sa_dev->port[port_num - sa_dev->start_port]; | ||
573 | struct ib_mad_agent *agent = port->agent; | ||
574 | int ret; | ||
575 | |||
576 | query = kmalloc(sizeof *query, gfp_mask); | ||
577 | if (!query) | ||
578 | return -ENOMEM; | ||
579 | query->sa_query.mad = kmalloc(sizeof *query->sa_query.mad, gfp_mask); | ||
580 | if (!query->sa_query.mad) { | ||
581 | kfree(query); | ||
582 | return -ENOMEM; | ||
583 | } | ||
584 | |||
585 | query->callback = callback; | ||
586 | query->context = context; | ||
587 | |||
588 | init_mad(query->sa_query.mad, agent); | ||
589 | |||
590 | query->sa_query.callback = ib_sa_path_rec_callback; | ||
591 | query->sa_query.release = ib_sa_path_rec_release; | ||
592 | query->sa_query.port = port; | ||
593 | query->sa_query.mad->mad_hdr.method = IB_MGMT_METHOD_GET; | ||
594 | query->sa_query.mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_PATH_REC); | ||
595 | query->sa_query.mad->sa_hdr.comp_mask = comp_mask; | ||
596 | |||
597 | ib_pack(path_rec_table, ARRAY_SIZE(path_rec_table), | ||
598 | rec, query->sa_query.mad->data); | ||
599 | |||
600 | *sa_query = &query->sa_query; | ||
601 | ret = send_mad(&query->sa_query, timeout_ms); | ||
602 | if (ret) { | ||
603 | *sa_query = NULL; | ||
604 | kfree(query->sa_query.mad); | ||
605 | kfree(query); | ||
606 | } | ||
607 | |||
608 | return ret ? ret : query->sa_query.id; | ||
609 | } | ||
610 | EXPORT_SYMBOL(ib_sa_path_rec_get); | ||
611 | |||
612 | static void ib_sa_mcmember_rec_callback(struct ib_sa_query *sa_query, | ||
613 | int status, | ||
614 | struct ib_sa_mad *mad) | ||
615 | { | ||
616 | struct ib_sa_mcmember_query *query = | ||
617 | container_of(sa_query, struct ib_sa_mcmember_query, sa_query); | ||
618 | |||
619 | if (mad) { | ||
620 | struct ib_sa_mcmember_rec rec; | ||
621 | |||
622 | ib_unpack(mcmember_rec_table, ARRAY_SIZE(mcmember_rec_table), | ||
623 | mad->data, &rec); | ||
624 | query->callback(status, &rec, query->context); | ||
625 | } else | ||
626 | query->callback(status, NULL, query->context); | ||
627 | } | ||
628 | |||
629 | static void ib_sa_mcmember_rec_release(struct ib_sa_query *sa_query) | ||
630 | { | ||
631 | kfree(sa_query->mad); | ||
632 | kfree(container_of(sa_query, struct ib_sa_mcmember_query, sa_query)); | ||
633 | } | ||
634 | |||
635 | int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num, | ||
636 | u8 method, | ||
637 | struct ib_sa_mcmember_rec *rec, | ||
638 | ib_sa_comp_mask comp_mask, | ||
639 | int timeout_ms, int gfp_mask, | ||
640 | void (*callback)(int status, | ||
641 | struct ib_sa_mcmember_rec *resp, | ||
642 | void *context), | ||
643 | void *context, | ||
644 | struct ib_sa_query **sa_query) | ||
645 | { | ||
646 | struct ib_sa_mcmember_query *query; | ||
647 | struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); | ||
648 | struct ib_sa_port *port = &sa_dev->port[port_num - sa_dev->start_port]; | ||
649 | struct ib_mad_agent *agent = port->agent; | ||
650 | int ret; | ||
651 | |||
652 | query = kmalloc(sizeof *query, gfp_mask); | ||
653 | if (!query) | ||
654 | return -ENOMEM; | ||
655 | query->sa_query.mad = kmalloc(sizeof *query->sa_query.mad, gfp_mask); | ||
656 | if (!query->sa_query.mad) { | ||
657 | kfree(query); | ||
658 | return -ENOMEM; | ||
659 | } | ||
660 | |||
661 | query->callback = callback; | ||
662 | query->context = context; | ||
663 | |||
664 | init_mad(query->sa_query.mad, agent); | ||
665 | |||
666 | query->sa_query.callback = ib_sa_mcmember_rec_callback; | ||
667 | query->sa_query.release = ib_sa_mcmember_rec_release; | ||
668 | query->sa_query.port = port; | ||
669 | query->sa_query.mad->mad_hdr.method = method; | ||
670 | query->sa_query.mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_MC_MEMBER_REC); | ||
671 | query->sa_query.mad->sa_hdr.comp_mask = comp_mask; | ||
672 | |||
673 | ib_pack(mcmember_rec_table, ARRAY_SIZE(mcmember_rec_table), | ||
674 | rec, query->sa_query.mad->data); | ||
675 | |||
676 | *sa_query = &query->sa_query; | ||
677 | ret = send_mad(&query->sa_query, timeout_ms); | ||
678 | if (ret) { | ||
679 | *sa_query = NULL; | ||
680 | kfree(query->sa_query.mad); | ||
681 | kfree(query); | ||
682 | } | ||
683 | |||
684 | return ret ? ret : query->sa_query.id; | ||
685 | } | ||
686 | EXPORT_SYMBOL(ib_sa_mcmember_rec_query); | ||
687 | |||
688 | static void send_handler(struct ib_mad_agent *agent, | ||
689 | struct ib_mad_send_wc *mad_send_wc) | ||
690 | { | ||
691 | struct ib_sa_query *query; | ||
692 | unsigned long flags; | ||
693 | |||
694 | spin_lock_irqsave(&idr_lock, flags); | ||
695 | query = idr_find(&query_idr, mad_send_wc->wr_id); | ||
696 | spin_unlock_irqrestore(&idr_lock, flags); | ||
697 | |||
698 | if (!query) | ||
699 | return; | ||
700 | |||
701 | switch (mad_send_wc->status) { | ||
702 | case IB_WC_SUCCESS: | ||
703 | /* No callback -- already got recv */ | ||
704 | break; | ||
705 | case IB_WC_RESP_TIMEOUT_ERR: | ||
706 | query->callback(query, -ETIMEDOUT, NULL); | ||
707 | break; | ||
708 | case IB_WC_WR_FLUSH_ERR: | ||
709 | query->callback(query, -EINTR, NULL); | ||
710 | break; | ||
711 | default: | ||
712 | query->callback(query, -EIO, NULL); | ||
713 | break; | ||
714 | } | ||
715 | |||
716 | dma_unmap_single(agent->device->dma_device, | ||
717 | pci_unmap_addr(query, mapping), | ||
718 | sizeof (struct ib_sa_mad), | ||
719 | DMA_TO_DEVICE); | ||
720 | kref_put(&query->sm_ah->ref, free_sm_ah); | ||
721 | |||
722 | query->release(query); | ||
723 | |||
724 | spin_lock_irqsave(&idr_lock, flags); | ||
725 | idr_remove(&query_idr, mad_send_wc->wr_id); | ||
726 | spin_unlock_irqrestore(&idr_lock, flags); | ||
727 | } | ||
728 | |||
729 | static void recv_handler(struct ib_mad_agent *mad_agent, | ||
730 | struct ib_mad_recv_wc *mad_recv_wc) | ||
731 | { | ||
732 | struct ib_sa_query *query; | ||
733 | unsigned long flags; | ||
734 | |||
735 | spin_lock_irqsave(&idr_lock, flags); | ||
736 | query = idr_find(&query_idr, mad_recv_wc->wc->wr_id); | ||
737 | spin_unlock_irqrestore(&idr_lock, flags); | ||
738 | |||
739 | if (query) { | ||
740 | if (mad_recv_wc->wc->status == IB_WC_SUCCESS) | ||
741 | query->callback(query, | ||
742 | mad_recv_wc->recv_buf.mad->mad_hdr.status ? | ||
743 | -EINVAL : 0, | ||
744 | (struct ib_sa_mad *) mad_recv_wc->recv_buf.mad); | ||
745 | else | ||
746 | query->callback(query, -EIO, NULL); | ||
747 | } | ||
748 | |||
749 | ib_free_recv_mad(mad_recv_wc); | ||
750 | } | ||
751 | |||
752 | static void ib_sa_add_one(struct ib_device *device) | ||
753 | { | ||
754 | struct ib_sa_device *sa_dev; | ||
755 | int s, e, i; | ||
756 | |||
757 | if (device->node_type == IB_NODE_SWITCH) | ||
758 | s = e = 0; | ||
759 | else { | ||
760 | s = 1; | ||
761 | e = device->phys_port_cnt; | ||
762 | } | ||
763 | |||
764 | sa_dev = kmalloc(sizeof *sa_dev + | ||
765 | (e - s + 1) * sizeof (struct ib_sa_port), | ||
766 | GFP_KERNEL); | ||
767 | if (!sa_dev) | ||
768 | return; | ||
769 | |||
770 | sa_dev->start_port = s; | ||
771 | sa_dev->end_port = e; | ||
772 | |||
773 | for (i = 0; i <= e - s; ++i) { | ||
774 | sa_dev->port[i].mr = NULL; | ||
775 | sa_dev->port[i].sm_ah = NULL; | ||
776 | sa_dev->port[i].port_num = i + s; | ||
777 | spin_lock_init(&sa_dev->port[i].ah_lock); | ||
778 | |||
779 | sa_dev->port[i].agent = | ||
780 | ib_register_mad_agent(device, i + s, IB_QPT_GSI, | ||
781 | NULL, 0, send_handler, | ||
782 | recv_handler, sa_dev); | ||
783 | if (IS_ERR(sa_dev->port[i].agent)) | ||
784 | goto err; | ||
785 | |||
786 | sa_dev->port[i].mr = ib_get_dma_mr(sa_dev->port[i].agent->qp->pd, | ||
787 | IB_ACCESS_LOCAL_WRITE); | ||
788 | if (IS_ERR(sa_dev->port[i].mr)) { | ||
789 | ib_unregister_mad_agent(sa_dev->port[i].agent); | ||
790 | goto err; | ||
791 | } | ||
792 | |||
793 | INIT_WORK(&sa_dev->port[i].update_task, | ||
794 | update_sm_ah, &sa_dev->port[i]); | ||
795 | } | ||
796 | |||
797 | ib_set_client_data(device, &sa_client, sa_dev); | ||
798 | |||
799 | /* | ||
800 | * We register our event handler after everything is set up, | ||
801 | * and then update our cached info after the event handler is | ||
802 | * registered to avoid any problems if a port changes state | ||
803 | * during our initialization. | ||
804 | */ | ||
805 | |||
806 | INIT_IB_EVENT_HANDLER(&sa_dev->event_handler, device, ib_sa_event); | ||
807 | if (ib_register_event_handler(&sa_dev->event_handler)) | ||
808 | goto err; | ||
809 | |||
810 | for (i = 0; i <= e - s; ++i) | ||
811 | update_sm_ah(&sa_dev->port[i]); | ||
812 | |||
813 | return; | ||
814 | |||
815 | err: | ||
816 | while (--i >= 0) { | ||
817 | ib_dereg_mr(sa_dev->port[i].mr); | ||
818 | ib_unregister_mad_agent(sa_dev->port[i].agent); | ||
819 | } | ||
820 | |||
821 | kfree(sa_dev); | ||
822 | |||
823 | return; | ||
824 | } | ||
825 | |||
826 | static void ib_sa_remove_one(struct ib_device *device) | ||
827 | { | ||
828 | struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); | ||
829 | int i; | ||
830 | |||
831 | if (!sa_dev) | ||
832 | return; | ||
833 | |||
834 | ib_unregister_event_handler(&sa_dev->event_handler); | ||
835 | |||
836 | for (i = 0; i <= sa_dev->end_port - sa_dev->start_port; ++i) { | ||
837 | ib_unregister_mad_agent(sa_dev->port[i].agent); | ||
838 | kref_put(&sa_dev->port[i].sm_ah->ref, free_sm_ah); | ||
839 | } | ||
840 | |||
841 | kfree(sa_dev); | ||
842 | } | ||
843 | |||
844 | static int __init ib_sa_init(void) | ||
845 | { | ||
846 | int ret; | ||
847 | |||
848 | spin_lock_init(&idr_lock); | ||
849 | spin_lock_init(&tid_lock); | ||
850 | |||
851 | get_random_bytes(&tid, sizeof tid); | ||
852 | |||
853 | ret = ib_register_client(&sa_client); | ||
854 | if (ret) | ||
855 | printk(KERN_ERR "Couldn't register ib_sa client\n"); | ||
856 | |||
857 | return ret; | ||
858 | } | ||
859 | |||
860 | static void __exit ib_sa_cleanup(void) | ||
861 | { | ||
862 | ib_unregister_client(&sa_client); | ||
863 | } | ||
864 | |||
865 | module_init(ib_sa_init); | ||
866 | module_exit(ib_sa_cleanup); | ||
diff --git a/drivers/infiniband/core/smi.c b/drivers/infiniband/core/smi.c new file mode 100644 index 000000000000..b4b284324a33 --- /dev/null +++ b/drivers/infiniband/core/smi.c | |||
@@ -0,0 +1,234 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. | ||
3 | * Copyright (c) 2004 Infinicon Corporation. All rights reserved. | ||
4 | * Copyright (c) 2004 Intel Corporation. All rights reserved. | ||
5 | * Copyright (c) 2004 Topspin Corporation. All rights reserved. | ||
6 | * Copyright (c) 2004 Voltaire Corporation. All rights reserved. | ||
7 | * | ||
8 | * This software is available to you under a choice of one of two | ||
9 | * licenses. You may choose to be licensed under the terms of the GNU | ||
10 | * General Public License (GPL) Version 2, available from the file | ||
11 | * COPYING in the main directory of this source tree, or the | ||
12 | * OpenIB.org BSD license below: | ||
13 | * | ||
14 | * Redistribution and use in source and binary forms, with or | ||
15 | * without modification, are permitted provided that the following | ||
16 | * conditions are met: | ||
17 | * | ||
18 | * - Redistributions of source code must retain the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer. | ||
21 | * | ||
22 | * - Redistributions in binary form must reproduce the above | ||
23 | * copyright notice, this list of conditions and the following | ||
24 | * disclaimer in the documentation and/or other materials | ||
25 | * provided with the distribution. | ||
26 | * | ||
27 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
28 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
29 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
30 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
31 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
32 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
33 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
34 | * SOFTWARE. | ||
35 | * | ||
36 | * $Id: smi.c 1389 2004-12-27 22:56:47Z roland $ | ||
37 | */ | ||
38 | |||
39 | #include <ib_smi.h> | ||
40 | #include "smi.h" | ||
41 | |||
42 | /* | ||
43 | * Fixup a directed route SMP for sending | ||
44 | * Return 0 if the SMP should be discarded | ||
45 | */ | ||
46 | int smi_handle_dr_smp_send(struct ib_smp *smp, | ||
47 | u8 node_type, | ||
48 | int port_num) | ||
49 | { | ||
50 | u8 hop_ptr, hop_cnt; | ||
51 | |||
52 | hop_ptr = smp->hop_ptr; | ||
53 | hop_cnt = smp->hop_cnt; | ||
54 | |||
55 | /* See section 14.2.2.2, Vol 1 IB spec */ | ||
56 | if (!ib_get_smp_direction(smp)) { | ||
57 | /* C14-9:1 */ | ||
58 | if (hop_cnt && hop_ptr == 0) { | ||
59 | smp->hop_ptr++; | ||
60 | return (smp->initial_path[smp->hop_ptr] == | ||
61 | port_num); | ||
62 | } | ||
63 | |||
64 | /* C14-9:2 */ | ||
65 | if (hop_ptr && hop_ptr < hop_cnt) { | ||
66 | if (node_type != IB_NODE_SWITCH) | ||
67 | return 0; | ||
68 | |||
69 | /* smp->return_path set when received */ | ||
70 | smp->hop_ptr++; | ||
71 | return (smp->initial_path[smp->hop_ptr] == | ||
72 | port_num); | ||
73 | } | ||
74 | |||
75 | /* C14-9:3 -- We're at the end of the DR segment of path */ | ||
76 | if (hop_ptr == hop_cnt) { | ||
77 | /* smp->return_path set when received */ | ||
78 | smp->hop_ptr++; | ||
79 | return (node_type == IB_NODE_SWITCH || | ||
80 | smp->dr_dlid == IB_LID_PERMISSIVE); | ||
81 | } | ||
82 | |||
83 | /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ | ||
84 | /* C14-9:5 -- Fail unreasonable hop pointer */ | ||
85 | return (hop_ptr == hop_cnt + 1); | ||
86 | |||
87 | } else { | ||
88 | /* C14-13:1 */ | ||
89 | if (hop_cnt && hop_ptr == hop_cnt + 1) { | ||
90 | smp->hop_ptr--; | ||
91 | return (smp->return_path[smp->hop_ptr] == | ||
92 | port_num); | ||
93 | } | ||
94 | |||
95 | /* C14-13:2 */ | ||
96 | if (2 <= hop_ptr && hop_ptr <= hop_cnt) { | ||
97 | if (node_type != IB_NODE_SWITCH) | ||
98 | return 0; | ||
99 | |||
100 | smp->hop_ptr--; | ||
101 | return (smp->return_path[smp->hop_ptr] == | ||
102 | port_num); | ||
103 | } | ||
104 | |||
105 | /* C14-13:3 -- at the end of the DR segment of path */ | ||
106 | if (hop_ptr == 1) { | ||
107 | smp->hop_ptr--; | ||
108 | /* C14-13:3 -- SMPs destined for SM shouldn't be here */ | ||
109 | return (node_type == IB_NODE_SWITCH || | ||
110 | smp->dr_slid == IB_LID_PERMISSIVE); | ||
111 | } | ||
112 | |||
113 | /* C14-13:4 -- hop_ptr = 0 -> should have gone to SM */ | ||
114 | if (hop_ptr == 0) | ||
115 | return 1; | ||
116 | |||
117 | /* C14-13:5 -- Check for unreasonable hop pointer */ | ||
118 | return 0; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Adjust information for a received SMP | ||
124 | * Return 0 if the SMP should be dropped | ||
125 | */ | ||
126 | int smi_handle_dr_smp_recv(struct ib_smp *smp, | ||
127 | u8 node_type, | ||
128 | int port_num, | ||
129 | int phys_port_cnt) | ||
130 | { | ||
131 | u8 hop_ptr, hop_cnt; | ||
132 | |||
133 | hop_ptr = smp->hop_ptr; | ||
134 | hop_cnt = smp->hop_cnt; | ||
135 | |||
136 | /* See section 14.2.2.2, Vol 1 IB spec */ | ||
137 | if (!ib_get_smp_direction(smp)) { | ||
138 | /* C14-9:1 -- sender should have incremented hop_ptr */ | ||
139 | if (hop_cnt && hop_ptr == 0) | ||
140 | return 0; | ||
141 | |||
142 | /* C14-9:2 -- intermediate hop */ | ||
143 | if (hop_ptr && hop_ptr < hop_cnt) { | ||
144 | if (node_type != IB_NODE_SWITCH) | ||
145 | return 0; | ||
146 | |||
147 | smp->return_path[hop_ptr] = port_num; | ||
148 | /* smp->hop_ptr updated when sending */ | ||
149 | return (smp->initial_path[hop_ptr+1] <= phys_port_cnt); | ||
150 | } | ||
151 | |||
152 | /* C14-9:3 -- We're at the end of the DR segment of path */ | ||
153 | if (hop_ptr == hop_cnt) { | ||
154 | if (hop_cnt) | ||
155 | smp->return_path[hop_ptr] = port_num; | ||
156 | /* smp->hop_ptr updated when sending */ | ||
157 | |||
158 | return (node_type == IB_NODE_SWITCH || | ||
159 | smp->dr_dlid == IB_LID_PERMISSIVE); | ||
160 | } | ||
161 | |||
162 | /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ | ||
163 | /* C14-9:5 -- fail unreasonable hop pointer */ | ||
164 | return (hop_ptr == hop_cnt + 1); | ||
165 | |||
166 | } else { | ||
167 | |||
168 | /* C14-13:1 */ | ||
169 | if (hop_cnt && hop_ptr == hop_cnt + 1) { | ||
170 | smp->hop_ptr--; | ||
171 | return (smp->return_path[smp->hop_ptr] == | ||
172 | port_num); | ||
173 | } | ||
174 | |||
175 | /* C14-13:2 */ | ||
176 | if (2 <= hop_ptr && hop_ptr <= hop_cnt) { | ||
177 | if (node_type != IB_NODE_SWITCH) | ||
178 | return 0; | ||
179 | |||
180 | /* smp->hop_ptr updated when sending */ | ||
181 | return (smp->return_path[hop_ptr-1] <= phys_port_cnt); | ||
182 | } | ||
183 | |||
184 | /* C14-13:3 -- We're at the end of the DR segment of path */ | ||
185 | if (hop_ptr == 1) { | ||
186 | if (smp->dr_slid == IB_LID_PERMISSIVE) { | ||
187 | /* giving SMP to SM - update hop_ptr */ | ||
188 | smp->hop_ptr--; | ||
189 | return 1; | ||
190 | } | ||
191 | /* smp->hop_ptr updated when sending */ | ||
192 | return (node_type == IB_NODE_SWITCH); | ||
193 | } | ||
194 | |||
195 | /* C14-13:4 -- hop_ptr = 0 -> give to SM */ | ||
196 | /* C14-13:5 -- Check for unreasonable hop pointer */ | ||
197 | return (hop_ptr == 0); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * Return 1 if the received DR SMP should be forwarded to the send queue | ||
203 | * Return 0 if the SMP should be completed up the stack | ||
204 | */ | ||
205 | int smi_check_forward_dr_smp(struct ib_smp *smp) | ||
206 | { | ||
207 | u8 hop_ptr, hop_cnt; | ||
208 | |||
209 | hop_ptr = smp->hop_ptr; | ||
210 | hop_cnt = smp->hop_cnt; | ||
211 | |||
212 | if (!ib_get_smp_direction(smp)) { | ||
213 | /* C14-9:2 -- intermediate hop */ | ||
214 | if (hop_ptr && hop_ptr < hop_cnt) | ||
215 | return 1; | ||
216 | |||
217 | /* C14-9:3 -- at the end of the DR segment of path */ | ||
218 | if (hop_ptr == hop_cnt) | ||
219 | return (smp->dr_dlid == IB_LID_PERMISSIVE); | ||
220 | |||
221 | /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ | ||
222 | if (hop_ptr == hop_cnt + 1) | ||
223 | return 1; | ||
224 | } else { | ||
225 | /* C14-13:2 */ | ||
226 | if (2 <= hop_ptr && hop_ptr <= hop_cnt) | ||
227 | return 1; | ||
228 | |||
229 | /* C14-13:3 -- at the end of the DR segment of path */ | ||
230 | if (hop_ptr == 1) | ||
231 | return (smp->dr_slid != IB_LID_PERMISSIVE); | ||
232 | } | ||
233 | return 0; | ||
234 | } | ||
diff --git a/drivers/infiniband/core/smi.h b/drivers/infiniband/core/smi.h new file mode 100644 index 000000000000..db25503a0736 --- /dev/null +++ b/drivers/infiniband/core/smi.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. | ||
3 | * Copyright (c) 2004 Infinicon Corporation. All rights reserved. | ||
4 | * Copyright (c) 2004 Intel Corporation. All rights reserved. | ||
5 | * Copyright (c) 2004 Topspin Corporation. All rights reserved. | ||
6 | * Copyright (c) 2004 Voltaire Corporation. All rights reserved. | ||
7 | * | ||
8 | * This software is available to you under a choice of one of two | ||
9 | * licenses. You may choose to be licensed under the terms of the GNU | ||
10 | * General Public License (GPL) Version 2, available from the file | ||
11 | * COPYING in the main directory of this source tree, or the | ||
12 | * OpenIB.org BSD license below: | ||
13 | * | ||
14 | * Redistribution and use in source and binary forms, with or | ||
15 | * without modification, are permitted provided that the following | ||
16 | * conditions are met: | ||
17 | * | ||
18 | * - Redistributions of source code must retain the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer. | ||
21 | * | ||
22 | * - Redistributions in binary form must reproduce the above | ||
23 | * copyright notice, this list of conditions and the following | ||
24 | * disclaimer in the documentation and/or other materials | ||
25 | * provided with the distribution. | ||
26 | * | ||
27 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
28 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
29 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
30 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
31 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
32 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
33 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
34 | * SOFTWARE. | ||
35 | * | ||
36 | * $Id: smi.h 1389 2004-12-27 22:56:47Z roland $ | ||
37 | */ | ||
38 | |||
39 | #ifndef __SMI_H_ | ||
40 | #define __SMI_H_ | ||
41 | |||
42 | int smi_handle_dr_smp_recv(struct ib_smp *smp, | ||
43 | u8 node_type, | ||
44 | int port_num, | ||
45 | int phys_port_cnt); | ||
46 | extern int smi_check_forward_dr_smp(struct ib_smp *smp); | ||
47 | extern int smi_handle_dr_smp_send(struct ib_smp *smp, | ||
48 | u8 node_type, | ||
49 | int port_num); | ||
50 | extern int smi_check_local_dr_smp(struct ib_smp *smp, | ||
51 | struct ib_device *device, | ||
52 | int port_num); | ||
53 | |||
54 | /* | ||
55 | * Return 1 if the SMP should be handled by the local SMA/SM via process_mad | ||
56 | */ | ||
57 | static inline int smi_check_local_smp(struct ib_mad_agent *mad_agent, | ||
58 | struct ib_smp *smp) | ||
59 | { | ||
60 | /* C14-9:3 -- We're at the end of the DR segment of path */ | ||
61 | /* C14-9:4 -- Hop Pointer = Hop Count + 1 -> give to SMA/SM */ | ||
62 | return ((mad_agent->device->process_mad && | ||
63 | !ib_get_smp_direction(smp) && | ||
64 | (smp->hop_ptr == smp->hop_cnt + 1))); | ||
65 | } | ||
66 | |||
67 | #endif /* __SMI_H_ */ | ||
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c new file mode 100644 index 000000000000..3a413f72ff6d --- /dev/null +++ b/drivers/infiniband/core/sysfs.c | |||
@@ -0,0 +1,762 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | * $Id: sysfs.c 1349 2004-12-16 21:09:43Z roland $ | ||
33 | */ | ||
34 | |||
35 | #include "core_priv.h" | ||
36 | |||
37 | #include <ib_mad.h> | ||
38 | |||
39 | struct ib_port { | ||
40 | struct kobject kobj; | ||
41 | struct ib_device *ibdev; | ||
42 | struct attribute_group gid_group; | ||
43 | struct attribute **gid_attr; | ||
44 | struct attribute_group pkey_group; | ||
45 | struct attribute **pkey_attr; | ||
46 | u8 port_num; | ||
47 | }; | ||
48 | |||
49 | struct port_attribute { | ||
50 | struct attribute attr; | ||
51 | ssize_t (*show)(struct ib_port *, struct port_attribute *, char *buf); | ||
52 | ssize_t (*store)(struct ib_port *, struct port_attribute *, | ||
53 | const char *buf, size_t count); | ||
54 | }; | ||
55 | |||
56 | #define PORT_ATTR(_name, _mode, _show, _store) \ | ||
57 | struct port_attribute port_attr_##_name = __ATTR(_name, _mode, _show, _store) | ||
58 | |||
59 | #define PORT_ATTR_RO(_name) \ | ||
60 | struct port_attribute port_attr_##_name = __ATTR_RO(_name) | ||
61 | |||
62 | struct port_table_attribute { | ||
63 | struct port_attribute attr; | ||
64 | int index; | ||
65 | }; | ||
66 | |||
67 | static ssize_t port_attr_show(struct kobject *kobj, | ||
68 | struct attribute *attr, char *buf) | ||
69 | { | ||
70 | struct port_attribute *port_attr = | ||
71 | container_of(attr, struct port_attribute, attr); | ||
72 | struct ib_port *p = container_of(kobj, struct ib_port, kobj); | ||
73 | |||
74 | if (!port_attr->show) | ||
75 | return 0; | ||
76 | |||
77 | return port_attr->show(p, port_attr, buf); | ||
78 | } | ||
79 | |||
80 | static struct sysfs_ops port_sysfs_ops = { | ||
81 | .show = port_attr_show | ||
82 | }; | ||
83 | |||
84 | static ssize_t state_show(struct ib_port *p, struct port_attribute *unused, | ||
85 | char *buf) | ||
86 | { | ||
87 | struct ib_port_attr attr; | ||
88 | ssize_t ret; | ||
89 | |||
90 | static const char *state_name[] = { | ||
91 | [IB_PORT_NOP] = "NOP", | ||
92 | [IB_PORT_DOWN] = "DOWN", | ||
93 | [IB_PORT_INIT] = "INIT", | ||
94 | [IB_PORT_ARMED] = "ARMED", | ||
95 | [IB_PORT_ACTIVE] = "ACTIVE", | ||
96 | [IB_PORT_ACTIVE_DEFER] = "ACTIVE_DEFER" | ||
97 | }; | ||
98 | |||
99 | ret = ib_query_port(p->ibdev, p->port_num, &attr); | ||
100 | if (ret) | ||
101 | return ret; | ||
102 | |||
103 | return sprintf(buf, "%d: %s\n", attr.state, | ||
104 | attr.state >= 0 && attr.state <= ARRAY_SIZE(state_name) ? | ||
105 | state_name[attr.state] : "UNKNOWN"); | ||
106 | } | ||
107 | |||
108 | static ssize_t lid_show(struct ib_port *p, struct port_attribute *unused, | ||
109 | char *buf) | ||
110 | { | ||
111 | struct ib_port_attr attr; | ||
112 | ssize_t ret; | ||
113 | |||
114 | ret = ib_query_port(p->ibdev, p->port_num, &attr); | ||
115 | if (ret) | ||
116 | return ret; | ||
117 | |||
118 | return sprintf(buf, "0x%x\n", attr.lid); | ||
119 | } | ||
120 | |||
121 | static ssize_t lid_mask_count_show(struct ib_port *p, | ||
122 | struct port_attribute *unused, | ||
123 | char *buf) | ||
124 | { | ||
125 | struct ib_port_attr attr; | ||
126 | ssize_t ret; | ||
127 | |||
128 | ret = ib_query_port(p->ibdev, p->port_num, &attr); | ||
129 | if (ret) | ||
130 | return ret; | ||
131 | |||
132 | return sprintf(buf, "%d\n", attr.lmc); | ||
133 | } | ||
134 | |||
135 | static ssize_t sm_lid_show(struct ib_port *p, struct port_attribute *unused, | ||
136 | char *buf) | ||
137 | { | ||
138 | struct ib_port_attr attr; | ||
139 | ssize_t ret; | ||
140 | |||
141 | ret = ib_query_port(p->ibdev, p->port_num, &attr); | ||
142 | if (ret) | ||
143 | return ret; | ||
144 | |||
145 | return sprintf(buf, "0x%x\n", attr.sm_lid); | ||
146 | } | ||
147 | |||
148 | static ssize_t sm_sl_show(struct ib_port *p, struct port_attribute *unused, | ||
149 | char *buf) | ||
150 | { | ||
151 | struct ib_port_attr attr; | ||
152 | ssize_t ret; | ||
153 | |||
154 | ret = ib_query_port(p->ibdev, p->port_num, &attr); | ||
155 | if (ret) | ||
156 | return ret; | ||
157 | |||
158 | return sprintf(buf, "%d\n", attr.sm_sl); | ||
159 | } | ||
160 | |||
161 | static ssize_t cap_mask_show(struct ib_port *p, struct port_attribute *unused, | ||
162 | char *buf) | ||
163 | { | ||
164 | struct ib_port_attr attr; | ||
165 | ssize_t ret; | ||
166 | |||
167 | ret = ib_query_port(p->ibdev, p->port_num, &attr); | ||
168 | if (ret) | ||
169 | return ret; | ||
170 | |||
171 | return sprintf(buf, "0x%08x\n", attr.port_cap_flags); | ||
172 | } | ||
173 | |||
174 | static ssize_t rate_show(struct ib_port *p, struct port_attribute *unused, | ||
175 | char *buf) | ||
176 | { | ||
177 | struct ib_port_attr attr; | ||
178 | char *speed = ""; | ||
179 | int rate; | ||
180 | ssize_t ret; | ||
181 | |||
182 | ret = ib_query_port(p->ibdev, p->port_num, &attr); | ||
183 | if (ret) | ||
184 | return ret; | ||
185 | |||
186 | switch (attr.active_speed) { | ||
187 | case 2: speed = " DDR"; break; | ||
188 | case 4: speed = " QDR"; break; | ||
189 | } | ||
190 | |||
191 | rate = 25 * ib_width_enum_to_int(attr.active_width) * attr.active_speed; | ||
192 | if (rate < 0) | ||
193 | return -EINVAL; | ||
194 | |||
195 | return sprintf(buf, "%d%s Gb/sec (%dX%s)\n", | ||
196 | rate / 10, rate % 10 ? ".5" : "", | ||
197 | ib_width_enum_to_int(attr.active_width), speed); | ||
198 | } | ||
199 | |||
200 | static ssize_t phys_state_show(struct ib_port *p, struct port_attribute *unused, | ||
201 | char *buf) | ||
202 | { | ||
203 | struct ib_port_attr attr; | ||
204 | |||
205 | ssize_t ret; | ||
206 | |||
207 | ret = ib_query_port(p->ibdev, p->port_num, &attr); | ||
208 | if (ret) | ||
209 | return ret; | ||
210 | |||
211 | switch (attr.phys_state) { | ||
212 | case 1: return sprintf(buf, "1: Sleep\n"); | ||
213 | case 2: return sprintf(buf, "2: Polling\n"); | ||
214 | case 3: return sprintf(buf, "3: Disabled\n"); | ||
215 | case 4: return sprintf(buf, "4: PortConfigurationTraining\n"); | ||
216 | case 5: return sprintf(buf, "5: LinkUp\n"); | ||
217 | case 6: return sprintf(buf, "6: LinkErrorRecovery\n"); | ||
218 | case 7: return sprintf(buf, "7: Phy Test\n"); | ||
219 | default: return sprintf(buf, "%d: <unknown>\n", attr.phys_state); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | static PORT_ATTR_RO(state); | ||
224 | static PORT_ATTR_RO(lid); | ||
225 | static PORT_ATTR_RO(lid_mask_count); | ||
226 | static PORT_ATTR_RO(sm_lid); | ||
227 | static PORT_ATTR_RO(sm_sl); | ||
228 | static PORT_ATTR_RO(cap_mask); | ||
229 | static PORT_ATTR_RO(rate); | ||
230 | static PORT_ATTR_RO(phys_state); | ||
231 | |||
232 | static struct attribute *port_default_attrs[] = { | ||
233 | &port_attr_state.attr, | ||
234 | &port_attr_lid.attr, | ||
235 | &port_attr_lid_mask_count.attr, | ||
236 | &port_attr_sm_lid.attr, | ||
237 | &port_attr_sm_sl.attr, | ||
238 | &port_attr_cap_mask.attr, | ||
239 | &port_attr_rate.attr, | ||
240 | &port_attr_phys_state.attr, | ||
241 | NULL | ||
242 | }; | ||
243 | |||
244 | static ssize_t show_port_gid(struct ib_port *p, struct port_attribute *attr, | ||
245 | char *buf) | ||
246 | { | ||
247 | struct port_table_attribute *tab_attr = | ||
248 | container_of(attr, struct port_table_attribute, attr); | ||
249 | union ib_gid gid; | ||
250 | ssize_t ret; | ||
251 | |||
252 | ret = ib_query_gid(p->ibdev, p->port_num, tab_attr->index, &gid); | ||
253 | if (ret) | ||
254 | return ret; | ||
255 | |||
256 | return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", | ||
257 | be16_to_cpu(((u16 *) gid.raw)[0]), | ||
258 | be16_to_cpu(((u16 *) gid.raw)[1]), | ||
259 | be16_to_cpu(((u16 *) gid.raw)[2]), | ||
260 | be16_to_cpu(((u16 *) gid.raw)[3]), | ||
261 | be16_to_cpu(((u16 *) gid.raw)[4]), | ||
262 | be16_to_cpu(((u16 *) gid.raw)[5]), | ||
263 | be16_to_cpu(((u16 *) gid.raw)[6]), | ||
264 | be16_to_cpu(((u16 *) gid.raw)[7])); | ||
265 | } | ||
266 | |||
267 | static ssize_t show_port_pkey(struct ib_port *p, struct port_attribute *attr, | ||
268 | char *buf) | ||
269 | { | ||
270 | struct port_table_attribute *tab_attr = | ||
271 | container_of(attr, struct port_table_attribute, attr); | ||
272 | u16 pkey; | ||
273 | ssize_t ret; | ||
274 | |||
275 | ret = ib_query_pkey(p->ibdev, p->port_num, tab_attr->index, &pkey); | ||
276 | if (ret) | ||
277 | return ret; | ||
278 | |||
279 | return sprintf(buf, "0x%04x\n", pkey); | ||
280 | } | ||
281 | |||
282 | #define PORT_PMA_ATTR(_name, _counter, _width, _offset) \ | ||
283 | struct port_table_attribute port_pma_attr_##_name = { \ | ||
284 | .attr = __ATTR(_name, S_IRUGO, show_pma_counter, NULL), \ | ||
285 | .index = (_offset) | ((_width) << 16) | ((_counter) << 24) \ | ||
286 | } | ||
287 | |||
288 | static ssize_t show_pma_counter(struct ib_port *p, struct port_attribute *attr, | ||
289 | char *buf) | ||
290 | { | ||
291 | struct port_table_attribute *tab_attr = | ||
292 | container_of(attr, struct port_table_attribute, attr); | ||
293 | int offset = tab_attr->index & 0xffff; | ||
294 | int width = (tab_attr->index >> 16) & 0xff; | ||
295 | struct ib_mad *in_mad = NULL; | ||
296 | struct ib_mad *out_mad = NULL; | ||
297 | ssize_t ret; | ||
298 | |||
299 | if (!p->ibdev->process_mad) | ||
300 | return sprintf(buf, "N/A (no PMA)\n"); | ||
301 | |||
302 | in_mad = kmalloc(sizeof *in_mad, GFP_KERNEL); | ||
303 | out_mad = kmalloc(sizeof *in_mad, GFP_KERNEL); | ||
304 | if (!in_mad || !out_mad) { | ||
305 | ret = -ENOMEM; | ||
306 | goto out; | ||
307 | } | ||
308 | |||
309 | memset(in_mad, 0, sizeof *in_mad); | ||
310 | in_mad->mad_hdr.base_version = 1; | ||
311 | in_mad->mad_hdr.mgmt_class = IB_MGMT_CLASS_PERF_MGMT; | ||
312 | in_mad->mad_hdr.class_version = 1; | ||
313 | in_mad->mad_hdr.method = IB_MGMT_METHOD_GET; | ||
314 | in_mad->mad_hdr.attr_id = cpu_to_be16(0x12); /* PortCounters */ | ||
315 | |||
316 | in_mad->data[41] = p->port_num; /* PortSelect field */ | ||
317 | |||
318 | if ((p->ibdev->process_mad(p->ibdev, IB_MAD_IGNORE_MKEY, | ||
319 | p->port_num, NULL, NULL, in_mad, out_mad) & | ||
320 | (IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY)) != | ||
321 | (IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY)) { | ||
322 | ret = -EINVAL; | ||
323 | goto out; | ||
324 | } | ||
325 | |||
326 | switch (width) { | ||
327 | case 4: | ||
328 | ret = sprintf(buf, "%u\n", (out_mad->data[40 + offset / 8] >> | ||
329 | (offset % 4)) & 0xf); | ||
330 | break; | ||
331 | case 8: | ||
332 | ret = sprintf(buf, "%u\n", out_mad->data[40 + offset / 8]); | ||
333 | break; | ||
334 | case 16: | ||
335 | ret = sprintf(buf, "%u\n", | ||
336 | be16_to_cpup((u16 *)(out_mad->data + 40 + offset / 8))); | ||
337 | break; | ||
338 | case 32: | ||
339 | ret = sprintf(buf, "%u\n", | ||
340 | be32_to_cpup((u32 *)(out_mad->data + 40 + offset / 8))); | ||
341 | break; | ||
342 | default: | ||
343 | ret = 0; | ||
344 | } | ||
345 | |||
346 | out: | ||
347 | kfree(in_mad); | ||
348 | kfree(out_mad); | ||
349 | |||
350 | return ret; | ||
351 | } | ||
352 | |||
353 | static PORT_PMA_ATTR(symbol_error , 0, 16, 32); | ||
354 | static PORT_PMA_ATTR(link_error_recovery , 1, 8, 48); | ||
355 | static PORT_PMA_ATTR(link_downed , 2, 8, 56); | ||
356 | static PORT_PMA_ATTR(port_rcv_errors , 3, 16, 64); | ||
357 | static PORT_PMA_ATTR(port_rcv_remote_physical_errors, 4, 16, 80); | ||
358 | static PORT_PMA_ATTR(port_rcv_switch_relay_errors , 5, 16, 96); | ||
359 | static PORT_PMA_ATTR(port_xmit_discards , 6, 16, 112); | ||
360 | static PORT_PMA_ATTR(port_xmit_constraint_errors , 7, 8, 128); | ||
361 | static PORT_PMA_ATTR(port_rcv_constraint_errors , 8, 8, 136); | ||
362 | static PORT_PMA_ATTR(local_link_integrity_errors , 9, 4, 152); | ||
363 | static PORT_PMA_ATTR(excessive_buffer_overrun_errors, 10, 4, 156); | ||
364 | static PORT_PMA_ATTR(VL15_dropped , 11, 16, 176); | ||
365 | static PORT_PMA_ATTR(port_xmit_data , 12, 32, 192); | ||
366 | static PORT_PMA_ATTR(port_rcv_data , 13, 32, 224); | ||
367 | static PORT_PMA_ATTR(port_xmit_packets , 14, 32, 256); | ||
368 | static PORT_PMA_ATTR(port_rcv_packets , 15, 32, 288); | ||
369 | |||
370 | static struct attribute *pma_attrs[] = { | ||
371 | &port_pma_attr_symbol_error.attr.attr, | ||
372 | &port_pma_attr_link_error_recovery.attr.attr, | ||
373 | &port_pma_attr_link_downed.attr.attr, | ||
374 | &port_pma_attr_port_rcv_errors.attr.attr, | ||
375 | &port_pma_attr_port_rcv_remote_physical_errors.attr.attr, | ||
376 | &port_pma_attr_port_rcv_switch_relay_errors.attr.attr, | ||
377 | &port_pma_attr_port_xmit_discards.attr.attr, | ||
378 | &port_pma_attr_port_xmit_constraint_errors.attr.attr, | ||
379 | &port_pma_attr_port_rcv_constraint_errors.attr.attr, | ||
380 | &port_pma_attr_local_link_integrity_errors.attr.attr, | ||
381 | &port_pma_attr_excessive_buffer_overrun_errors.attr.attr, | ||
382 | &port_pma_attr_VL15_dropped.attr.attr, | ||
383 | &port_pma_attr_port_xmit_data.attr.attr, | ||
384 | &port_pma_attr_port_rcv_data.attr.attr, | ||
385 | &port_pma_attr_port_xmit_packets.attr.attr, | ||
386 | &port_pma_attr_port_rcv_packets.attr.attr, | ||
387 | NULL | ||
388 | }; | ||
389 | |||
390 | static struct attribute_group pma_group = { | ||
391 | .name = "counters", | ||
392 | .attrs = pma_attrs | ||
393 | }; | ||
394 | |||
395 | static void ib_port_release(struct kobject *kobj) | ||
396 | { | ||
397 | struct ib_port *p = container_of(kobj, struct ib_port, kobj); | ||
398 | struct attribute *a; | ||
399 | int i; | ||
400 | |||
401 | for (i = 0; (a = p->gid_attr[i]); ++i) { | ||
402 | kfree(a->name); | ||
403 | kfree(a); | ||
404 | } | ||
405 | |||
406 | for (i = 0; (a = p->pkey_attr[i]); ++i) { | ||
407 | kfree(a->name); | ||
408 | kfree(a); | ||
409 | } | ||
410 | |||
411 | kfree(p->gid_attr); | ||
412 | kfree(p); | ||
413 | } | ||
414 | |||
415 | static struct kobj_type port_type = { | ||
416 | .release = ib_port_release, | ||
417 | .sysfs_ops = &port_sysfs_ops, | ||
418 | .default_attrs = port_default_attrs | ||
419 | }; | ||
420 | |||
421 | static void ib_device_release(struct class_device *cdev) | ||
422 | { | ||
423 | struct ib_device *dev = container_of(cdev, struct ib_device, class_dev); | ||
424 | |||
425 | kfree(dev); | ||
426 | } | ||
427 | |||
428 | static int ib_device_hotplug(struct class_device *cdev, char **envp, | ||
429 | int num_envp, char *buf, int size) | ||
430 | { | ||
431 | struct ib_device *dev = container_of(cdev, struct ib_device, class_dev); | ||
432 | int i = 0, len = 0; | ||
433 | |||
434 | if (add_hotplug_env_var(envp, num_envp, &i, buf, size, &len, | ||
435 | "NAME=%s", dev->name)) | ||
436 | return -ENOMEM; | ||
437 | |||
438 | /* | ||
439 | * It might be nice to pass the node GUID to hotplug, but | ||
440 | * right now the only way to get it is to query the device | ||
441 | * provider, and this can crash during device removal because | ||
442 | * we are will be running after driver removal has started. | ||
443 | * We could add a node_guid field to struct ib_device, or we | ||
444 | * could just let the hotplug script read the node GUID from | ||
445 | * sysfs when devices are added. | ||
446 | */ | ||
447 | |||
448 | envp[i] = NULL; | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int alloc_group(struct attribute ***attr, | ||
453 | ssize_t (*show)(struct ib_port *, | ||
454 | struct port_attribute *, char *buf), | ||
455 | int len) | ||
456 | { | ||
457 | struct port_table_attribute ***tab_attr = | ||
458 | (struct port_table_attribute ***) attr; | ||
459 | int i; | ||
460 | int ret; | ||
461 | |||
462 | *tab_attr = kmalloc((1 + len) * sizeof *tab_attr, GFP_KERNEL); | ||
463 | if (!*tab_attr) | ||
464 | return -ENOMEM; | ||
465 | |||
466 | memset(*tab_attr, 0, (1 + len) * sizeof *tab_attr); | ||
467 | |||
468 | for (i = 0; i < len; ++i) { | ||
469 | (*tab_attr)[i] = kmalloc(sizeof *(*tab_attr)[i], GFP_KERNEL); | ||
470 | if (!(*tab_attr)[i]) { | ||
471 | ret = -ENOMEM; | ||
472 | goto err; | ||
473 | } | ||
474 | memset((*tab_attr)[i], 0, sizeof *(*tab_attr)[i]); | ||
475 | (*tab_attr)[i]->attr.attr.name = kmalloc(8, GFP_KERNEL); | ||
476 | if (!(*tab_attr)[i]->attr.attr.name) { | ||
477 | ret = -ENOMEM; | ||
478 | goto err; | ||
479 | } | ||
480 | |||
481 | if (snprintf((*tab_attr)[i]->attr.attr.name, 8, "%d", i) >= 8) { | ||
482 | ret = -ENOMEM; | ||
483 | goto err; | ||
484 | } | ||
485 | |||
486 | (*tab_attr)[i]->attr.attr.mode = S_IRUGO; | ||
487 | (*tab_attr)[i]->attr.attr.owner = THIS_MODULE; | ||
488 | (*tab_attr)[i]->attr.show = show; | ||
489 | (*tab_attr)[i]->index = i; | ||
490 | } | ||
491 | |||
492 | return 0; | ||
493 | |||
494 | err: | ||
495 | for (i = 0; i < len; ++i) { | ||
496 | if ((*tab_attr)[i]) | ||
497 | kfree((*tab_attr)[i]->attr.attr.name); | ||
498 | kfree((*tab_attr)[i]); | ||
499 | } | ||
500 | |||
501 | kfree(*tab_attr); | ||
502 | |||
503 | return ret; | ||
504 | } | ||
505 | |||
506 | static int add_port(struct ib_device *device, int port_num) | ||
507 | { | ||
508 | struct ib_port *p; | ||
509 | struct ib_port_attr attr; | ||
510 | int i; | ||
511 | int ret; | ||
512 | |||
513 | ret = ib_query_port(device, port_num, &attr); | ||
514 | if (ret) | ||
515 | return ret; | ||
516 | |||
517 | p = kmalloc(sizeof *p, GFP_KERNEL); | ||
518 | if (!p) | ||
519 | return -ENOMEM; | ||
520 | memset(p, 0, sizeof *p); | ||
521 | |||
522 | p->ibdev = device; | ||
523 | p->port_num = port_num; | ||
524 | p->kobj.ktype = &port_type; | ||
525 | |||
526 | p->kobj.parent = kobject_get(&device->ports_parent); | ||
527 | if (!p->kobj.parent) { | ||
528 | ret = -EBUSY; | ||
529 | goto err; | ||
530 | } | ||
531 | |||
532 | ret = kobject_set_name(&p->kobj, "%d", port_num); | ||
533 | if (ret) | ||
534 | goto err_put; | ||
535 | |||
536 | ret = kobject_register(&p->kobj); | ||
537 | if (ret) | ||
538 | goto err_put; | ||
539 | |||
540 | ret = sysfs_create_group(&p->kobj, &pma_group); | ||
541 | if (ret) | ||
542 | goto err_put; | ||
543 | |||
544 | ret = alloc_group(&p->gid_attr, show_port_gid, attr.gid_tbl_len); | ||
545 | if (ret) | ||
546 | goto err_remove_pma; | ||
547 | |||
548 | p->gid_group.name = "gids"; | ||
549 | p->gid_group.attrs = p->gid_attr; | ||
550 | |||
551 | ret = sysfs_create_group(&p->kobj, &p->gid_group); | ||
552 | if (ret) | ||
553 | goto err_free_gid; | ||
554 | |||
555 | ret = alloc_group(&p->pkey_attr, show_port_pkey, attr.pkey_tbl_len); | ||
556 | if (ret) | ||
557 | goto err_remove_gid; | ||
558 | |||
559 | p->pkey_group.name = "pkeys"; | ||
560 | p->pkey_group.attrs = p->pkey_attr; | ||
561 | |||
562 | ret = sysfs_create_group(&p->kobj, &p->pkey_group); | ||
563 | if (ret) | ||
564 | goto err_free_pkey; | ||
565 | |||
566 | list_add_tail(&p->kobj.entry, &device->port_list); | ||
567 | |||
568 | return 0; | ||
569 | |||
570 | err_free_pkey: | ||
571 | for (i = 0; i < attr.pkey_tbl_len; ++i) { | ||
572 | kfree(p->pkey_attr[i]->name); | ||
573 | kfree(p->pkey_attr[i]); | ||
574 | } | ||
575 | |||
576 | kfree(p->pkey_attr); | ||
577 | |||
578 | err_remove_gid: | ||
579 | sysfs_remove_group(&p->kobj, &p->gid_group); | ||
580 | |||
581 | err_free_gid: | ||
582 | for (i = 0; i < attr.gid_tbl_len; ++i) { | ||
583 | kfree(p->gid_attr[i]->name); | ||
584 | kfree(p->gid_attr[i]); | ||
585 | } | ||
586 | |||
587 | kfree(p->gid_attr); | ||
588 | |||
589 | err_remove_pma: | ||
590 | sysfs_remove_group(&p->kobj, &pma_group); | ||
591 | |||
592 | err_put: | ||
593 | kobject_put(&device->ports_parent); | ||
594 | |||
595 | err: | ||
596 | kfree(p); | ||
597 | return ret; | ||
598 | } | ||
599 | |||
600 | static ssize_t show_node_type(struct class_device *cdev, char *buf) | ||
601 | { | ||
602 | struct ib_device *dev = container_of(cdev, struct ib_device, class_dev); | ||
603 | |||
604 | switch (dev->node_type) { | ||
605 | case IB_NODE_CA: return sprintf(buf, "%d: CA\n", dev->node_type); | ||
606 | case IB_NODE_SWITCH: return sprintf(buf, "%d: switch\n", dev->node_type); | ||
607 | case IB_NODE_ROUTER: return sprintf(buf, "%d: router\n", dev->node_type); | ||
608 | default: return sprintf(buf, "%d: <unknown>\n", dev->node_type); | ||
609 | } | ||
610 | } | ||
611 | |||
612 | static ssize_t show_sys_image_guid(struct class_device *cdev, char *buf) | ||
613 | { | ||
614 | struct ib_device *dev = container_of(cdev, struct ib_device, class_dev); | ||
615 | struct ib_device_attr attr; | ||
616 | ssize_t ret; | ||
617 | |||
618 | ret = ib_query_device(dev, &attr); | ||
619 | if (ret) | ||
620 | return ret; | ||
621 | |||
622 | return sprintf(buf, "%04x:%04x:%04x:%04x\n", | ||
623 | be16_to_cpu(((u16 *) &attr.sys_image_guid)[0]), | ||
624 | be16_to_cpu(((u16 *) &attr.sys_image_guid)[1]), | ||
625 | be16_to_cpu(((u16 *) &attr.sys_image_guid)[2]), | ||
626 | be16_to_cpu(((u16 *) &attr.sys_image_guid)[3])); | ||
627 | } | ||
628 | |||
629 | static ssize_t show_node_guid(struct class_device *cdev, char *buf) | ||
630 | { | ||
631 | struct ib_device *dev = container_of(cdev, struct ib_device, class_dev); | ||
632 | struct ib_device_attr attr; | ||
633 | ssize_t ret; | ||
634 | |||
635 | ret = ib_query_device(dev, &attr); | ||
636 | if (ret) | ||
637 | return ret; | ||
638 | |||
639 | return sprintf(buf, "%04x:%04x:%04x:%04x\n", | ||
640 | be16_to_cpu(((u16 *) &attr.node_guid)[0]), | ||
641 | be16_to_cpu(((u16 *) &attr.node_guid)[1]), | ||
642 | be16_to_cpu(((u16 *) &attr.node_guid)[2]), | ||
643 | be16_to_cpu(((u16 *) &attr.node_guid)[3])); | ||
644 | } | ||
645 | |||
646 | static CLASS_DEVICE_ATTR(node_type, S_IRUGO, show_node_type, NULL); | ||
647 | static CLASS_DEVICE_ATTR(sys_image_guid, S_IRUGO, show_sys_image_guid, NULL); | ||
648 | static CLASS_DEVICE_ATTR(node_guid, S_IRUGO, show_node_guid, NULL); | ||
649 | |||
650 | static struct class_device_attribute *ib_class_attributes[] = { | ||
651 | &class_device_attr_node_type, | ||
652 | &class_device_attr_sys_image_guid, | ||
653 | &class_device_attr_node_guid | ||
654 | }; | ||
655 | |||
656 | static struct class ib_class = { | ||
657 | .name = "infiniband", | ||
658 | .release = ib_device_release, | ||
659 | .hotplug = ib_device_hotplug, | ||
660 | }; | ||
661 | |||
662 | int ib_device_register_sysfs(struct ib_device *device) | ||
663 | { | ||
664 | struct class_device *class_dev = &device->class_dev; | ||
665 | int ret; | ||
666 | int i; | ||
667 | |||
668 | class_dev->class = &ib_class; | ||
669 | class_dev->class_data = device; | ||
670 | strlcpy(class_dev->class_id, device->name, BUS_ID_SIZE); | ||
671 | |||
672 | INIT_LIST_HEAD(&device->port_list); | ||
673 | |||
674 | ret = class_device_register(class_dev); | ||
675 | if (ret) | ||
676 | goto err; | ||
677 | |||
678 | for (i = 0; i < ARRAY_SIZE(ib_class_attributes); ++i) { | ||
679 | ret = class_device_create_file(class_dev, ib_class_attributes[i]); | ||
680 | if (ret) | ||
681 | goto err_unregister; | ||
682 | } | ||
683 | |||
684 | device->ports_parent.parent = kobject_get(&class_dev->kobj); | ||
685 | if (!device->ports_parent.parent) { | ||
686 | ret = -EBUSY; | ||
687 | goto err_unregister; | ||
688 | } | ||
689 | ret = kobject_set_name(&device->ports_parent, "ports"); | ||
690 | if (ret) | ||
691 | goto err_put; | ||
692 | ret = kobject_register(&device->ports_parent); | ||
693 | if (ret) | ||
694 | goto err_put; | ||
695 | |||
696 | if (device->node_type == IB_NODE_SWITCH) { | ||
697 | ret = add_port(device, 0); | ||
698 | if (ret) | ||
699 | goto err_put; | ||
700 | } else { | ||
701 | int i; | ||
702 | |||
703 | for (i = 1; i <= device->phys_port_cnt; ++i) { | ||
704 | ret = add_port(device, i); | ||
705 | if (ret) | ||
706 | goto err_put; | ||
707 | } | ||
708 | } | ||
709 | |||
710 | return 0; | ||
711 | |||
712 | err_put: | ||
713 | { | ||
714 | struct kobject *p, *t; | ||
715 | struct ib_port *port; | ||
716 | |||
717 | list_for_each_entry_safe(p, t, &device->port_list, entry) { | ||
718 | list_del(&p->entry); | ||
719 | port = container_of(p, struct ib_port, kobj); | ||
720 | sysfs_remove_group(p, &pma_group); | ||
721 | sysfs_remove_group(p, &port->pkey_group); | ||
722 | sysfs_remove_group(p, &port->gid_group); | ||
723 | kobject_unregister(p); | ||
724 | } | ||
725 | } | ||
726 | |||
727 | kobject_put(&class_dev->kobj); | ||
728 | |||
729 | err_unregister: | ||
730 | class_device_unregister(class_dev); | ||
731 | |||
732 | err: | ||
733 | return ret; | ||
734 | } | ||
735 | |||
736 | void ib_device_unregister_sysfs(struct ib_device *device) | ||
737 | { | ||
738 | struct kobject *p, *t; | ||
739 | struct ib_port *port; | ||
740 | |||
741 | list_for_each_entry_safe(p, t, &device->port_list, entry) { | ||
742 | list_del(&p->entry); | ||
743 | port = container_of(p, struct ib_port, kobj); | ||
744 | sysfs_remove_group(p, &pma_group); | ||
745 | sysfs_remove_group(p, &port->pkey_group); | ||
746 | sysfs_remove_group(p, &port->gid_group); | ||
747 | kobject_unregister(p); | ||
748 | } | ||
749 | |||
750 | kobject_unregister(&device->ports_parent); | ||
751 | class_device_unregister(&device->class_dev); | ||
752 | } | ||
753 | |||
754 | int ib_sysfs_setup(void) | ||
755 | { | ||
756 | return class_register(&ib_class); | ||
757 | } | ||
758 | |||
759 | void ib_sysfs_cleanup(void) | ||
760 | { | ||
761 | class_unregister(&ib_class); | ||
762 | } | ||
diff --git a/drivers/infiniband/core/ud_header.c b/drivers/infiniband/core/ud_header.c new file mode 100644 index 000000000000..dc4eb1db5e96 --- /dev/null +++ b/drivers/infiniband/core/ud_header.c | |||
@@ -0,0 +1,365 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Topspin Corporation. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | * $Id: ud_header.c 1349 2004-12-16 21:09:43Z roland $ | ||
33 | */ | ||
34 | |||
35 | #include <linux/errno.h> | ||
36 | |||
37 | #include <ib_pack.h> | ||
38 | |||
39 | #define STRUCT_FIELD(header, field) \ | ||
40 | .struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field), \ | ||
41 | .struct_size_bytes = sizeof ((struct ib_unpacked_ ## header *) 0)->field, \ | ||
42 | .field_name = #header ":" #field | ||
43 | |||
44 | static const struct ib_field lrh_table[] = { | ||
45 | { STRUCT_FIELD(lrh, virtual_lane), | ||
46 | .offset_words = 0, | ||
47 | .offset_bits = 0, | ||
48 | .size_bits = 4 }, | ||
49 | { STRUCT_FIELD(lrh, link_version), | ||
50 | .offset_words = 0, | ||
51 | .offset_bits = 4, | ||
52 | .size_bits = 4 }, | ||
53 | { STRUCT_FIELD(lrh, service_level), | ||
54 | .offset_words = 0, | ||
55 | .offset_bits = 8, | ||
56 | .size_bits = 4 }, | ||
57 | { RESERVED, | ||
58 | .offset_words = 0, | ||
59 | .offset_bits = 12, | ||
60 | .size_bits = 2 }, | ||
61 | { STRUCT_FIELD(lrh, link_next_header), | ||
62 | .offset_words = 0, | ||
63 | .offset_bits = 14, | ||
64 | .size_bits = 2 }, | ||
65 | { STRUCT_FIELD(lrh, destination_lid), | ||
66 | .offset_words = 0, | ||
67 | .offset_bits = 16, | ||
68 | .size_bits = 16 }, | ||
69 | { RESERVED, | ||
70 | .offset_words = 1, | ||
71 | .offset_bits = 0, | ||
72 | .size_bits = 5 }, | ||
73 | { STRUCT_FIELD(lrh, packet_length), | ||
74 | .offset_words = 1, | ||
75 | .offset_bits = 5, | ||
76 | .size_bits = 11 }, | ||
77 | { STRUCT_FIELD(lrh, source_lid), | ||
78 | .offset_words = 1, | ||
79 | .offset_bits = 16, | ||
80 | .size_bits = 16 } | ||
81 | }; | ||
82 | |||
83 | static const struct ib_field grh_table[] = { | ||
84 | { STRUCT_FIELD(grh, ip_version), | ||
85 | .offset_words = 0, | ||
86 | .offset_bits = 0, | ||
87 | .size_bits = 4 }, | ||
88 | { STRUCT_FIELD(grh, traffic_class), | ||
89 | .offset_words = 0, | ||
90 | .offset_bits = 4, | ||
91 | .size_bits = 8 }, | ||
92 | { STRUCT_FIELD(grh, flow_label), | ||
93 | .offset_words = 0, | ||
94 | .offset_bits = 12, | ||
95 | .size_bits = 20 }, | ||
96 | { STRUCT_FIELD(grh, payload_length), | ||
97 | .offset_words = 1, | ||
98 | .offset_bits = 0, | ||
99 | .size_bits = 16 }, | ||
100 | { STRUCT_FIELD(grh, next_header), | ||
101 | .offset_words = 1, | ||
102 | .offset_bits = 16, | ||
103 | .size_bits = 8 }, | ||
104 | { STRUCT_FIELD(grh, hop_limit), | ||
105 | .offset_words = 1, | ||
106 | .offset_bits = 24, | ||
107 | .size_bits = 8 }, | ||
108 | { STRUCT_FIELD(grh, source_gid), | ||
109 | .offset_words = 2, | ||
110 | .offset_bits = 0, | ||
111 | .size_bits = 128 }, | ||
112 | { STRUCT_FIELD(grh, destination_gid), | ||
113 | .offset_words = 6, | ||
114 | .offset_bits = 0, | ||
115 | .size_bits = 128 } | ||
116 | }; | ||
117 | |||
118 | static const struct ib_field bth_table[] = { | ||
119 | { STRUCT_FIELD(bth, opcode), | ||
120 | .offset_words = 0, | ||
121 | .offset_bits = 0, | ||
122 | .size_bits = 8 }, | ||
123 | { STRUCT_FIELD(bth, solicited_event), | ||
124 | .offset_words = 0, | ||
125 | .offset_bits = 8, | ||
126 | .size_bits = 1 }, | ||
127 | { STRUCT_FIELD(bth, mig_req), | ||
128 | .offset_words = 0, | ||
129 | .offset_bits = 9, | ||
130 | .size_bits = 1 }, | ||
131 | { STRUCT_FIELD(bth, pad_count), | ||
132 | .offset_words = 0, | ||
133 | .offset_bits = 10, | ||
134 | .size_bits = 2 }, | ||
135 | { STRUCT_FIELD(bth, transport_header_version), | ||
136 | .offset_words = 0, | ||
137 | .offset_bits = 12, | ||
138 | .size_bits = 4 }, | ||
139 | { STRUCT_FIELD(bth, pkey), | ||
140 | .offset_words = 0, | ||
141 | .offset_bits = 16, | ||
142 | .size_bits = 16 }, | ||
143 | { RESERVED, | ||
144 | .offset_words = 1, | ||
145 | .offset_bits = 0, | ||
146 | .size_bits = 8 }, | ||
147 | { STRUCT_FIELD(bth, destination_qpn), | ||
148 | .offset_words = 1, | ||
149 | .offset_bits = 8, | ||
150 | .size_bits = 24 }, | ||
151 | { STRUCT_FIELD(bth, ack_req), | ||
152 | .offset_words = 2, | ||
153 | .offset_bits = 0, | ||
154 | .size_bits = 1 }, | ||
155 | { RESERVED, | ||
156 | .offset_words = 2, | ||
157 | .offset_bits = 1, | ||
158 | .size_bits = 7 }, | ||
159 | { STRUCT_FIELD(bth, psn), | ||
160 | .offset_words = 2, | ||
161 | .offset_bits = 8, | ||
162 | .size_bits = 24 } | ||
163 | }; | ||
164 | |||
165 | static const struct ib_field deth_table[] = { | ||
166 | { STRUCT_FIELD(deth, qkey), | ||
167 | .offset_words = 0, | ||
168 | .offset_bits = 0, | ||
169 | .size_bits = 32 }, | ||
170 | { RESERVED, | ||
171 | .offset_words = 1, | ||
172 | .offset_bits = 0, | ||
173 | .size_bits = 8 }, | ||
174 | { STRUCT_FIELD(deth, source_qpn), | ||
175 | .offset_words = 1, | ||
176 | .offset_bits = 8, | ||
177 | .size_bits = 24 } | ||
178 | }; | ||
179 | |||
180 | /** | ||
181 | * ib_ud_header_init - Initialize UD header structure | ||
182 | * @payload_bytes:Length of packet payload | ||
183 | * @grh_present:GRH flag (if non-zero, GRH will be included) | ||
184 | * @header:Structure to initialize | ||
185 | * | ||
186 | * ib_ud_header_init() initializes the lrh.link_version, lrh.link_next_header, | ||
187 | * lrh.packet_length, grh.ip_version, grh.payload_length, | ||
188 | * grh.next_header, bth.opcode, bth.pad_count and | ||
189 | * bth.transport_header_version fields of a &struct ib_ud_header given | ||
190 | * the payload length and whether a GRH will be included. | ||
191 | */ | ||
192 | void ib_ud_header_init(int payload_bytes, | ||
193 | int grh_present, | ||
194 | struct ib_ud_header *header) | ||
195 | { | ||
196 | int header_len; | ||
197 | |||
198 | memset(header, 0, sizeof *header); | ||
199 | |||
200 | header_len = | ||
201 | IB_LRH_BYTES + | ||
202 | IB_BTH_BYTES + | ||
203 | IB_DETH_BYTES; | ||
204 | if (grh_present) { | ||
205 | header_len += IB_GRH_BYTES; | ||
206 | } | ||
207 | |||
208 | header->lrh.link_version = 0; | ||
209 | header->lrh.link_next_header = | ||
210 | grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL; | ||
211 | header->lrh.packet_length = (IB_LRH_BYTES + | ||
212 | IB_BTH_BYTES + | ||
213 | IB_DETH_BYTES + | ||
214 | payload_bytes + | ||
215 | 4 + /* ICRC */ | ||
216 | 3) / 4; /* round up */ | ||
217 | |||
218 | header->grh_present = grh_present; | ||
219 | if (grh_present) { | ||
220 | header->lrh.packet_length += IB_GRH_BYTES / 4; | ||
221 | |||
222 | header->grh.ip_version = 6; | ||
223 | header->grh.payload_length = | ||
224 | cpu_to_be16((IB_BTH_BYTES + | ||
225 | IB_DETH_BYTES + | ||
226 | payload_bytes + | ||
227 | 4 + /* ICRC */ | ||
228 | 3) & ~3); /* round up */ | ||
229 | header->grh.next_header = 0x1b; | ||
230 | } | ||
231 | |||
232 | cpu_to_be16s(&header->lrh.packet_length); | ||
233 | |||
234 | if (header->immediate_present) | ||
235 | header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; | ||
236 | else | ||
237 | header->bth.opcode = IB_OPCODE_UD_SEND_ONLY; | ||
238 | header->bth.pad_count = (4 - payload_bytes) & 3; | ||
239 | header->bth.transport_header_version = 0; | ||
240 | } | ||
241 | EXPORT_SYMBOL(ib_ud_header_init); | ||
242 | |||
243 | /** | ||
244 | * ib_ud_header_pack - Pack UD header struct into wire format | ||
245 | * @header:UD header struct | ||
246 | * @buf:Buffer to pack into | ||
247 | * | ||
248 | * ib_ud_header_pack() packs the UD header structure @header into wire | ||
249 | * format in the buffer @buf. | ||
250 | */ | ||
251 | int ib_ud_header_pack(struct ib_ud_header *header, | ||
252 | void *buf) | ||
253 | { | ||
254 | int len = 0; | ||
255 | |||
256 | ib_pack(lrh_table, ARRAY_SIZE(lrh_table), | ||
257 | &header->lrh, buf); | ||
258 | len += IB_LRH_BYTES; | ||
259 | |||
260 | if (header->grh_present) { | ||
261 | ib_pack(grh_table, ARRAY_SIZE(grh_table), | ||
262 | &header->grh, buf + len); | ||
263 | len += IB_GRH_BYTES; | ||
264 | } | ||
265 | |||
266 | ib_pack(bth_table, ARRAY_SIZE(bth_table), | ||
267 | &header->bth, buf + len); | ||
268 | len += IB_BTH_BYTES; | ||
269 | |||
270 | ib_pack(deth_table, ARRAY_SIZE(deth_table), | ||
271 | &header->deth, buf + len); | ||
272 | len += IB_DETH_BYTES; | ||
273 | |||
274 | if (header->immediate_present) { | ||
275 | memcpy(buf + len, &header->immediate_data, sizeof header->immediate_data); | ||
276 | len += sizeof header->immediate_data; | ||
277 | } | ||
278 | |||
279 | return len; | ||
280 | } | ||
281 | EXPORT_SYMBOL(ib_ud_header_pack); | ||
282 | |||
283 | /** | ||
284 | * ib_ud_header_unpack - Unpack UD header struct from wire format | ||
285 | * @header:UD header struct | ||
286 | * @buf:Buffer to pack into | ||
287 | * | ||
288 | * ib_ud_header_pack() unpacks the UD header structure @header from wire | ||
289 | * format in the buffer @buf. | ||
290 | */ | ||
291 | int ib_ud_header_unpack(void *buf, | ||
292 | struct ib_ud_header *header) | ||
293 | { | ||
294 | ib_unpack(lrh_table, ARRAY_SIZE(lrh_table), | ||
295 | buf, &header->lrh); | ||
296 | buf += IB_LRH_BYTES; | ||
297 | |||
298 | if (header->lrh.link_version != 0) { | ||
299 | printk(KERN_WARNING "Invalid LRH.link_version %d\n", | ||
300 | header->lrh.link_version); | ||
301 | return -EINVAL; | ||
302 | } | ||
303 | |||
304 | switch (header->lrh.link_next_header) { | ||
305 | case IB_LNH_IBA_LOCAL: | ||
306 | header->grh_present = 0; | ||
307 | break; | ||
308 | |||
309 | case IB_LNH_IBA_GLOBAL: | ||
310 | header->grh_present = 1; | ||
311 | ib_unpack(grh_table, ARRAY_SIZE(grh_table), | ||
312 | buf, &header->grh); | ||
313 | buf += IB_GRH_BYTES; | ||
314 | |||
315 | if (header->grh.ip_version != 6) { | ||
316 | printk(KERN_WARNING "Invalid GRH.ip_version %d\n", | ||
317 | header->grh.ip_version); | ||
318 | return -EINVAL; | ||
319 | } | ||
320 | if (header->grh.next_header != 0x1b) { | ||
321 | printk(KERN_WARNING "Invalid GRH.next_header 0x%02x\n", | ||
322 | header->grh.next_header); | ||
323 | return -EINVAL; | ||
324 | } | ||
325 | break; | ||
326 | |||
327 | default: | ||
328 | printk(KERN_WARNING "Invalid LRH.link_next_header %d\n", | ||
329 | header->lrh.link_next_header); | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | |||
333 | ib_unpack(bth_table, ARRAY_SIZE(bth_table), | ||
334 | buf, &header->bth); | ||
335 | buf += IB_BTH_BYTES; | ||
336 | |||
337 | switch (header->bth.opcode) { | ||
338 | case IB_OPCODE_UD_SEND_ONLY: | ||
339 | header->immediate_present = 0; | ||
340 | break; | ||
341 | case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE: | ||
342 | header->immediate_present = 1; | ||
343 | break; | ||
344 | default: | ||
345 | printk(KERN_WARNING "Invalid BTH.opcode 0x%02x\n", | ||
346 | header->bth.opcode); | ||
347 | return -EINVAL; | ||
348 | } | ||
349 | |||
350 | if (header->bth.transport_header_version != 0) { | ||
351 | printk(KERN_WARNING "Invalid BTH.transport_header_version %d\n", | ||
352 | header->bth.transport_header_version); | ||
353 | return -EINVAL; | ||
354 | } | ||
355 | |||
356 | ib_unpack(deth_table, ARRAY_SIZE(deth_table), | ||
357 | buf, &header->deth); | ||
358 | buf += IB_DETH_BYTES; | ||
359 | |||
360 | if (header->immediate_present) | ||
361 | memcpy(&header->immediate_data, buf, sizeof header->immediate_data); | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | EXPORT_SYMBOL(ib_ud_header_unpack); | ||
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c new file mode 100644 index 000000000000..54b4f33b0bf9 --- /dev/null +++ b/drivers/infiniband/core/user_mad.c | |||
@@ -0,0 +1,840 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Topspin Communications. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | * $Id: user_mad.c 1389 2004-12-27 22:56:47Z roland $ | ||
33 | */ | ||
34 | |||
35 | #include <linux/module.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/device.h> | ||
38 | #include <linux/err.h> | ||
39 | #include <linux/fs.h> | ||
40 | #include <linux/cdev.h> | ||
41 | #include <linux/pci.h> | ||
42 | #include <linux/dma-mapping.h> | ||
43 | #include <linux/poll.h> | ||
44 | #include <linux/rwsem.h> | ||
45 | #include <linux/kref.h> | ||
46 | |||
47 | #include <asm/uaccess.h> | ||
48 | #include <asm/semaphore.h> | ||
49 | |||
50 | #include <ib_mad.h> | ||
51 | #include <ib_user_mad.h> | ||
52 | |||
53 | MODULE_AUTHOR("Roland Dreier"); | ||
54 | MODULE_DESCRIPTION("InfiniBand userspace MAD packet access"); | ||
55 | MODULE_LICENSE("Dual BSD/GPL"); | ||
56 | |||
57 | enum { | ||
58 | IB_UMAD_MAX_PORTS = 64, | ||
59 | IB_UMAD_MAX_AGENTS = 32, | ||
60 | |||
61 | IB_UMAD_MAJOR = 231, | ||
62 | IB_UMAD_MINOR_BASE = 0 | ||
63 | }; | ||
64 | |||
65 | struct ib_umad_port { | ||
66 | int devnum; | ||
67 | struct cdev dev; | ||
68 | struct class_device class_dev; | ||
69 | |||
70 | int sm_devnum; | ||
71 | struct cdev sm_dev; | ||
72 | struct class_device sm_class_dev; | ||
73 | struct semaphore sm_sem; | ||
74 | |||
75 | struct ib_device *ib_dev; | ||
76 | struct ib_umad_device *umad_dev; | ||
77 | u8 port_num; | ||
78 | }; | ||
79 | |||
80 | struct ib_umad_device { | ||
81 | int start_port, end_port; | ||
82 | struct kref ref; | ||
83 | struct ib_umad_port port[0]; | ||
84 | }; | ||
85 | |||
86 | struct ib_umad_file { | ||
87 | struct ib_umad_port *port; | ||
88 | spinlock_t recv_lock; | ||
89 | struct list_head recv_list; | ||
90 | wait_queue_head_t recv_wait; | ||
91 | struct rw_semaphore agent_mutex; | ||
92 | struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS]; | ||
93 | struct ib_mr *mr[IB_UMAD_MAX_AGENTS]; | ||
94 | }; | ||
95 | |||
96 | struct ib_umad_packet { | ||
97 | struct ib_user_mad mad; | ||
98 | struct ib_ah *ah; | ||
99 | struct list_head list; | ||
100 | DECLARE_PCI_UNMAP_ADDR(mapping) | ||
101 | }; | ||
102 | |||
103 | static const dev_t base_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE); | ||
104 | static spinlock_t map_lock; | ||
105 | static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS * 2); | ||
106 | |||
107 | static void ib_umad_add_one(struct ib_device *device); | ||
108 | static void ib_umad_remove_one(struct ib_device *device); | ||
109 | |||
110 | static int queue_packet(struct ib_umad_file *file, | ||
111 | struct ib_mad_agent *agent, | ||
112 | struct ib_umad_packet *packet) | ||
113 | { | ||
114 | int ret = 1; | ||
115 | |||
116 | down_read(&file->agent_mutex); | ||
117 | for (packet->mad.id = 0; | ||
118 | packet->mad.id < IB_UMAD_MAX_AGENTS; | ||
119 | packet->mad.id++) | ||
120 | if (agent == file->agent[packet->mad.id]) { | ||
121 | spin_lock_irq(&file->recv_lock); | ||
122 | list_add_tail(&packet->list, &file->recv_list); | ||
123 | spin_unlock_irq(&file->recv_lock); | ||
124 | wake_up_interruptible(&file->recv_wait); | ||
125 | ret = 0; | ||
126 | break; | ||
127 | } | ||
128 | |||
129 | up_read(&file->agent_mutex); | ||
130 | |||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static void send_handler(struct ib_mad_agent *agent, | ||
135 | struct ib_mad_send_wc *send_wc) | ||
136 | { | ||
137 | struct ib_umad_file *file = agent->context; | ||
138 | struct ib_umad_packet *packet = | ||
139 | (void *) (unsigned long) send_wc->wr_id; | ||
140 | |||
141 | dma_unmap_single(agent->device->dma_device, | ||
142 | pci_unmap_addr(packet, mapping), | ||
143 | sizeof packet->mad.data, | ||
144 | DMA_TO_DEVICE); | ||
145 | ib_destroy_ah(packet->ah); | ||
146 | |||
147 | if (send_wc->status == IB_WC_RESP_TIMEOUT_ERR) { | ||
148 | packet->mad.status = ETIMEDOUT; | ||
149 | |||
150 | if (!queue_packet(file, agent, packet)) | ||
151 | return; | ||
152 | } | ||
153 | |||
154 | kfree(packet); | ||
155 | } | ||
156 | |||
157 | static void recv_handler(struct ib_mad_agent *agent, | ||
158 | struct ib_mad_recv_wc *mad_recv_wc) | ||
159 | { | ||
160 | struct ib_umad_file *file = agent->context; | ||
161 | struct ib_umad_packet *packet; | ||
162 | |||
163 | if (mad_recv_wc->wc->status != IB_WC_SUCCESS) | ||
164 | goto out; | ||
165 | |||
166 | packet = kmalloc(sizeof *packet, GFP_KERNEL); | ||
167 | if (!packet) | ||
168 | goto out; | ||
169 | |||
170 | memset(packet, 0, sizeof *packet); | ||
171 | |||
172 | memcpy(packet->mad.data, mad_recv_wc->recv_buf.mad, sizeof packet->mad.data); | ||
173 | packet->mad.status = 0; | ||
174 | packet->mad.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp); | ||
175 | packet->mad.lid = cpu_to_be16(mad_recv_wc->wc->slid); | ||
176 | packet->mad.sl = mad_recv_wc->wc->sl; | ||
177 | packet->mad.path_bits = mad_recv_wc->wc->dlid_path_bits; | ||
178 | packet->mad.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH); | ||
179 | if (packet->mad.grh_present) { | ||
180 | /* XXX parse GRH */ | ||
181 | packet->mad.gid_index = 0; | ||
182 | packet->mad.hop_limit = 0; | ||
183 | packet->mad.traffic_class = 0; | ||
184 | memset(packet->mad.gid, 0, 16); | ||
185 | packet->mad.flow_label = 0; | ||
186 | } | ||
187 | |||
188 | if (queue_packet(file, agent, packet)) | ||
189 | kfree(packet); | ||
190 | |||
191 | out: | ||
192 | ib_free_recv_mad(mad_recv_wc); | ||
193 | } | ||
194 | |||
195 | static ssize_t ib_umad_read(struct file *filp, char __user *buf, | ||
196 | size_t count, loff_t *pos) | ||
197 | { | ||
198 | struct ib_umad_file *file = filp->private_data; | ||
199 | struct ib_umad_packet *packet; | ||
200 | ssize_t ret; | ||
201 | |||
202 | if (count < sizeof (struct ib_user_mad)) | ||
203 | return -EINVAL; | ||
204 | |||
205 | spin_lock_irq(&file->recv_lock); | ||
206 | |||
207 | while (list_empty(&file->recv_list)) { | ||
208 | spin_unlock_irq(&file->recv_lock); | ||
209 | |||
210 | if (filp->f_flags & O_NONBLOCK) | ||
211 | return -EAGAIN; | ||
212 | |||
213 | if (wait_event_interruptible(file->recv_wait, | ||
214 | !list_empty(&file->recv_list))) | ||
215 | return -ERESTARTSYS; | ||
216 | |||
217 | spin_lock_irq(&file->recv_lock); | ||
218 | } | ||
219 | |||
220 | packet = list_entry(file->recv_list.next, struct ib_umad_packet, list); | ||
221 | list_del(&packet->list); | ||
222 | |||
223 | spin_unlock_irq(&file->recv_lock); | ||
224 | |||
225 | if (copy_to_user(buf, &packet->mad, sizeof packet->mad)) | ||
226 | ret = -EFAULT; | ||
227 | else | ||
228 | ret = sizeof packet->mad; | ||
229 | |||
230 | kfree(packet); | ||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | static ssize_t ib_umad_write(struct file *filp, const char __user *buf, | ||
235 | size_t count, loff_t *pos) | ||
236 | { | ||
237 | struct ib_umad_file *file = filp->private_data; | ||
238 | struct ib_umad_packet *packet; | ||
239 | struct ib_mad_agent *agent; | ||
240 | struct ib_ah_attr ah_attr; | ||
241 | struct ib_sge gather_list; | ||
242 | struct ib_send_wr *bad_wr, wr = { | ||
243 | .opcode = IB_WR_SEND, | ||
244 | .sg_list = &gather_list, | ||
245 | .num_sge = 1, | ||
246 | .send_flags = IB_SEND_SIGNALED, | ||
247 | }; | ||
248 | u8 method; | ||
249 | u64 *tid; | ||
250 | int ret; | ||
251 | |||
252 | if (count < sizeof (struct ib_user_mad)) | ||
253 | return -EINVAL; | ||
254 | |||
255 | packet = kmalloc(sizeof *packet, GFP_KERNEL); | ||
256 | if (!packet) | ||
257 | return -ENOMEM; | ||
258 | |||
259 | if (copy_from_user(&packet->mad, buf, sizeof packet->mad)) { | ||
260 | kfree(packet); | ||
261 | return -EFAULT; | ||
262 | } | ||
263 | |||
264 | if (packet->mad.id < 0 || packet->mad.id >= IB_UMAD_MAX_AGENTS) { | ||
265 | ret = -EINVAL; | ||
266 | goto err; | ||
267 | } | ||
268 | |||
269 | down_read(&file->agent_mutex); | ||
270 | |||
271 | agent = file->agent[packet->mad.id]; | ||
272 | if (!agent) { | ||
273 | ret = -EINVAL; | ||
274 | goto err_up; | ||
275 | } | ||
276 | |||
277 | /* | ||
278 | * If userspace is generating a request that will generate a | ||
279 | * response, we need to make sure the high-order part of the | ||
280 | * transaction ID matches the agent being used to send the | ||
281 | * MAD. | ||
282 | */ | ||
283 | method = ((struct ib_mad_hdr *) packet->mad.data)->method; | ||
284 | |||
285 | if (!(method & IB_MGMT_METHOD_RESP) && | ||
286 | method != IB_MGMT_METHOD_TRAP_REPRESS && | ||
287 | method != IB_MGMT_METHOD_SEND) { | ||
288 | tid = &((struct ib_mad_hdr *) packet->mad.data)->tid; | ||
289 | *tid = cpu_to_be64(((u64) agent->hi_tid) << 32 | | ||
290 | (be64_to_cpup(tid) & 0xffffffff)); | ||
291 | } | ||
292 | |||
293 | memset(&ah_attr, 0, sizeof ah_attr); | ||
294 | ah_attr.dlid = be16_to_cpu(packet->mad.lid); | ||
295 | ah_attr.sl = packet->mad.sl; | ||
296 | ah_attr.src_path_bits = packet->mad.path_bits; | ||
297 | ah_attr.port_num = file->port->port_num; | ||
298 | if (packet->mad.grh_present) { | ||
299 | ah_attr.ah_flags = IB_AH_GRH; | ||
300 | memcpy(ah_attr.grh.dgid.raw, packet->mad.gid, 16); | ||
301 | ah_attr.grh.flow_label = packet->mad.flow_label; | ||
302 | ah_attr.grh.hop_limit = packet->mad.hop_limit; | ||
303 | ah_attr.grh.traffic_class = packet->mad.traffic_class; | ||
304 | } | ||
305 | |||
306 | packet->ah = ib_create_ah(agent->qp->pd, &ah_attr); | ||
307 | if (IS_ERR(packet->ah)) { | ||
308 | ret = PTR_ERR(packet->ah); | ||
309 | goto err_up; | ||
310 | } | ||
311 | |||
312 | gather_list.addr = dma_map_single(agent->device->dma_device, | ||
313 | packet->mad.data, | ||
314 | sizeof packet->mad.data, | ||
315 | DMA_TO_DEVICE); | ||
316 | gather_list.length = sizeof packet->mad.data; | ||
317 | gather_list.lkey = file->mr[packet->mad.id]->lkey; | ||
318 | pci_unmap_addr_set(packet, mapping, gather_list.addr); | ||
319 | |||
320 | wr.wr.ud.mad_hdr = (struct ib_mad_hdr *) packet->mad.data; | ||
321 | wr.wr.ud.ah = packet->ah; | ||
322 | wr.wr.ud.remote_qpn = be32_to_cpu(packet->mad.qpn); | ||
323 | wr.wr.ud.remote_qkey = be32_to_cpu(packet->mad.qkey); | ||
324 | wr.wr.ud.timeout_ms = packet->mad.timeout_ms; | ||
325 | |||
326 | wr.wr_id = (unsigned long) packet; | ||
327 | |||
328 | ret = ib_post_send_mad(agent, &wr, &bad_wr); | ||
329 | if (ret) { | ||
330 | dma_unmap_single(agent->device->dma_device, | ||
331 | pci_unmap_addr(packet, mapping), | ||
332 | sizeof packet->mad.data, | ||
333 | DMA_TO_DEVICE); | ||
334 | goto err_up; | ||
335 | } | ||
336 | |||
337 | up_read(&file->agent_mutex); | ||
338 | |||
339 | return sizeof packet->mad; | ||
340 | |||
341 | err_up: | ||
342 | up_read(&file->agent_mutex); | ||
343 | |||
344 | err: | ||
345 | kfree(packet); | ||
346 | return ret; | ||
347 | } | ||
348 | |||
349 | static unsigned int ib_umad_poll(struct file *filp, struct poll_table_struct *wait) | ||
350 | { | ||
351 | struct ib_umad_file *file = filp->private_data; | ||
352 | |||
353 | /* we will always be able to post a MAD send */ | ||
354 | unsigned int mask = POLLOUT | POLLWRNORM; | ||
355 | |||
356 | poll_wait(filp, &file->recv_wait, wait); | ||
357 | |||
358 | if (!list_empty(&file->recv_list)) | ||
359 | mask |= POLLIN | POLLRDNORM; | ||
360 | |||
361 | return mask; | ||
362 | } | ||
363 | |||
364 | static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg) | ||
365 | { | ||
366 | struct ib_user_mad_reg_req ureq; | ||
367 | struct ib_mad_reg_req req; | ||
368 | struct ib_mad_agent *agent; | ||
369 | int agent_id; | ||
370 | int ret; | ||
371 | |||
372 | down_write(&file->agent_mutex); | ||
373 | |||
374 | if (copy_from_user(&ureq, (void __user *) arg, sizeof ureq)) { | ||
375 | ret = -EFAULT; | ||
376 | goto out; | ||
377 | } | ||
378 | |||
379 | if (ureq.qpn != 0 && ureq.qpn != 1) { | ||
380 | ret = -EINVAL; | ||
381 | goto out; | ||
382 | } | ||
383 | |||
384 | for (agent_id = 0; agent_id < IB_UMAD_MAX_AGENTS; ++agent_id) | ||
385 | if (!file->agent[agent_id]) | ||
386 | goto found; | ||
387 | |||
388 | ret = -ENOMEM; | ||
389 | goto out; | ||
390 | |||
391 | found: | ||
392 | req.mgmt_class = ureq.mgmt_class; | ||
393 | req.mgmt_class_version = ureq.mgmt_class_version; | ||
394 | memcpy(req.method_mask, ureq.method_mask, sizeof req.method_mask); | ||
395 | memcpy(req.oui, ureq.oui, sizeof req.oui); | ||
396 | |||
397 | agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num, | ||
398 | ureq.qpn ? IB_QPT_GSI : IB_QPT_SMI, | ||
399 | &req, 0, send_handler, recv_handler, | ||
400 | file); | ||
401 | if (IS_ERR(agent)) { | ||
402 | ret = PTR_ERR(agent); | ||
403 | goto out; | ||
404 | } | ||
405 | |||
406 | file->agent[agent_id] = agent; | ||
407 | |||
408 | file->mr[agent_id] = ib_get_dma_mr(agent->qp->pd, IB_ACCESS_LOCAL_WRITE); | ||
409 | if (IS_ERR(file->mr[agent_id])) { | ||
410 | ret = -ENOMEM; | ||
411 | goto err; | ||
412 | } | ||
413 | |||
414 | if (put_user(agent_id, | ||
415 | (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) { | ||
416 | ret = -EFAULT; | ||
417 | goto err_mr; | ||
418 | } | ||
419 | |||
420 | ret = 0; | ||
421 | goto out; | ||
422 | |||
423 | err_mr: | ||
424 | ib_dereg_mr(file->mr[agent_id]); | ||
425 | |||
426 | err: | ||
427 | file->agent[agent_id] = NULL; | ||
428 | ib_unregister_mad_agent(agent); | ||
429 | |||
430 | out: | ||
431 | up_write(&file->agent_mutex); | ||
432 | return ret; | ||
433 | } | ||
434 | |||
435 | static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg) | ||
436 | { | ||
437 | u32 id; | ||
438 | int ret = 0; | ||
439 | |||
440 | down_write(&file->agent_mutex); | ||
441 | |||
442 | if (get_user(id, (u32 __user *) arg)) { | ||
443 | ret = -EFAULT; | ||
444 | goto out; | ||
445 | } | ||
446 | |||
447 | if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !file->agent[id]) { | ||
448 | ret = -EINVAL; | ||
449 | goto out; | ||
450 | } | ||
451 | |||
452 | ib_dereg_mr(file->mr[id]); | ||
453 | ib_unregister_mad_agent(file->agent[id]); | ||
454 | file->agent[id] = NULL; | ||
455 | |||
456 | out: | ||
457 | up_write(&file->agent_mutex); | ||
458 | return ret; | ||
459 | } | ||
460 | |||
461 | static long ib_umad_ioctl(struct file *filp, | ||
462 | unsigned int cmd, unsigned long arg) | ||
463 | { | ||
464 | switch (cmd) { | ||
465 | case IB_USER_MAD_REGISTER_AGENT: | ||
466 | return ib_umad_reg_agent(filp->private_data, arg); | ||
467 | case IB_USER_MAD_UNREGISTER_AGENT: | ||
468 | return ib_umad_unreg_agent(filp->private_data, arg); | ||
469 | default: | ||
470 | return -ENOIOCTLCMD; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | static int ib_umad_open(struct inode *inode, struct file *filp) | ||
475 | { | ||
476 | struct ib_umad_port *port = | ||
477 | container_of(inode->i_cdev, struct ib_umad_port, dev); | ||
478 | struct ib_umad_file *file; | ||
479 | |||
480 | file = kmalloc(sizeof *file, GFP_KERNEL); | ||
481 | if (!file) | ||
482 | return -ENOMEM; | ||
483 | |||
484 | memset(file, 0, sizeof *file); | ||
485 | |||
486 | spin_lock_init(&file->recv_lock); | ||
487 | init_rwsem(&file->agent_mutex); | ||
488 | INIT_LIST_HEAD(&file->recv_list); | ||
489 | init_waitqueue_head(&file->recv_wait); | ||
490 | |||
491 | file->port = port; | ||
492 | filp->private_data = file; | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static int ib_umad_close(struct inode *inode, struct file *filp) | ||
498 | { | ||
499 | struct ib_umad_file *file = filp->private_data; | ||
500 | int i; | ||
501 | |||
502 | for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i) | ||
503 | if (file->agent[i]) { | ||
504 | ib_dereg_mr(file->mr[i]); | ||
505 | ib_unregister_mad_agent(file->agent[i]); | ||
506 | } | ||
507 | |||
508 | kfree(file); | ||
509 | |||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static struct file_operations umad_fops = { | ||
514 | .owner = THIS_MODULE, | ||
515 | .read = ib_umad_read, | ||
516 | .write = ib_umad_write, | ||
517 | .poll = ib_umad_poll, | ||
518 | .unlocked_ioctl = ib_umad_ioctl, | ||
519 | .compat_ioctl = ib_umad_ioctl, | ||
520 | .open = ib_umad_open, | ||
521 | .release = ib_umad_close | ||
522 | }; | ||
523 | |||
524 | static int ib_umad_sm_open(struct inode *inode, struct file *filp) | ||
525 | { | ||
526 | struct ib_umad_port *port = | ||
527 | container_of(inode->i_cdev, struct ib_umad_port, sm_dev); | ||
528 | struct ib_port_modify props = { | ||
529 | .set_port_cap_mask = IB_PORT_SM | ||
530 | }; | ||
531 | int ret; | ||
532 | |||
533 | if (filp->f_flags & O_NONBLOCK) { | ||
534 | if (down_trylock(&port->sm_sem)) | ||
535 | return -EAGAIN; | ||
536 | } else { | ||
537 | if (down_interruptible(&port->sm_sem)) | ||
538 | return -ERESTARTSYS; | ||
539 | } | ||
540 | |||
541 | ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props); | ||
542 | if (ret) { | ||
543 | up(&port->sm_sem); | ||
544 | return ret; | ||
545 | } | ||
546 | |||
547 | filp->private_data = port; | ||
548 | |||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | static int ib_umad_sm_close(struct inode *inode, struct file *filp) | ||
553 | { | ||
554 | struct ib_umad_port *port = filp->private_data; | ||
555 | struct ib_port_modify props = { | ||
556 | .clr_port_cap_mask = IB_PORT_SM | ||
557 | }; | ||
558 | int ret; | ||
559 | |||
560 | ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props); | ||
561 | up(&port->sm_sem); | ||
562 | |||
563 | return ret; | ||
564 | } | ||
565 | |||
566 | static struct file_operations umad_sm_fops = { | ||
567 | .owner = THIS_MODULE, | ||
568 | .open = ib_umad_sm_open, | ||
569 | .release = ib_umad_sm_close | ||
570 | }; | ||
571 | |||
572 | static struct ib_client umad_client = { | ||
573 | .name = "umad", | ||
574 | .add = ib_umad_add_one, | ||
575 | .remove = ib_umad_remove_one | ||
576 | }; | ||
577 | |||
578 | static ssize_t show_dev(struct class_device *class_dev, char *buf) | ||
579 | { | ||
580 | struct ib_umad_port *port = class_get_devdata(class_dev); | ||
581 | |||
582 | if (class_dev == &port->class_dev) | ||
583 | return print_dev_t(buf, port->dev.dev); | ||
584 | else | ||
585 | return print_dev_t(buf, port->sm_dev.dev); | ||
586 | } | ||
587 | static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); | ||
588 | |||
589 | static ssize_t show_ibdev(struct class_device *class_dev, char *buf) | ||
590 | { | ||
591 | struct ib_umad_port *port = class_get_devdata(class_dev); | ||
592 | |||
593 | return sprintf(buf, "%s\n", port->ib_dev->name); | ||
594 | } | ||
595 | static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); | ||
596 | |||
597 | static ssize_t show_port(struct class_device *class_dev, char *buf) | ||
598 | { | ||
599 | struct ib_umad_port *port = class_get_devdata(class_dev); | ||
600 | |||
601 | return sprintf(buf, "%d\n", port->port_num); | ||
602 | } | ||
603 | static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL); | ||
604 | |||
605 | static void ib_umad_release_dev(struct kref *ref) | ||
606 | { | ||
607 | struct ib_umad_device *dev = | ||
608 | container_of(ref, struct ib_umad_device, ref); | ||
609 | |||
610 | kfree(dev); | ||
611 | } | ||
612 | |||
613 | static void ib_umad_release_port(struct class_device *class_dev) | ||
614 | { | ||
615 | struct ib_umad_port *port = class_get_devdata(class_dev); | ||
616 | |||
617 | if (class_dev == &port->class_dev) { | ||
618 | cdev_del(&port->dev); | ||
619 | clear_bit(port->devnum, dev_map); | ||
620 | } else { | ||
621 | cdev_del(&port->sm_dev); | ||
622 | clear_bit(port->sm_devnum, dev_map); | ||
623 | } | ||
624 | |||
625 | kref_put(&port->umad_dev->ref, ib_umad_release_dev); | ||
626 | } | ||
627 | |||
628 | static struct class umad_class = { | ||
629 | .name = "infiniband_mad", | ||
630 | .release = ib_umad_release_port | ||
631 | }; | ||
632 | |||
633 | static ssize_t show_abi_version(struct class *class, char *buf) | ||
634 | { | ||
635 | return sprintf(buf, "%d\n", IB_USER_MAD_ABI_VERSION); | ||
636 | } | ||
637 | static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); | ||
638 | |||
639 | static int ib_umad_init_port(struct ib_device *device, int port_num, | ||
640 | struct ib_umad_port *port) | ||
641 | { | ||
642 | spin_lock(&map_lock); | ||
643 | port->devnum = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS); | ||
644 | if (port->devnum >= IB_UMAD_MAX_PORTS) { | ||
645 | spin_unlock(&map_lock); | ||
646 | return -1; | ||
647 | } | ||
648 | port->sm_devnum = find_next_zero_bit(dev_map, IB_UMAD_MAX_PORTS * 2, IB_UMAD_MAX_PORTS); | ||
649 | if (port->sm_devnum >= IB_UMAD_MAX_PORTS * 2) { | ||
650 | spin_unlock(&map_lock); | ||
651 | return -1; | ||
652 | } | ||
653 | set_bit(port->devnum, dev_map); | ||
654 | set_bit(port->sm_devnum, dev_map); | ||
655 | spin_unlock(&map_lock); | ||
656 | |||
657 | port->ib_dev = device; | ||
658 | port->port_num = port_num; | ||
659 | init_MUTEX(&port->sm_sem); | ||
660 | |||
661 | cdev_init(&port->dev, &umad_fops); | ||
662 | port->dev.owner = THIS_MODULE; | ||
663 | kobject_set_name(&port->dev.kobj, "umad%d", port->devnum); | ||
664 | if (cdev_add(&port->dev, base_dev + port->devnum, 1)) | ||
665 | return -1; | ||
666 | |||
667 | port->class_dev.class = &umad_class; | ||
668 | port->class_dev.dev = device->dma_device; | ||
669 | |||
670 | snprintf(port->class_dev.class_id, BUS_ID_SIZE, "umad%d", port->devnum); | ||
671 | |||
672 | if (class_device_register(&port->class_dev)) | ||
673 | goto err_cdev; | ||
674 | |||
675 | class_set_devdata(&port->class_dev, port); | ||
676 | kref_get(&port->umad_dev->ref); | ||
677 | |||
678 | if (class_device_create_file(&port->class_dev, &class_device_attr_dev)) | ||
679 | goto err_class; | ||
680 | if (class_device_create_file(&port->class_dev, &class_device_attr_ibdev)) | ||
681 | goto err_class; | ||
682 | if (class_device_create_file(&port->class_dev, &class_device_attr_port)) | ||
683 | goto err_class; | ||
684 | |||
685 | cdev_init(&port->sm_dev, &umad_sm_fops); | ||
686 | port->sm_dev.owner = THIS_MODULE; | ||
687 | kobject_set_name(&port->dev.kobj, "issm%d", port->sm_devnum - IB_UMAD_MAX_PORTS); | ||
688 | if (cdev_add(&port->sm_dev, base_dev + port->sm_devnum, 1)) | ||
689 | return -1; | ||
690 | |||
691 | port->sm_class_dev.class = &umad_class; | ||
692 | port->sm_class_dev.dev = device->dma_device; | ||
693 | |||
694 | snprintf(port->sm_class_dev.class_id, BUS_ID_SIZE, "issm%d", port->sm_devnum - IB_UMAD_MAX_PORTS); | ||
695 | |||
696 | if (class_device_register(&port->sm_class_dev)) | ||
697 | goto err_sm_cdev; | ||
698 | |||
699 | class_set_devdata(&port->sm_class_dev, port); | ||
700 | kref_get(&port->umad_dev->ref); | ||
701 | |||
702 | if (class_device_create_file(&port->sm_class_dev, &class_device_attr_dev)) | ||
703 | goto err_sm_class; | ||
704 | if (class_device_create_file(&port->sm_class_dev, &class_device_attr_ibdev)) | ||
705 | goto err_sm_class; | ||
706 | if (class_device_create_file(&port->sm_class_dev, &class_device_attr_port)) | ||
707 | goto err_sm_class; | ||
708 | |||
709 | return 0; | ||
710 | |||
711 | err_sm_class: | ||
712 | class_device_unregister(&port->sm_class_dev); | ||
713 | |||
714 | err_sm_cdev: | ||
715 | cdev_del(&port->sm_dev); | ||
716 | |||
717 | err_class: | ||
718 | class_device_unregister(&port->class_dev); | ||
719 | |||
720 | err_cdev: | ||
721 | cdev_del(&port->dev); | ||
722 | clear_bit(port->devnum, dev_map); | ||
723 | |||
724 | return -1; | ||
725 | } | ||
726 | |||
727 | static void ib_umad_add_one(struct ib_device *device) | ||
728 | { | ||
729 | struct ib_umad_device *umad_dev; | ||
730 | int s, e, i; | ||
731 | |||
732 | if (device->node_type == IB_NODE_SWITCH) | ||
733 | s = e = 0; | ||
734 | else { | ||
735 | s = 1; | ||
736 | e = device->phys_port_cnt; | ||
737 | } | ||
738 | |||
739 | umad_dev = kmalloc(sizeof *umad_dev + | ||
740 | (e - s + 1) * sizeof (struct ib_umad_port), | ||
741 | GFP_KERNEL); | ||
742 | if (!umad_dev) | ||
743 | return; | ||
744 | |||
745 | memset(umad_dev, 0, sizeof *umad_dev + | ||
746 | (e - s + 1) * sizeof (struct ib_umad_port)); | ||
747 | |||
748 | kref_init(&umad_dev->ref); | ||
749 | |||
750 | umad_dev->start_port = s; | ||
751 | umad_dev->end_port = e; | ||
752 | |||
753 | for (i = s; i <= e; ++i) { | ||
754 | umad_dev->port[i - s].umad_dev = umad_dev; | ||
755 | |||
756 | if (ib_umad_init_port(device, i, &umad_dev->port[i - s])) | ||
757 | goto err; | ||
758 | } | ||
759 | |||
760 | ib_set_client_data(device, &umad_client, umad_dev); | ||
761 | |||
762 | return; | ||
763 | |||
764 | err: | ||
765 | while (--i >= s) { | ||
766 | class_device_unregister(&umad_dev->port[i - s].class_dev); | ||
767 | class_device_unregister(&umad_dev->port[i - s].sm_class_dev); | ||
768 | } | ||
769 | |||
770 | kref_put(&umad_dev->ref, ib_umad_release_dev); | ||
771 | } | ||
772 | |||
773 | static void ib_umad_remove_one(struct ib_device *device) | ||
774 | { | ||
775 | struct ib_umad_device *umad_dev = ib_get_client_data(device, &umad_client); | ||
776 | int i; | ||
777 | |||
778 | if (!umad_dev) | ||
779 | return; | ||
780 | |||
781 | for (i = 0; i <= umad_dev->end_port - umad_dev->start_port; ++i) { | ||
782 | class_device_unregister(&umad_dev->port[i].class_dev); | ||
783 | class_device_unregister(&umad_dev->port[i].sm_class_dev); | ||
784 | } | ||
785 | |||
786 | kref_put(&umad_dev->ref, ib_umad_release_dev); | ||
787 | } | ||
788 | |||
789 | static int __init ib_umad_init(void) | ||
790 | { | ||
791 | int ret; | ||
792 | |||
793 | spin_lock_init(&map_lock); | ||
794 | |||
795 | ret = register_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2, | ||
796 | "infiniband_mad"); | ||
797 | if (ret) { | ||
798 | printk(KERN_ERR "user_mad: couldn't register device number\n"); | ||
799 | goto out; | ||
800 | } | ||
801 | |||
802 | ret = class_register(&umad_class); | ||
803 | if (ret) { | ||
804 | printk(KERN_ERR "user_mad: couldn't create class infiniband_mad\n"); | ||
805 | goto out_chrdev; | ||
806 | } | ||
807 | |||
808 | ret = class_create_file(&umad_class, &class_attr_abi_version); | ||
809 | if (ret) { | ||
810 | printk(KERN_ERR "user_mad: couldn't create abi_version attribute\n"); | ||
811 | goto out_class; | ||
812 | } | ||
813 | |||
814 | ret = ib_register_client(&umad_client); | ||
815 | if (ret) { | ||
816 | printk(KERN_ERR "user_mad: couldn't register ib_umad client\n"); | ||
817 | goto out_class; | ||
818 | } | ||
819 | |||
820 | return 0; | ||
821 | |||
822 | out_class: | ||
823 | class_unregister(&umad_class); | ||
824 | |||
825 | out_chrdev: | ||
826 | unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2); | ||
827 | |||
828 | out: | ||
829 | return ret; | ||
830 | } | ||
831 | |||
832 | static void __exit ib_umad_cleanup(void) | ||
833 | { | ||
834 | ib_unregister_client(&umad_client); | ||
835 | class_unregister(&umad_class); | ||
836 | unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2); | ||
837 | } | ||
838 | |||
839 | module_init(ib_umad_init); | ||
840 | module_exit(ib_umad_cleanup); | ||
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c new file mode 100644 index 000000000000..7c08ed0cd7dd --- /dev/null +++ b/drivers/infiniband/core/verbs.c | |||
@@ -0,0 +1,434 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. | ||
3 | * Copyright (c) 2004 Infinicon Corporation. All rights reserved. | ||
4 | * Copyright (c) 2004 Intel Corporation. All rights reserved. | ||
5 | * Copyright (c) 2004 Topspin Corporation. All rights reserved. | ||
6 | * Copyright (c) 2004 Voltaire Corporation. All rights reserved. | ||
7 | * | ||
8 | * This software is available to you under a choice of one of two | ||
9 | * licenses. You may choose to be licensed under the terms of the GNU | ||
10 | * General Public License (GPL) Version 2, available from the file | ||
11 | * COPYING in the main directory of this source tree, or the | ||
12 | * OpenIB.org BSD license below: | ||
13 | * | ||
14 | * Redistribution and use in source and binary forms, with or | ||
15 | * without modification, are permitted provided that the following | ||
16 | * conditions are met: | ||
17 | * | ||
18 | * - Redistributions of source code must retain the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer. | ||
21 | * | ||
22 | * - Redistributions in binary form must reproduce the above | ||
23 | * copyright notice, this list of conditions and the following | ||
24 | * disclaimer in the documentation and/or other materials | ||
25 | * provided with the distribution. | ||
26 | * | ||
27 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
28 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
29 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
30 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
31 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
32 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
33 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
34 | * SOFTWARE. | ||
35 | * | ||
36 | * $Id: verbs.c 1349 2004-12-16 21:09:43Z roland $ | ||
37 | */ | ||
38 | |||
39 | #include <linux/errno.h> | ||
40 | #include <linux/err.h> | ||
41 | |||
42 | #include <ib_verbs.h> | ||
43 | |||
44 | /* Protection domains */ | ||
45 | |||
46 | struct ib_pd *ib_alloc_pd(struct ib_device *device) | ||
47 | { | ||
48 | struct ib_pd *pd; | ||
49 | |||
50 | pd = device->alloc_pd(device); | ||
51 | |||
52 | if (!IS_ERR(pd)) { | ||
53 | pd->device = device; | ||
54 | atomic_set(&pd->usecnt, 0); | ||
55 | } | ||
56 | |||
57 | return pd; | ||
58 | } | ||
59 | EXPORT_SYMBOL(ib_alloc_pd); | ||
60 | |||
61 | int ib_dealloc_pd(struct ib_pd *pd) | ||
62 | { | ||
63 | if (atomic_read(&pd->usecnt)) | ||
64 | return -EBUSY; | ||
65 | |||
66 | return pd->device->dealloc_pd(pd); | ||
67 | } | ||
68 | EXPORT_SYMBOL(ib_dealloc_pd); | ||
69 | |||
70 | /* Address handles */ | ||
71 | |||
72 | struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) | ||
73 | { | ||
74 | struct ib_ah *ah; | ||
75 | |||
76 | ah = pd->device->create_ah(pd, ah_attr); | ||
77 | |||
78 | if (!IS_ERR(ah)) { | ||
79 | ah->device = pd->device; | ||
80 | ah->pd = pd; | ||
81 | atomic_inc(&pd->usecnt); | ||
82 | } | ||
83 | |||
84 | return ah; | ||
85 | } | ||
86 | EXPORT_SYMBOL(ib_create_ah); | ||
87 | |||
88 | int ib_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr) | ||
89 | { | ||
90 | return ah->device->modify_ah ? | ||
91 | ah->device->modify_ah(ah, ah_attr) : | ||
92 | -ENOSYS; | ||
93 | } | ||
94 | EXPORT_SYMBOL(ib_modify_ah); | ||
95 | |||
96 | int ib_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr) | ||
97 | { | ||
98 | return ah->device->query_ah ? | ||
99 | ah->device->query_ah(ah, ah_attr) : | ||
100 | -ENOSYS; | ||
101 | } | ||
102 | EXPORT_SYMBOL(ib_query_ah); | ||
103 | |||
104 | int ib_destroy_ah(struct ib_ah *ah) | ||
105 | { | ||
106 | struct ib_pd *pd; | ||
107 | int ret; | ||
108 | |||
109 | pd = ah->pd; | ||
110 | ret = ah->device->destroy_ah(ah); | ||
111 | if (!ret) | ||
112 | atomic_dec(&pd->usecnt); | ||
113 | |||
114 | return ret; | ||
115 | } | ||
116 | EXPORT_SYMBOL(ib_destroy_ah); | ||
117 | |||
118 | /* Queue pairs */ | ||
119 | |||
120 | struct ib_qp *ib_create_qp(struct ib_pd *pd, | ||
121 | struct ib_qp_init_attr *qp_init_attr) | ||
122 | { | ||
123 | struct ib_qp *qp; | ||
124 | |||
125 | qp = pd->device->create_qp(pd, qp_init_attr); | ||
126 | |||
127 | if (!IS_ERR(qp)) { | ||
128 | qp->device = pd->device; | ||
129 | qp->pd = pd; | ||
130 | qp->send_cq = qp_init_attr->send_cq; | ||
131 | qp->recv_cq = qp_init_attr->recv_cq; | ||
132 | qp->srq = qp_init_attr->srq; | ||
133 | qp->event_handler = qp_init_attr->event_handler; | ||
134 | qp->qp_context = qp_init_attr->qp_context; | ||
135 | qp->qp_type = qp_init_attr->qp_type; | ||
136 | atomic_inc(&pd->usecnt); | ||
137 | atomic_inc(&qp_init_attr->send_cq->usecnt); | ||
138 | atomic_inc(&qp_init_attr->recv_cq->usecnt); | ||
139 | if (qp_init_attr->srq) | ||
140 | atomic_inc(&qp_init_attr->srq->usecnt); | ||
141 | } | ||
142 | |||
143 | return qp; | ||
144 | } | ||
145 | EXPORT_SYMBOL(ib_create_qp); | ||
146 | |||
147 | int ib_modify_qp(struct ib_qp *qp, | ||
148 | struct ib_qp_attr *qp_attr, | ||
149 | int qp_attr_mask) | ||
150 | { | ||
151 | return qp->device->modify_qp(qp, qp_attr, qp_attr_mask); | ||
152 | } | ||
153 | EXPORT_SYMBOL(ib_modify_qp); | ||
154 | |||
155 | int ib_query_qp(struct ib_qp *qp, | ||
156 | struct ib_qp_attr *qp_attr, | ||
157 | int qp_attr_mask, | ||
158 | struct ib_qp_init_attr *qp_init_attr) | ||
159 | { | ||
160 | return qp->device->query_qp ? | ||
161 | qp->device->query_qp(qp, qp_attr, qp_attr_mask, qp_init_attr) : | ||
162 | -ENOSYS; | ||
163 | } | ||
164 | EXPORT_SYMBOL(ib_query_qp); | ||
165 | |||
166 | int ib_destroy_qp(struct ib_qp *qp) | ||
167 | { | ||
168 | struct ib_pd *pd; | ||
169 | struct ib_cq *scq, *rcq; | ||
170 | struct ib_srq *srq; | ||
171 | int ret; | ||
172 | |||
173 | pd = qp->pd; | ||
174 | scq = qp->send_cq; | ||
175 | rcq = qp->recv_cq; | ||
176 | srq = qp->srq; | ||
177 | |||
178 | ret = qp->device->destroy_qp(qp); | ||
179 | if (!ret) { | ||
180 | atomic_dec(&pd->usecnt); | ||
181 | atomic_dec(&scq->usecnt); | ||
182 | atomic_dec(&rcq->usecnt); | ||
183 | if (srq) | ||
184 | atomic_dec(&srq->usecnt); | ||
185 | } | ||
186 | |||
187 | return ret; | ||
188 | } | ||
189 | EXPORT_SYMBOL(ib_destroy_qp); | ||
190 | |||
191 | /* Completion queues */ | ||
192 | |||
193 | struct ib_cq *ib_create_cq(struct ib_device *device, | ||
194 | ib_comp_handler comp_handler, | ||
195 | void (*event_handler)(struct ib_event *, void *), | ||
196 | void *cq_context, int cqe) | ||
197 | { | ||
198 | struct ib_cq *cq; | ||
199 | |||
200 | cq = device->create_cq(device, cqe); | ||
201 | |||
202 | if (!IS_ERR(cq)) { | ||
203 | cq->device = device; | ||
204 | cq->comp_handler = comp_handler; | ||
205 | cq->event_handler = event_handler; | ||
206 | cq->cq_context = cq_context; | ||
207 | atomic_set(&cq->usecnt, 0); | ||
208 | } | ||
209 | |||
210 | return cq; | ||
211 | } | ||
212 | EXPORT_SYMBOL(ib_create_cq); | ||
213 | |||
214 | int ib_destroy_cq(struct ib_cq *cq) | ||
215 | { | ||
216 | if (atomic_read(&cq->usecnt)) | ||
217 | return -EBUSY; | ||
218 | |||
219 | return cq->device->destroy_cq(cq); | ||
220 | } | ||
221 | EXPORT_SYMBOL(ib_destroy_cq); | ||
222 | |||
223 | int ib_resize_cq(struct ib_cq *cq, | ||
224 | int cqe) | ||
225 | { | ||
226 | int ret; | ||
227 | |||
228 | if (!cq->device->resize_cq) | ||
229 | return -ENOSYS; | ||
230 | |||
231 | ret = cq->device->resize_cq(cq, &cqe); | ||
232 | if (!ret) | ||
233 | cq->cqe = cqe; | ||
234 | |||
235 | return ret; | ||
236 | } | ||
237 | EXPORT_SYMBOL(ib_resize_cq); | ||
238 | |||
239 | /* Memory regions */ | ||
240 | |||
241 | struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags) | ||
242 | { | ||
243 | struct ib_mr *mr; | ||
244 | |||
245 | mr = pd->device->get_dma_mr(pd, mr_access_flags); | ||
246 | |||
247 | if (!IS_ERR(mr)) { | ||
248 | mr->device = pd->device; | ||
249 | mr->pd = pd; | ||
250 | atomic_inc(&pd->usecnt); | ||
251 | atomic_set(&mr->usecnt, 0); | ||
252 | } | ||
253 | |||
254 | return mr; | ||
255 | } | ||
256 | EXPORT_SYMBOL(ib_get_dma_mr); | ||
257 | |||
258 | struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd, | ||
259 | struct ib_phys_buf *phys_buf_array, | ||
260 | int num_phys_buf, | ||
261 | int mr_access_flags, | ||
262 | u64 *iova_start) | ||
263 | { | ||
264 | struct ib_mr *mr; | ||
265 | |||
266 | mr = pd->device->reg_phys_mr(pd, phys_buf_array, num_phys_buf, | ||
267 | mr_access_flags, iova_start); | ||
268 | |||
269 | if (!IS_ERR(mr)) { | ||
270 | mr->device = pd->device; | ||
271 | mr->pd = pd; | ||
272 | atomic_inc(&pd->usecnt); | ||
273 | atomic_set(&mr->usecnt, 0); | ||
274 | } | ||
275 | |||
276 | return mr; | ||
277 | } | ||
278 | EXPORT_SYMBOL(ib_reg_phys_mr); | ||
279 | |||
280 | int ib_rereg_phys_mr(struct ib_mr *mr, | ||
281 | int mr_rereg_mask, | ||
282 | struct ib_pd *pd, | ||
283 | struct ib_phys_buf *phys_buf_array, | ||
284 | int num_phys_buf, | ||
285 | int mr_access_flags, | ||
286 | u64 *iova_start) | ||
287 | { | ||
288 | struct ib_pd *old_pd; | ||
289 | int ret; | ||
290 | |||
291 | if (!mr->device->rereg_phys_mr) | ||
292 | return -ENOSYS; | ||
293 | |||
294 | if (atomic_read(&mr->usecnt)) | ||
295 | return -EBUSY; | ||
296 | |||
297 | old_pd = mr->pd; | ||
298 | |||
299 | ret = mr->device->rereg_phys_mr(mr, mr_rereg_mask, pd, | ||
300 | phys_buf_array, num_phys_buf, | ||
301 | mr_access_flags, iova_start); | ||
302 | |||
303 | if (!ret && (mr_rereg_mask & IB_MR_REREG_PD)) { | ||
304 | atomic_dec(&old_pd->usecnt); | ||
305 | atomic_inc(&pd->usecnt); | ||
306 | } | ||
307 | |||
308 | return ret; | ||
309 | } | ||
310 | EXPORT_SYMBOL(ib_rereg_phys_mr); | ||
311 | |||
312 | int ib_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr) | ||
313 | { | ||
314 | return mr->device->query_mr ? | ||
315 | mr->device->query_mr(mr, mr_attr) : -ENOSYS; | ||
316 | } | ||
317 | EXPORT_SYMBOL(ib_query_mr); | ||
318 | |||
319 | int ib_dereg_mr(struct ib_mr *mr) | ||
320 | { | ||
321 | struct ib_pd *pd; | ||
322 | int ret; | ||
323 | |||
324 | if (atomic_read(&mr->usecnt)) | ||
325 | return -EBUSY; | ||
326 | |||
327 | pd = mr->pd; | ||
328 | ret = mr->device->dereg_mr(mr); | ||
329 | if (!ret) | ||
330 | atomic_dec(&pd->usecnt); | ||
331 | |||
332 | return ret; | ||
333 | } | ||
334 | EXPORT_SYMBOL(ib_dereg_mr); | ||
335 | |||
336 | /* Memory windows */ | ||
337 | |||
338 | struct ib_mw *ib_alloc_mw(struct ib_pd *pd) | ||
339 | { | ||
340 | struct ib_mw *mw; | ||
341 | |||
342 | if (!pd->device->alloc_mw) | ||
343 | return ERR_PTR(-ENOSYS); | ||
344 | |||
345 | mw = pd->device->alloc_mw(pd); | ||
346 | if (!IS_ERR(mw)) { | ||
347 | mw->device = pd->device; | ||
348 | mw->pd = pd; | ||
349 | atomic_inc(&pd->usecnt); | ||
350 | } | ||
351 | |||
352 | return mw; | ||
353 | } | ||
354 | EXPORT_SYMBOL(ib_alloc_mw); | ||
355 | |||
356 | int ib_dealloc_mw(struct ib_mw *mw) | ||
357 | { | ||
358 | struct ib_pd *pd; | ||
359 | int ret; | ||
360 | |||
361 | pd = mw->pd; | ||
362 | ret = mw->device->dealloc_mw(mw); | ||
363 | if (!ret) | ||
364 | atomic_dec(&pd->usecnt); | ||
365 | |||
366 | return ret; | ||
367 | } | ||
368 | EXPORT_SYMBOL(ib_dealloc_mw); | ||
369 | |||
370 | /* "Fast" memory regions */ | ||
371 | |||
372 | struct ib_fmr *ib_alloc_fmr(struct ib_pd *pd, | ||
373 | int mr_access_flags, | ||
374 | struct ib_fmr_attr *fmr_attr) | ||
375 | { | ||
376 | struct ib_fmr *fmr; | ||
377 | |||
378 | if (!pd->device->alloc_fmr) | ||
379 | return ERR_PTR(-ENOSYS); | ||
380 | |||
381 | fmr = pd->device->alloc_fmr(pd, mr_access_flags, fmr_attr); | ||
382 | if (!IS_ERR(fmr)) { | ||
383 | fmr->device = pd->device; | ||
384 | fmr->pd = pd; | ||
385 | atomic_inc(&pd->usecnt); | ||
386 | } | ||
387 | |||
388 | return fmr; | ||
389 | } | ||
390 | EXPORT_SYMBOL(ib_alloc_fmr); | ||
391 | |||
392 | int ib_unmap_fmr(struct list_head *fmr_list) | ||
393 | { | ||
394 | struct ib_fmr *fmr; | ||
395 | |||
396 | if (list_empty(fmr_list)) | ||
397 | return 0; | ||
398 | |||
399 | fmr = list_entry(fmr_list->next, struct ib_fmr, list); | ||
400 | return fmr->device->unmap_fmr(fmr_list); | ||
401 | } | ||
402 | EXPORT_SYMBOL(ib_unmap_fmr); | ||
403 | |||
404 | int ib_dealloc_fmr(struct ib_fmr *fmr) | ||
405 | { | ||
406 | struct ib_pd *pd; | ||
407 | int ret; | ||
408 | |||
409 | pd = fmr->pd; | ||
410 | ret = fmr->device->dealloc_fmr(fmr); | ||
411 | if (!ret) | ||
412 | atomic_dec(&pd->usecnt); | ||
413 | |||
414 | return ret; | ||
415 | } | ||
416 | EXPORT_SYMBOL(ib_dealloc_fmr); | ||
417 | |||
418 | /* Multicast groups */ | ||
419 | |||
420 | int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) | ||
421 | { | ||
422 | return qp->device->attach_mcast ? | ||
423 | qp->device->attach_mcast(qp, gid, lid) : | ||
424 | -ENOSYS; | ||
425 | } | ||
426 | EXPORT_SYMBOL(ib_attach_mcast); | ||
427 | |||
428 | int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) | ||
429 | { | ||
430 | return qp->device->detach_mcast ? | ||
431 | qp->device->detach_mcast(qp, gid, lid) : | ||
432 | -ENOSYS; | ||
433 | } | ||
434 | EXPORT_SYMBOL(ib_detach_mcast); | ||