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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
582 static int __init ib_madeye_init(void)
583 {
584 	return ib_register_client(&madeye_client);
585 }
586 
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