1 /*
2 * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved.
3 * Copyright (c) 2005, 2006 Voltaire Inc. All rights reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses. You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directorY of this source tree, or the
9 * OpenIB.org BSD license below:
10 *
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
13 * conditions are met:
14 *
15 * - Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer.
18 *
19 * - Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials
22 * provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 *
33 * $Id$
34 */
35 #include <linux/module.h>
36 #include <linux/device.h>
37 #include <linux/err.h>
38
39 #include <rdma/ib_mad.h>
40 #include <rdma/ib_smi.h>
41 #include <rdma/ib_sa.h>
42
43 MODULE_AUTHOR("Sean Hefty");
44 MODULE_DESCRIPTION("InfiniBand MAD viewer");
45 MODULE_LICENSE("Dual BSD/GPL");
46
47 static void madeye_remove_one(struct ib_device *device);
48 static void madeye_add_one(struct ib_device *device);
49
50 static struct ib_client madeye_client = {
51 .name = "madeye",
52 .add = madeye_add_one,
53 .remove = madeye_remove_one
54 };
55
56 struct madeye_port {
57 struct ib_mad_agent *smi_agent;
58 struct ib_mad_agent *gsi_agent;
59 };
60
61 static int smp = 1;
62 static int gmp = 1;
63 static int mgmt_class = 0;
64 static int attr_id = 0;
65 static int data = 0;
66
67 module_param(smp, int, 0444);
68 module_param(gmp, int, 0444);
69 module_param(mgmt_class, int, 0444);
70 module_param(attr_id, int, 0444);
71 module_param(data, int, 0444);
72
73 MODULE_PARM_DESC(smp, "Display all SMPs (default=1)");
74 MODULE_PARM_DESC(gmp, "Display all GMPs (default=1)");
75 MODULE_PARM_DESC(mgmt_class, "Display all MADs of specified class (default=0)");
76 MODULE_PARM_DESC(attr_id, "Display add MADs of specified attribute ID (default=0)");
77 MODULE_PARM_DESC(data, "Display data area of MADs (default=0)");
78
get_class_name(u8 mgmt_class)79 static char * get_class_name(u8 mgmt_class)
80 {
81 switch(mgmt_class) {
82 case IB_MGMT_CLASS_SUBN_LID_ROUTED:
83 return "LID routed SMP";
84 case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE:
85 return "Directed route SMP";
86 case IB_MGMT_CLASS_SUBN_ADM:
87 return "Subnet admin.";
88 case IB_MGMT_CLASS_PERF_MGMT:
89 return "Perf. mgmt.";
90 case IB_MGMT_CLASS_BM:
91 return "Baseboard mgmt.";
92 case IB_MGMT_CLASS_DEVICE_MGMT:
93 return "Device mgmt.";
94 case IB_MGMT_CLASS_CM:
95 return "Comm. mgmt.";
96 case IB_MGMT_CLASS_SNMP:
97 return "SNMP";
98 default:
99 return "Unknown vendor/application";
100 }
101 }
102
get_method_name(u8 mgmt_class,u8 method)103 static char * get_method_name(u8 mgmt_class, u8 method)
104 {
105 switch(method) {
106 case IB_MGMT_METHOD_GET:
107 return "Get";
108 case IB_MGMT_METHOD_SET:
109 return "Set";
110 case IB_MGMT_METHOD_GET_RESP:
111 return "Get response";
112 case IB_MGMT_METHOD_SEND:
113 return "Send";
114 case IB_MGMT_METHOD_SEND | IB_MGMT_METHOD_RESP:
115 return "Send response";
116 case IB_MGMT_METHOD_TRAP:
117 return "Trap";
118 case IB_MGMT_METHOD_REPORT:
119 return "Report";
120 case IB_MGMT_METHOD_REPORT_RESP:
121 return "Report response";
122 case IB_MGMT_METHOD_TRAP_REPRESS:
123 return "Trap repress";
124 default:
125 break;
126 }
127
128 switch (mgmt_class) {
129 case IB_MGMT_CLASS_SUBN_ADM:
130 switch (method) {
131 case IB_SA_METHOD_GET_TABLE:
132 return "Get table";
133 case IB_SA_METHOD_GET_TABLE_RESP:
134 return "Get table response";
135 case IB_SA_METHOD_DELETE:
136 return "Delete";
137 case IB_SA_METHOD_DELETE_RESP:
138 return "Delete response";
139 case IB_SA_METHOD_GET_MULTI:
140 return "Get Multi";
141 case IB_SA_METHOD_GET_MULTI_RESP:
142 return "Get Multi response";
143 case IB_SA_METHOD_GET_TRACE_TBL:
144 return "Get Trace Table response";
145 default:
146 break;
147 }
148 default:
149 break;
150 }
151
152 return "Unknown";
153 }
154
print_status_details(u16 status)155 static void print_status_details(u16 status)
156 {
157 if (status & 0x0001)
158 printk(" busy\n");
159 if (status & 0x0002)
160 printk(" redirection required\n");
161 switch((status & 0x001C) >> 2) {
162 case 1:
163 printk(" bad version\n");
164 break;
165 case 2:
166 printk(" method not supported\n");
167 break;
168 case 3:
169 printk(" method/attribute combo not supported\n");
170 break;
171 case 7:
172 printk(" invalid attribute/modifier value\n");
173 break;
174 }
175 }
176
get_sa_attr(__be16 attr)177 static char * get_sa_attr(__be16 attr)
178 {
179 switch(attr) {
180 case IB_SA_ATTR_CLASS_PORTINFO:
181 return "Class Port Info";
182 case IB_SA_ATTR_NOTICE:
183 return "Notice";
184 case IB_SA_ATTR_INFORM_INFO:
185 return "Inform Info";
186 case IB_SA_ATTR_NODE_REC:
187 return "Node Record";
188 case IB_SA_ATTR_PORT_INFO_REC:
189 return "PortInfo Record";
190 case IB_SA_ATTR_SL2VL_REC:
191 return "SL to VL Record";
192 case IB_SA_ATTR_SWITCH_REC:
193 return "Switch Record";
194 case IB_SA_ATTR_LINEAR_FDB_REC:
195 return "Linear FDB Record";
196 case IB_SA_ATTR_RANDOM_FDB_REC:
197 return "Random FDB Record";
198 case IB_SA_ATTR_MCAST_FDB_REC:
199 return "Multicast FDB Record";
200 case IB_SA_ATTR_SM_INFO_REC:
201 return "SM Info Record";
202 case IB_SA_ATTR_LINK_REC:
203 return "Link Record";
204 case IB_SA_ATTR_GUID_INFO_REC:
205 return "Guid Info Record";
206 case IB_SA_ATTR_SERVICE_REC:
207 return "Service Record";
208 case IB_SA_ATTR_PARTITION_REC:
209 return "Partition Record";
210 case IB_SA_ATTR_PATH_REC:
211 return "Path Record";
212 case IB_SA_ATTR_VL_ARB_REC:
213 return "VL Arb Record";
214 case IB_SA_ATTR_MC_MEMBER_REC:
215 return "MC Member Record";
216 case IB_SA_ATTR_TRACE_REC:
217 return "Trace Record";
218 case IB_SA_ATTR_MULTI_PATH_REC:
219 return "Multi Path Record";
220 case IB_SA_ATTR_SERVICE_ASSOC_REC:
221 return "Service Assoc Record";
222 case IB_SA_ATTR_INFORM_INFO_REC:
223 return "Inform Info Record";
224 default:
225 return "";
226 }
227 }
228
print_mad_hdr(struct ib_mad_hdr * mad_hdr)229 static void print_mad_hdr(struct ib_mad_hdr *mad_hdr)
230 {
231 printk("MAD version....0x%01x\n", mad_hdr->base_version);
232 printk("Class..........0x%01x (%s)\n", mad_hdr->mgmt_class,
233 get_class_name(mad_hdr->mgmt_class));
234 printk("Class version..0x%01x\n", mad_hdr->class_version);
235 printk("Method.........0x%01x (%s)\n", mad_hdr->method,
236 get_method_name(mad_hdr->mgmt_class, mad_hdr->method));
237 printk("Status.........0x%02x\n", be16_to_cpu(mad_hdr->status));
238 if (mad_hdr->status)
239 print_status_details(be16_to_cpu(mad_hdr->status));
240 printk("Class specific.0x%02x\n", be16_to_cpu(mad_hdr->class_specific));
241 printk("Trans ID.......0x%llx\n",
242 (unsigned long long)be64_to_cpu(mad_hdr->tid));
243 if (mad_hdr->mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
244 printk("Attr ID........0x%02x (%s)\n",
245 be16_to_cpu(mad_hdr->attr_id),
246 get_sa_attr(be16_to_cpu(mad_hdr->attr_id)));
247 else
248 printk("Attr ID........0x%02x\n",
249 be16_to_cpu(mad_hdr->attr_id));
250 printk("Attr modifier..0x%04x\n", be32_to_cpu(mad_hdr->attr_mod));
251 }
252
get_rmpp_type(u8 rmpp_type)253 static char * get_rmpp_type(u8 rmpp_type)
254 {
255 switch (rmpp_type) {
256 case IB_MGMT_RMPP_TYPE_DATA:
257 return "Data";
258 case IB_MGMT_RMPP_TYPE_ACK:
259 return "Ack";
260 case IB_MGMT_RMPP_TYPE_STOP:
261 return "Stop";
262 case IB_MGMT_RMPP_TYPE_ABORT:
263 return "Abort";
264 default:
265 return "Unknown";
266 }
267 }
268
get_rmpp_flags(u8 rmpp_flags)269 static char * get_rmpp_flags(u8 rmpp_flags)
270 {
271 if (rmpp_flags & IB_MGMT_RMPP_FLAG_ACTIVE)
272 if (rmpp_flags & IB_MGMT_RMPP_FLAG_FIRST)
273 if (rmpp_flags & IB_MGMT_RMPP_FLAG_LAST)
274 return "Active - First & Last";
275 else
276 return "Active - First";
277 else
278 if (rmpp_flags & IB_MGMT_RMPP_FLAG_LAST)
279 return "Active - Last";
280 else
281 return "Active";
282 else
283 return "Inactive";
284 }
285
print_rmpp_hdr(struct ib_rmpp_hdr * rmpp_hdr)286 static void print_rmpp_hdr(struct ib_rmpp_hdr *rmpp_hdr)
287 {
288 printk("RMPP version...0x%01x\n", rmpp_hdr->rmpp_version);
289 printk("RMPP type......0x%01x (%s)\n", rmpp_hdr->rmpp_type,
290 get_rmpp_type(rmpp_hdr->rmpp_type));
291 printk("RMPP RRespTime.0x%01x\n", ib_get_rmpp_resptime(rmpp_hdr));
292 printk("RMPP flags.....0x%01x (%s)\n", ib_get_rmpp_flags(rmpp_hdr),
293 get_rmpp_flags(ib_get_rmpp_flags(rmpp_hdr)));
294 printk("RMPP status....0x%01x\n", rmpp_hdr->rmpp_status);
295 printk("Seg number.....0x%04x\n", be32_to_cpu(rmpp_hdr->seg_num));
296 switch (rmpp_hdr->rmpp_type) {
297 case IB_MGMT_RMPP_TYPE_DATA:
298 printk("Payload len....0x%04x\n",
299 be32_to_cpu(rmpp_hdr->paylen_newwin));
300 break;
301 case IB_MGMT_RMPP_TYPE_ACK:
302 printk("New window.....0x%04x\n",
303 be32_to_cpu(rmpp_hdr->paylen_newwin));
304 break;
305 default:
306 printk("Data 2.........0x%04x\n",
307 be32_to_cpu(rmpp_hdr->paylen_newwin));
308 break;
309 }
310 }
311
get_smp_attr(__be16 attr)312 static char * get_smp_attr(__be16 attr)
313 {
314 switch (attr) {
315 case IB_SMP_ATTR_NOTICE:
316 return "notice";
317 case IB_SMP_ATTR_NODE_DESC:
318 return "node description";
319 case IB_SMP_ATTR_NODE_INFO:
320 return "node info";
321 case IB_SMP_ATTR_SWITCH_INFO:
322 return "switch info";
323 case IB_SMP_ATTR_GUID_INFO:
324 return "GUID info";
325 case IB_SMP_ATTR_PORT_INFO:
326 return "port info";
327 case IB_SMP_ATTR_PKEY_TABLE:
328 return "pkey table";
329 case IB_SMP_ATTR_SL_TO_VL_TABLE:
330 return "SL to VL table";
331 case IB_SMP_ATTR_VL_ARB_TABLE:
332 return "VL arbitration table";
333 case IB_SMP_ATTR_LINEAR_FORWARD_TABLE:
334 return "linear forwarding table";
335 case IB_SMP_ATTR_RANDOM_FORWARD_TABLE:
336 return "random forward table";
337 case IB_SMP_ATTR_MCAST_FORWARD_TABLE:
338 return "multicast forward table";
339 case IB_SMP_ATTR_SM_INFO:
340 return "SM info";
341 case IB_SMP_ATTR_VENDOR_DIAG:
342 return "vendor diags";
343 case IB_SMP_ATTR_LED_INFO:
344 return "LED info";
345 default:
346 return "";
347 }
348 }
349
print_smp(struct ib_smp * smp)350 static void print_smp(struct ib_smp *smp)
351 {
352 int i;
353
354 printk("MAD version....0x%01x\n", smp->base_version);
355 printk("Class..........0x%01x (%s)\n", smp->mgmt_class,
356 get_class_name(smp->mgmt_class));
357 printk("Class version..0x%01x\n", smp->class_version);
358 printk("Method.........0x%01x (%s)\n", smp->method,
359 get_method_name(smp->mgmt_class, smp->method));
360 printk("Status.........0x%02x\n", be16_to_cpu(smp->status));
361 if (smp->status)
362 print_status_details(be16_to_cpu(smp->status));
363 printk("Hop pointer....0x%01x\n", smp->hop_ptr);
364 printk("Hop counter....0x%01x\n", smp->hop_cnt);
365 printk("Trans ID.......0x%llx\n",
366 (unsigned long long)be64_to_cpu(smp->tid));
367 printk("Attr ID........0x%02x (%s)\n", be16_to_cpu(smp->attr_id),
368 get_smp_attr(smp->attr_id));
369 printk("Attr modifier..0x%04x\n", be32_to_cpu(smp->attr_mod));
370
371 printk("Mkey...........0x%llx\n",
372 (unsigned long long)be64_to_cpu(smp->mkey));
373 printk("DR SLID........0x%02x\n", be16_to_cpu(smp->dr_slid));
374 printk("DR DLID........0x%02x", be16_to_cpu(smp->dr_dlid));
375
376 if (data) {
377 for (i = 0; i < IB_SMP_DATA_SIZE; i++) {
378 if (i % 16 == 0)
379 printk("\nSMP Data.......");
380 printk("%01x ", smp->data[i]);
381 }
382 for (i = 0; i < IB_SMP_MAX_PATH_HOPS; i++) {
383 if (i % 16 == 0)
384 printk("\nInitial path...");
385 printk("%01x ", smp->initial_path[i]);
386 }
387 for (i = 0; i < IB_SMP_MAX_PATH_HOPS; i++) {
388 if (i % 16 == 0)
389 printk("\nReturn path....");
390 printk("%01x ", smp->return_path[i]);
391 }
392 }
393 printk("\n");
394 }
395
snoop_smi_handler(struct ib_mad_agent * mad_agent,struct ib_mad_send_buf * send_buf,struct ib_mad_send_wc * mad_send_wc)396 static void snoop_smi_handler(struct ib_mad_agent *mad_agent,
397 struct ib_mad_send_buf *send_buf,
398 struct ib_mad_send_wc *mad_send_wc)
399 {
400 struct ib_mad_hdr *hdr = send_buf->mad;
401
402 if (!smp && hdr->mgmt_class != mgmt_class)
403 return;
404 if (attr_id && be16_to_cpu(hdr->attr_id) != attr_id)
405 return;
406
407 printk("Madeye:sent SMP\n");
408 print_smp(send_buf->mad);
409 }
410
recv_smi_handler(struct ib_mad_agent * mad_agent,struct ib_mad_recv_wc * mad_recv_wc)411 static void recv_smi_handler(struct ib_mad_agent *mad_agent,
412 struct ib_mad_recv_wc *mad_recv_wc)
413 {
414 if (!smp && mad_recv_wc->recv_buf.mad->mad_hdr.mgmt_class != mgmt_class)
415 return;
416 if (attr_id && be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) != attr_id)
417 return;
418
419 printk("Madeye:recv SMP\n");
420 print_smp((struct ib_smp *)&mad_recv_wc->recv_buf.mad->mad_hdr);
421 }
422
is_rmpp_mad(struct ib_mad_hdr * mad_hdr)423 static int is_rmpp_mad(struct ib_mad_hdr *mad_hdr)
424 {
425 if (mad_hdr->mgmt_class == IB_MGMT_CLASS_SUBN_ADM) {
426 switch (mad_hdr->method) {
427 case IB_SA_METHOD_GET_TABLE:
428 case IB_SA_METHOD_GET_TABLE_RESP:
429 case IB_SA_METHOD_GET_MULTI_RESP:
430 return 1;
431 default:
432 break;
433 }
434 } else if ((mad_hdr->mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
435 (mad_hdr->mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
436 return 1;
437
438 return 0;
439 }
440
snoop_gsi_handler(struct ib_mad_agent * mad_agent,struct ib_mad_send_buf * send_buf,struct ib_mad_send_wc * mad_send_wc)441 static void snoop_gsi_handler(struct ib_mad_agent *mad_agent,
442 struct ib_mad_send_buf *send_buf,
443 struct ib_mad_send_wc *mad_send_wc)
444 {
445 struct ib_mad_hdr *hdr = send_buf->mad;
446
447 if (!gmp && hdr->mgmt_class != mgmt_class)
448 return;
449 if (attr_id && be16_to_cpu(hdr->attr_id) != attr_id)
450 return;
451
452 printk("Madeye:sent GMP\n");
453 print_mad_hdr(hdr);
454
455 if (is_rmpp_mad(hdr))
456 print_rmpp_hdr(&((struct ib_rmpp_mad *) hdr)->rmpp_hdr);
457 }
458
recv_gsi_handler(struct ib_mad_agent * mad_agent,struct ib_mad_recv_wc * mad_recv_wc)459 static void recv_gsi_handler(struct ib_mad_agent *mad_agent,
460 struct ib_mad_recv_wc *mad_recv_wc)
461 {
462 struct ib_mad_hdr *hdr = &mad_recv_wc->recv_buf.mad->mad_hdr;
463 struct ib_rmpp_mad *mad = NULL;
464 struct ib_sa_mad *sa_mad;
465 struct ib_vendor_mad *vendor_mad;
466 u8 *mad_data;
467 int i, j;
468
469 if (!gmp && hdr->mgmt_class != mgmt_class)
470 return;
471 if (attr_id && be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) != attr_id)
472 return;
473
474 printk("Madeye:recv GMP\n");
475 print_mad_hdr(hdr);
476
477 if (is_rmpp_mad(hdr)) {
478 mad = (struct ib_rmpp_mad *) hdr;
479 print_rmpp_hdr(&mad->rmpp_hdr);
480 }
481
482 if (data) {
483 if (hdr->mgmt_class == IB_MGMT_CLASS_SUBN_ADM) {
484 j = IB_MGMT_SA_DATA;
485 /* Display SA header */
486 if (is_rmpp_mad(hdr) &&
487 mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA)
488 return;
489 sa_mad = (struct ib_sa_mad *)
490 &mad_recv_wc->recv_buf.mad;
491 mad_data = sa_mad->data;
492 } else {
493 if (is_rmpp_mad(hdr)) {
494 j = IB_MGMT_VENDOR_DATA;
495 /* Display OUI */
496 vendor_mad = (struct ib_vendor_mad *)
497 &mad_recv_wc->recv_buf.mad;
498 printk("Vendor OUI......%01x %01x %01x\n",
499 vendor_mad->oui[0],
500 vendor_mad->oui[1],
501 vendor_mad->oui[2]);
502 mad_data = vendor_mad->data;
503 } else {
504 j = IB_MGMT_MAD_DATA;
505 mad_data = mad_recv_wc->recv_buf.mad->data;
506 }
507 }
508 for (i = 0; i < j; i++) {
509 if (i % 16 == 0)
510 printk("\nData...........");
511 printk("%01x ", mad_data[i]);
512 }
513 printk("\n");
514 }
515 }
516
madeye_add_one(struct ib_device * device)517 static void madeye_add_one(struct ib_device *device)
518 {
519 struct madeye_port *port;
520 int reg_flags;
521 u8 i, s, e;
522
523 if (device->node_type == RDMA_NODE_IB_SWITCH) {
524 s = 0;
525 e = 0;
526 } else {
527 s = 1;
528 e = device->phys_port_cnt;
529 }
530
531 port = kmalloc(sizeof *port * (e - s + 1), GFP_KERNEL);
532 if (!port)
533 goto out;
534
535 reg_flags = IB_MAD_SNOOP_SEND_COMPLETIONS | IB_MAD_SNOOP_RECVS;
536 for (i = 0; i <= e - s; i++) {
537 port[i].smi_agent = ib_register_mad_snoop(device, i + s,
538 IB_QPT_SMI,
539 reg_flags,
540 snoop_smi_handler,
541 recv_smi_handler,
542 &port[i]);
543 port[i].gsi_agent = ib_register_mad_snoop(device, i + s,
544 IB_QPT_GSI,
545 reg_flags,
546 snoop_gsi_handler,
547 recv_gsi_handler,
548 &port[i]);
549 }
550
551 out:
552 ib_set_client_data(device, &madeye_client, port);
553 }
554
madeye_remove_one(struct ib_device * device)555 static void madeye_remove_one(struct ib_device *device)
556 {
557 struct madeye_port *port;
558 int i, s, e;
559
560 port = (struct madeye_port *)
561 ib_get_client_data(device, &madeye_client);
562 if (!port)
563 return;
564
565 if (device->node_type == RDMA_NODE_IB_SWITCH) {
566 s = 0;
567 e = 0;
568 } else {
569 s = 1;
570 e = device->phys_port_cnt;
571 }
572
573 for (i = 0; i <= e - s; i++) {
574 if (!IS_ERR(port[i].smi_agent))
575 ib_unregister_mad_agent(port[i].smi_agent);
576 if (!IS_ERR(port[i].gsi_agent))
577 ib_unregister_mad_agent(port[i].gsi_agent);
578 }
579 kfree(port);
580 }
581
ib_madeye_init(void)582 static int __init ib_madeye_init(void)
583 {
584 return ib_register_client(&madeye_client);
585 }
586
ib_madeye_cleanup(void)587 static void __exit ib_madeye_cleanup(void)
588 {
589 ib_unregister_client(&madeye_client);
590 }
591
592 module_init(ib_madeye_init);
593 module_exit(ib_madeye_cleanup);
594