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