[PATCH] IB: Introduce RMPP APIs
[deliverable/linux.git] / drivers / infiniband / core / sa_query.c
CommitLineData
1da177e4
LT
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
49MODULE_AUTHOR("Roland Dreier");
50MODULE_DESCRIPTION("InfiniBand subnet administration query support");
51MODULE_LICENSE("Dual BSD/GPL");
52
1da177e4
LT
53struct ib_sa_sm_ah {
54 struct ib_ah *ah;
55 struct kref ref;
56};
57
58struct ib_sa_port {
59 struct ib_mad_agent *agent;
1da177e4
LT
60 struct ib_sa_sm_ah *sm_ah;
61 struct work_struct update_task;
62 spinlock_t ah_lock;
63 u8 port_num;
64};
65
66struct ib_sa_device {
67 int start_port, end_port;
68 struct ib_event_handler event_handler;
69 struct ib_sa_port port[0];
70};
71
72struct ib_sa_query {
73 void (*callback)(struct ib_sa_query *, int, struct ib_sa_mad *);
74 void (*release)(struct ib_sa_query *);
75 struct ib_sa_port *port;
76 struct ib_sa_mad *mad;
77 struct ib_sa_sm_ah *sm_ah;
78 DECLARE_PCI_UNMAP_ADDR(mapping)
79 int id;
80};
81
82struct ib_sa_path_query {
83 void (*callback)(int, struct ib_sa_path_rec *, void *);
84 void *context;
85 struct ib_sa_query sa_query;
86};
87
88struct ib_sa_mcmember_query {
89 void (*callback)(int, struct ib_sa_mcmember_rec *, void *);
90 void *context;
91 struct ib_sa_query sa_query;
92};
93
94static void ib_sa_add_one(struct ib_device *device);
95static void ib_sa_remove_one(struct ib_device *device);
96
97static struct ib_client sa_client = {
98 .name = "sa",
99 .add = ib_sa_add_one,
100 .remove = ib_sa_remove_one
101};
102
103static spinlock_t idr_lock;
104static DEFINE_IDR(query_idr);
105
106static spinlock_t tid_lock;
107static u32 tid;
108
109enum {
110 IB_SA_ATTR_CLASS_PORTINFO = 0x01,
111 IB_SA_ATTR_NOTICE = 0x02,
112 IB_SA_ATTR_INFORM_INFO = 0x03,
113 IB_SA_ATTR_NODE_REC = 0x11,
114 IB_SA_ATTR_PORT_INFO_REC = 0x12,
115 IB_SA_ATTR_SL2VL_REC = 0x13,
116 IB_SA_ATTR_SWITCH_REC = 0x14,
117 IB_SA_ATTR_LINEAR_FDB_REC = 0x15,
118 IB_SA_ATTR_RANDOM_FDB_REC = 0x16,
119 IB_SA_ATTR_MCAST_FDB_REC = 0x17,
120 IB_SA_ATTR_SM_INFO_REC = 0x18,
121 IB_SA_ATTR_LINK_REC = 0x20,
122 IB_SA_ATTR_GUID_INFO_REC = 0x30,
123 IB_SA_ATTR_SERVICE_REC = 0x31,
124 IB_SA_ATTR_PARTITION_REC = 0x33,
125 IB_SA_ATTR_RANGE_REC = 0x34,
126 IB_SA_ATTR_PATH_REC = 0x35,
127 IB_SA_ATTR_VL_ARB_REC = 0x36,
128 IB_SA_ATTR_MC_GROUP_REC = 0x37,
129 IB_SA_ATTR_MC_MEMBER_REC = 0x38,
130 IB_SA_ATTR_TRACE_REC = 0x39,
131 IB_SA_ATTR_MULTI_PATH_REC = 0x3a,
132 IB_SA_ATTR_SERVICE_ASSOC_REC = 0x3b
133};
134
135#define PATH_REC_FIELD(field) \
136 .struct_offset_bytes = offsetof(struct ib_sa_path_rec, field), \
137 .struct_size_bytes = sizeof ((struct ib_sa_path_rec *) 0)->field, \
138 .field_name = "sa_path_rec:" #field
139
140static const struct ib_field path_rec_table[] = {
141 { RESERVED,
142 .offset_words = 0,
143 .offset_bits = 0,
144 .size_bits = 32 },
145 { RESERVED,
146 .offset_words = 1,
147 .offset_bits = 0,
148 .size_bits = 32 },
149 { PATH_REC_FIELD(dgid),
150 .offset_words = 2,
151 .offset_bits = 0,
152 .size_bits = 128 },
153 { PATH_REC_FIELD(sgid),
154 .offset_words = 6,
155 .offset_bits = 0,
156 .size_bits = 128 },
157 { PATH_REC_FIELD(dlid),
158 .offset_words = 10,
159 .offset_bits = 0,
160 .size_bits = 16 },
161 { PATH_REC_FIELD(slid),
162 .offset_words = 10,
163 .offset_bits = 16,
164 .size_bits = 16 },
165 { PATH_REC_FIELD(raw_traffic),
166 .offset_words = 11,
167 .offset_bits = 0,
168 .size_bits = 1 },
169 { RESERVED,
170 .offset_words = 11,
171 .offset_bits = 1,
172 .size_bits = 3 },
173 { PATH_REC_FIELD(flow_label),
174 .offset_words = 11,
175 .offset_bits = 4,
176 .size_bits = 20 },
177 { PATH_REC_FIELD(hop_limit),
178 .offset_words = 11,
179 .offset_bits = 24,
180 .size_bits = 8 },
181 { PATH_REC_FIELD(traffic_class),
182 .offset_words = 12,
183 .offset_bits = 0,
184 .size_bits = 8 },
185 { PATH_REC_FIELD(reversible),
186 .offset_words = 12,
187 .offset_bits = 8,
188 .size_bits = 1 },
189 { PATH_REC_FIELD(numb_path),
190 .offset_words = 12,
191 .offset_bits = 9,
192 .size_bits = 7 },
193 { PATH_REC_FIELD(pkey),
194 .offset_words = 12,
195 .offset_bits = 16,
196 .size_bits = 16 },
197 { RESERVED,
198 .offset_words = 13,
199 .offset_bits = 0,
200 .size_bits = 12 },
201 { PATH_REC_FIELD(sl),
202 .offset_words = 13,
203 .offset_bits = 12,
204 .size_bits = 4 },
205 { PATH_REC_FIELD(mtu_selector),
206 .offset_words = 13,
207 .offset_bits = 16,
208 .size_bits = 2 },
209 { PATH_REC_FIELD(mtu),
210 .offset_words = 13,
211 .offset_bits = 18,
212 .size_bits = 6 },
213 { PATH_REC_FIELD(rate_selector),
214 .offset_words = 13,
215 .offset_bits = 24,
216 .size_bits = 2 },
217 { PATH_REC_FIELD(rate),
218 .offset_words = 13,
219 .offset_bits = 26,
220 .size_bits = 6 },
221 { PATH_REC_FIELD(packet_life_time_selector),
222 .offset_words = 14,
223 .offset_bits = 0,
224 .size_bits = 2 },
225 { PATH_REC_FIELD(packet_life_time),
226 .offset_words = 14,
227 .offset_bits = 2,
228 .size_bits = 6 },
229 { PATH_REC_FIELD(preference),
230 .offset_words = 14,
231 .offset_bits = 8,
232 .size_bits = 8 },
233 { RESERVED,
234 .offset_words = 14,
235 .offset_bits = 16,
236 .size_bits = 48 },
237};
238
239#define MCMEMBER_REC_FIELD(field) \
240 .struct_offset_bytes = offsetof(struct ib_sa_mcmember_rec, field), \
241 .struct_size_bytes = sizeof ((struct ib_sa_mcmember_rec *) 0)->field, \
242 .field_name = "sa_mcmember_rec:" #field
243
244static const struct ib_field mcmember_rec_table[] = {
245 { MCMEMBER_REC_FIELD(mgid),
246 .offset_words = 0,
247 .offset_bits = 0,
248 .size_bits = 128 },
249 { MCMEMBER_REC_FIELD(port_gid),
250 .offset_words = 4,
251 .offset_bits = 0,
252 .size_bits = 128 },
253 { MCMEMBER_REC_FIELD(qkey),
254 .offset_words = 8,
255 .offset_bits = 0,
256 .size_bits = 32 },
257 { MCMEMBER_REC_FIELD(mlid),
258 .offset_words = 9,
259 .offset_bits = 0,
260 .size_bits = 16 },
261 { MCMEMBER_REC_FIELD(mtu_selector),
262 .offset_words = 9,
263 .offset_bits = 16,
264 .size_bits = 2 },
265 { MCMEMBER_REC_FIELD(mtu),
266 .offset_words = 9,
267 .offset_bits = 18,
268 .size_bits = 6 },
269 { MCMEMBER_REC_FIELD(traffic_class),
270 .offset_words = 9,
271 .offset_bits = 24,
272 .size_bits = 8 },
273 { MCMEMBER_REC_FIELD(pkey),
274 .offset_words = 10,
275 .offset_bits = 0,
276 .size_bits = 16 },
277 { MCMEMBER_REC_FIELD(rate_selector),
278 .offset_words = 10,
279 .offset_bits = 16,
280 .size_bits = 2 },
281 { MCMEMBER_REC_FIELD(rate),
282 .offset_words = 10,
283 .offset_bits = 18,
284 .size_bits = 6 },
285 { MCMEMBER_REC_FIELD(packet_life_time_selector),
286 .offset_words = 10,
287 .offset_bits = 24,
288 .size_bits = 2 },
289 { MCMEMBER_REC_FIELD(packet_life_time),
290 .offset_words = 10,
291 .offset_bits = 26,
292 .size_bits = 6 },
293 { MCMEMBER_REC_FIELD(sl),
294 .offset_words = 11,
295 .offset_bits = 0,
296 .size_bits = 4 },
297 { MCMEMBER_REC_FIELD(flow_label),
298 .offset_words = 11,
299 .offset_bits = 4,
300 .size_bits = 20 },
301 { MCMEMBER_REC_FIELD(hop_limit),
302 .offset_words = 11,
303 .offset_bits = 24,
304 .size_bits = 8 },
305 { MCMEMBER_REC_FIELD(scope),
306 .offset_words = 12,
307 .offset_bits = 0,
308 .size_bits = 4 },
309 { MCMEMBER_REC_FIELD(join_state),
310 .offset_words = 12,
311 .offset_bits = 4,
312 .size_bits = 4 },
313 { MCMEMBER_REC_FIELD(proxy_join),
314 .offset_words = 12,
315 .offset_bits = 8,
316 .size_bits = 1 },
317 { RESERVED,
318 .offset_words = 12,
319 .offset_bits = 9,
320 .size_bits = 23 },
321};
322
323static void free_sm_ah(struct kref *kref)
324{
325 struct ib_sa_sm_ah *sm_ah = container_of(kref, struct ib_sa_sm_ah, ref);
326
327 ib_destroy_ah(sm_ah->ah);
328 kfree(sm_ah);
329}
330
331static void update_sm_ah(void *port_ptr)
332{
333 struct ib_sa_port *port = port_ptr;
334 struct ib_sa_sm_ah *new_ah, *old_ah;
335 struct ib_port_attr port_attr;
336 struct ib_ah_attr ah_attr;
337
338 if (ib_query_port(port->agent->device, port->port_num, &port_attr)) {
339 printk(KERN_WARNING "Couldn't query port\n");
340 return;
341 }
342
343 new_ah = kmalloc(sizeof *new_ah, GFP_KERNEL);
344 if (!new_ah) {
345 printk(KERN_WARNING "Couldn't allocate new SM AH\n");
346 return;
347 }
348
349 kref_init(&new_ah->ref);
350
351 memset(&ah_attr, 0, sizeof ah_attr);
352 ah_attr.dlid = port_attr.sm_lid;
353 ah_attr.sl = port_attr.sm_sl;
354 ah_attr.port_num = port->port_num;
355
356 new_ah->ah = ib_create_ah(port->agent->qp->pd, &ah_attr);
357 if (IS_ERR(new_ah->ah)) {
358 printk(KERN_WARNING "Couldn't create new SM AH\n");
359 kfree(new_ah);
360 return;
361 }
362
363 spin_lock_irq(&port->ah_lock);
364 old_ah = port->sm_ah;
365 port->sm_ah = new_ah;
366 spin_unlock_irq(&port->ah_lock);
367
368 if (old_ah)
369 kref_put(&old_ah->ref, free_sm_ah);
370}
371
372static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event)
373{
374 if (event->event == IB_EVENT_PORT_ERR ||
375 event->event == IB_EVENT_PORT_ACTIVE ||
376 event->event == IB_EVENT_LID_CHANGE ||
377 event->event == IB_EVENT_PKEY_CHANGE ||
378 event->event == IB_EVENT_SM_CHANGE) {
379 struct ib_sa_device *sa_dev =
380 ib_get_client_data(event->device, &sa_client);
381
382 schedule_work(&sa_dev->port[event->element.port_num -
383 sa_dev->start_port].update_task);
384 }
385}
386
387/**
388 * ib_sa_cancel_query - try to cancel an SA query
389 * @id:ID of query to cancel
390 * @query:query pointer to cancel
391 *
392 * Try to cancel an SA query. If the id and query don't match up or
393 * the query has already completed, nothing is done. Otherwise the
394 * query is canceled and will complete with a status of -EINTR.
395 */
396void ib_sa_cancel_query(int id, struct ib_sa_query *query)
397{
398 unsigned long flags;
399 struct ib_mad_agent *agent;
400
401 spin_lock_irqsave(&idr_lock, flags);
402 if (idr_find(&query_idr, id) != query) {
403 spin_unlock_irqrestore(&idr_lock, flags);
404 return;
405 }
406 agent = query->port->agent;
407 spin_unlock_irqrestore(&idr_lock, flags);
408
409 ib_cancel_mad(agent, id);
410}
411EXPORT_SYMBOL(ib_sa_cancel_query);
412
413static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent)
414{
415 unsigned long flags;
416
417 memset(mad, 0, sizeof *mad);
418
419 mad->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
420 mad->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
421 mad->mad_hdr.class_version = IB_SA_CLASS_VERSION;
422
423 spin_lock_irqsave(&tid_lock, flags);
424 mad->mad_hdr.tid =
425 cpu_to_be64(((u64) agent->hi_tid) << 32 | tid++);
426 spin_unlock_irqrestore(&tid_lock, flags);
427}
428
429static int send_mad(struct ib_sa_query *query, int timeout_ms)
430{
431 struct ib_sa_port *port = query->port;
432 unsigned long flags;
433 int ret;
434 struct ib_sge gather_list;
435 struct ib_send_wr *bad_wr, wr = {
436 .opcode = IB_WR_SEND,
437 .sg_list = &gather_list,
438 .num_sge = 1,
439 .send_flags = IB_SEND_SIGNALED,
440 .wr = {
441 .ud = {
442 .mad_hdr = &query->mad->mad_hdr,
443 .remote_qpn = 1,
444 .remote_qkey = IB_QP1_QKEY,
f75b7a52
HR
445 .timeout_ms = timeout_ms,
446 .retries = 0
1da177e4
LT
447 }
448 }
449 };
450
451retry:
452 if (!idr_pre_get(&query_idr, GFP_ATOMIC))
453 return -ENOMEM;
454 spin_lock_irqsave(&idr_lock, flags);
455 ret = idr_get_new(&query_idr, query, &query->id);
456 spin_unlock_irqrestore(&idr_lock, flags);
457 if (ret == -EAGAIN)
458 goto retry;
459 if (ret)
460 return ret;
461
462 wr.wr_id = query->id;
463
464 spin_lock_irqsave(&port->ah_lock, flags);
465 kref_get(&port->sm_ah->ref);
466 query->sm_ah = port->sm_ah;
467 wr.wr.ud.ah = port->sm_ah->ah;
468 spin_unlock_irqrestore(&port->ah_lock, flags);
469
470 gather_list.addr = dma_map_single(port->agent->device->dma_device,
471 query->mad,
472 sizeof (struct ib_sa_mad),
473 DMA_TO_DEVICE);
474 gather_list.length = sizeof (struct ib_sa_mad);
b82cab6b 475 gather_list.lkey = port->agent->mr->lkey;
1da177e4
LT
476 pci_unmap_addr_set(query, mapping, gather_list.addr);
477
478 ret = ib_post_send_mad(port->agent, &wr, &bad_wr);
479 if (ret) {
480 dma_unmap_single(port->agent->device->dma_device,
481 pci_unmap_addr(query, mapping),
482 sizeof (struct ib_sa_mad),
483 DMA_TO_DEVICE);
484 kref_put(&query->sm_ah->ref, free_sm_ah);
485 spin_lock_irqsave(&idr_lock, flags);
486 idr_remove(&query_idr, query->id);
487 spin_unlock_irqrestore(&idr_lock, flags);
488 }
489
dae4c1d2
RD
490 /*
491 * It's not safe to dereference query any more, because the
492 * send may already have completed and freed the query in
493 * another context. So use wr.wr_id, which has a copy of the
494 * query's id.
495 */
496 return ret ? ret : wr.wr_id;
1da177e4
LT
497}
498
499static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
500 int status,
501 struct ib_sa_mad *mad)
502{
503 struct ib_sa_path_query *query =
504 container_of(sa_query, struct ib_sa_path_query, sa_query);
505
506 if (mad) {
507 struct ib_sa_path_rec rec;
508
509 ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table),
510 mad->data, &rec);
511 query->callback(status, &rec, query->context);
512 } else
513 query->callback(status, NULL, query->context);
514}
515
516static void ib_sa_path_rec_release(struct ib_sa_query *sa_query)
517{
518 kfree(sa_query->mad);
519 kfree(container_of(sa_query, struct ib_sa_path_query, sa_query));
520}
521
522/**
523 * ib_sa_path_rec_get - Start a Path get query
524 * @device:device to send query on
525 * @port_num: port number to send query on
526 * @rec:Path Record to send in query
527 * @comp_mask:component mask to send in query
528 * @timeout_ms:time to wait for response
529 * @gfp_mask:GFP mask to use for internal allocations
530 * @callback:function called when query completes, times out or is
531 * canceled
532 * @context:opaque user context passed to callback
533 * @sa_query:query context, used to cancel query
534 *
535 * Send a Path Record Get query to the SA to look up a path. The
536 * callback function will be called when the query completes (or
537 * fails); status is 0 for a successful response, -EINTR if the query
538 * is canceled, -ETIMEDOUT is the query timed out, or -EIO if an error
539 * occurred sending the query. The resp parameter of the callback is
540 * only valid if status is 0.
541 *
542 * If the return value of ib_sa_path_rec_get() is negative, it is an
543 * error code. Otherwise it is a query ID that can be used to cancel
544 * the query.
545 */
546int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,
547 struct ib_sa_path_rec *rec,
548 ib_sa_comp_mask comp_mask,
549 int timeout_ms, int gfp_mask,
550 void (*callback)(int status,
551 struct ib_sa_path_rec *resp,
552 void *context),
553 void *context,
554 struct ib_sa_query **sa_query)
555{
556 struct ib_sa_path_query *query;
557 struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client);
558 struct ib_sa_port *port = &sa_dev->port[port_num - sa_dev->start_port];
559 struct ib_mad_agent *agent = port->agent;
560 int ret;
561
562 query = kmalloc(sizeof *query, gfp_mask);
563 if (!query)
564 return -ENOMEM;
565 query->sa_query.mad = kmalloc(sizeof *query->sa_query.mad, gfp_mask);
566 if (!query->sa_query.mad) {
567 kfree(query);
568 return -ENOMEM;
569 }
570
571 query->callback = callback;
572 query->context = context;
573
574 init_mad(query->sa_query.mad, agent);
575
e4f50f00 576 query->sa_query.callback = callback ? ib_sa_path_rec_callback : NULL;
1da177e4
LT
577 query->sa_query.release = ib_sa_path_rec_release;
578 query->sa_query.port = port;
579 query->sa_query.mad->mad_hdr.method = IB_MGMT_METHOD_GET;
580 query->sa_query.mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_PATH_REC);
581 query->sa_query.mad->sa_hdr.comp_mask = comp_mask;
582
583 ib_pack(path_rec_table, ARRAY_SIZE(path_rec_table),
584 rec, query->sa_query.mad->data);
585
586 *sa_query = &query->sa_query;
dae4c1d2 587
1da177e4 588 ret = send_mad(&query->sa_query, timeout_ms);
dae4c1d2 589 if (ret < 0) {
1da177e4
LT
590 *sa_query = NULL;
591 kfree(query->sa_query.mad);
592 kfree(query);
593 }
594
dae4c1d2 595 return ret;
1da177e4
LT
596}
597EXPORT_SYMBOL(ib_sa_path_rec_get);
598
599static void ib_sa_mcmember_rec_callback(struct ib_sa_query *sa_query,
600 int status,
601 struct ib_sa_mad *mad)
602{
603 struct ib_sa_mcmember_query *query =
604 container_of(sa_query, struct ib_sa_mcmember_query, sa_query);
605
606 if (mad) {
607 struct ib_sa_mcmember_rec rec;
608
609 ib_unpack(mcmember_rec_table, ARRAY_SIZE(mcmember_rec_table),
610 mad->data, &rec);
611 query->callback(status, &rec, query->context);
612 } else
613 query->callback(status, NULL, query->context);
614}
615
616static void ib_sa_mcmember_rec_release(struct ib_sa_query *sa_query)
617{
618 kfree(sa_query->mad);
619 kfree(container_of(sa_query, struct ib_sa_mcmember_query, sa_query));
620}
621
622int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num,
623 u8 method,
624 struct ib_sa_mcmember_rec *rec,
625 ib_sa_comp_mask comp_mask,
626 int timeout_ms, int gfp_mask,
627 void (*callback)(int status,
628 struct ib_sa_mcmember_rec *resp,
629 void *context),
630 void *context,
631 struct ib_sa_query **sa_query)
632{
633 struct ib_sa_mcmember_query *query;
634 struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client);
635 struct ib_sa_port *port = &sa_dev->port[port_num - sa_dev->start_port];
636 struct ib_mad_agent *agent = port->agent;
637 int ret;
638
639 query = kmalloc(sizeof *query, gfp_mask);
640 if (!query)
641 return -ENOMEM;
642 query->sa_query.mad = kmalloc(sizeof *query->sa_query.mad, gfp_mask);
643 if (!query->sa_query.mad) {
644 kfree(query);
645 return -ENOMEM;
646 }
647
648 query->callback = callback;
649 query->context = context;
650
651 init_mad(query->sa_query.mad, agent);
652
e4f50f00 653 query->sa_query.callback = callback ? ib_sa_mcmember_rec_callback : NULL;
1da177e4
LT
654 query->sa_query.release = ib_sa_mcmember_rec_release;
655 query->sa_query.port = port;
656 query->sa_query.mad->mad_hdr.method = method;
657 query->sa_query.mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_MC_MEMBER_REC);
658 query->sa_query.mad->sa_hdr.comp_mask = comp_mask;
659
660 ib_pack(mcmember_rec_table, ARRAY_SIZE(mcmember_rec_table),
661 rec, query->sa_query.mad->data);
662
663 *sa_query = &query->sa_query;
dae4c1d2 664
1da177e4 665 ret = send_mad(&query->sa_query, timeout_ms);
dae4c1d2 666 if (ret < 0) {
1da177e4
LT
667 *sa_query = NULL;
668 kfree(query->sa_query.mad);
669 kfree(query);
670 }
671
dae4c1d2 672 return ret;
1da177e4
LT
673}
674EXPORT_SYMBOL(ib_sa_mcmember_rec_query);
675
676static void send_handler(struct ib_mad_agent *agent,
677 struct ib_mad_send_wc *mad_send_wc)
678{
679 struct ib_sa_query *query;
680 unsigned long flags;
681
682 spin_lock_irqsave(&idr_lock, flags);
683 query = idr_find(&query_idr, mad_send_wc->wr_id);
684 spin_unlock_irqrestore(&idr_lock, flags);
685
686 if (!query)
687 return;
688
e4f50f00
RD
689 if (query->callback)
690 switch (mad_send_wc->status) {
691 case IB_WC_SUCCESS:
692 /* No callback -- already got recv */
693 break;
694 case IB_WC_RESP_TIMEOUT_ERR:
695 query->callback(query, -ETIMEDOUT, NULL);
696 break;
697 case IB_WC_WR_FLUSH_ERR:
698 query->callback(query, -EINTR, NULL);
699 break;
700 default:
701 query->callback(query, -EIO, NULL);
702 break;
703 }
1da177e4
LT
704
705 dma_unmap_single(agent->device->dma_device,
706 pci_unmap_addr(query, mapping),
707 sizeof (struct ib_sa_mad),
708 DMA_TO_DEVICE);
709 kref_put(&query->sm_ah->ref, free_sm_ah);
710
711 query->release(query);
712
713 spin_lock_irqsave(&idr_lock, flags);
714 idr_remove(&query_idr, mad_send_wc->wr_id);
715 spin_unlock_irqrestore(&idr_lock, flags);
716}
717
718static void recv_handler(struct ib_mad_agent *mad_agent,
719 struct ib_mad_recv_wc *mad_recv_wc)
720{
721 struct ib_sa_query *query;
722 unsigned long flags;
723
724 spin_lock_irqsave(&idr_lock, flags);
725 query = idr_find(&query_idr, mad_recv_wc->wc->wr_id);
726 spin_unlock_irqrestore(&idr_lock, flags);
727
e4f50f00 728 if (query && query->callback) {
1da177e4
LT
729 if (mad_recv_wc->wc->status == IB_WC_SUCCESS)
730 query->callback(query,
731 mad_recv_wc->recv_buf.mad->mad_hdr.status ?
732 -EINVAL : 0,
733 (struct ib_sa_mad *) mad_recv_wc->recv_buf.mad);
734 else
735 query->callback(query, -EIO, NULL);
736 }
737
738 ib_free_recv_mad(mad_recv_wc);
739}
740
741static void ib_sa_add_one(struct ib_device *device)
742{
743 struct ib_sa_device *sa_dev;
744 int s, e, i;
745
746 if (device->node_type == IB_NODE_SWITCH)
747 s = e = 0;
748 else {
749 s = 1;
750 e = device->phys_port_cnt;
751 }
752
753 sa_dev = kmalloc(sizeof *sa_dev +
754 (e - s + 1) * sizeof (struct ib_sa_port),
755 GFP_KERNEL);
756 if (!sa_dev)
757 return;
758
759 sa_dev->start_port = s;
760 sa_dev->end_port = e;
761
762 for (i = 0; i <= e - s; ++i) {
1da177e4
LT
763 sa_dev->port[i].sm_ah = NULL;
764 sa_dev->port[i].port_num = i + s;
765 spin_lock_init(&sa_dev->port[i].ah_lock);
766
767 sa_dev->port[i].agent =
768 ib_register_mad_agent(device, i + s, IB_QPT_GSI,
769 NULL, 0, send_handler,
770 recv_handler, sa_dev);
771 if (IS_ERR(sa_dev->port[i].agent))
772 goto err;
773
1da177e4
LT
774 INIT_WORK(&sa_dev->port[i].update_task,
775 update_sm_ah, &sa_dev->port[i]);
776 }
777
778 ib_set_client_data(device, &sa_client, sa_dev);
779
780 /*
781 * We register our event handler after everything is set up,
782 * and then update our cached info after the event handler is
783 * registered to avoid any problems if a port changes state
784 * during our initialization.
785 */
786
787 INIT_IB_EVENT_HANDLER(&sa_dev->event_handler, device, ib_sa_event);
788 if (ib_register_event_handler(&sa_dev->event_handler))
789 goto err;
790
791 for (i = 0; i <= e - s; ++i)
792 update_sm_ah(&sa_dev->port[i]);
793
794 return;
795
796err:
b82cab6b 797 while (--i >= 0)
1da177e4 798 ib_unregister_mad_agent(sa_dev->port[i].agent);
1da177e4
LT
799
800 kfree(sa_dev);
801
802 return;
803}
804
805static void ib_sa_remove_one(struct ib_device *device)
806{
807 struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client);
808 int i;
809
810 if (!sa_dev)
811 return;
812
813 ib_unregister_event_handler(&sa_dev->event_handler);
814
815 for (i = 0; i <= sa_dev->end_port - sa_dev->start_port; ++i) {
816 ib_unregister_mad_agent(sa_dev->port[i].agent);
817 kref_put(&sa_dev->port[i].sm_ah->ref, free_sm_ah);
818 }
819
820 kfree(sa_dev);
821}
822
823static int __init ib_sa_init(void)
824{
825 int ret;
826
827 spin_lock_init(&idr_lock);
828 spin_lock_init(&tid_lock);
829
830 get_random_bytes(&tid, sizeof tid);
831
832 ret = ib_register_client(&sa_client);
833 if (ret)
834 printk(KERN_ERR "Couldn't register ib_sa client\n");
835
836 return ret;
837}
838
839static void __exit ib_sa_cleanup(void)
840{
841 ib_unregister_client(&sa_client);
842}
843
844module_init(ib_sa_init);
845module_exit(ib_sa_cleanup);
This page took 0.082886 seconds and 5 git commands to generate.