1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004, 2005 Intel Corporation.  All rights reserved.
3219820Sjeff * Copyright (c) 2005, 2006 Voltaire Inc.  All rights reserved.
4219820Sjeff *
5219820Sjeff * This software is available to you under a choice of one of two
6219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
7219820Sjeff * General Public License (GPL) Version 2, available from the file
8219820Sjeff * COPYING in the main directorY of this source tree, or the
9219820Sjeff * OpenIB.org BSD license below:
10219820Sjeff *
11219820Sjeff *     Redistribution and use in source and binary forms, with or
12219820Sjeff *     without modification, are permitted provided that the following
13219820Sjeff *     conditions are met:
14219820Sjeff *
15219820Sjeff *      - Redistributions of source code must retain the above
16219820Sjeff *        copyright notice, this list of conditions and the following
17219820Sjeff *        disclaimer.
18219820Sjeff *
19219820Sjeff *      - Redistributions in binary form must reproduce the above
20219820Sjeff *        copyright notice, this list of conditions and the following
21219820Sjeff *        disclaimer in the documentation and/or other materials
22219820Sjeff *        provided with the distribution.
23219820Sjeff *
24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31219820Sjeff * SOFTWARE.
32219820Sjeff *
33219820Sjeff * $Id$
34219820Sjeff */
35300676Shselasky
36300676Shselasky#define	LINUXKPI_PARAM_PREFIX ib_madeye_
37300676Shselasky
38219820Sjeff#include <linux/module.h>
39219820Sjeff#include <linux/device.h>
40219820Sjeff#include <linux/err.h>
41219820Sjeff
42219820Sjeff#include <rdma/ib_mad.h>
43219820Sjeff#include <rdma/ib_smi.h>
44219820Sjeff#include <rdma/ib_sa.h>
45219820Sjeff
46219820SjeffMODULE_AUTHOR("Sean Hefty");
47219820SjeffMODULE_DESCRIPTION("InfiniBand MAD viewer");
48219820SjeffMODULE_LICENSE("Dual BSD/GPL");
49219820Sjeff
50219820Sjeffstatic void madeye_remove_one(struct ib_device *device);
51219820Sjeffstatic void madeye_add_one(struct ib_device *device);
52219820Sjeff
53219820Sjeffstatic struct ib_client madeye_client = {
54219820Sjeff	.name   = "madeye",
55219820Sjeff	.add    = madeye_add_one,
56219820Sjeff	.remove = madeye_remove_one
57219820Sjeff};
58219820Sjeff
59219820Sjeffstruct madeye_port {
60219820Sjeff	struct ib_mad_agent *smi_agent;
61219820Sjeff	struct ib_mad_agent *gsi_agent;
62219820Sjeff};
63219820Sjeff
64219820Sjeffstatic int smp = 1;
65219820Sjeffstatic int gmp = 1;
66219820Sjeffstatic int mgmt_class = 0;
67219820Sjeffstatic int attr_id = 0;
68219820Sjeffstatic int data = 0;
69219820Sjeff
70219820Sjeffmodule_param(smp, int, 0444);
71219820Sjeffmodule_param(gmp, int, 0444);
72219820Sjeffmodule_param(mgmt_class, int, 0444);
73219820Sjeffmodule_param(attr_id, int, 0444);
74219820Sjeffmodule_param(data, int, 0444);
75219820Sjeff
76219820SjeffMODULE_PARM_DESC(smp, "Display all SMPs (default=1)");
77219820SjeffMODULE_PARM_DESC(gmp, "Display all GMPs (default=1)");
78219820SjeffMODULE_PARM_DESC(mgmt_class, "Display all MADs of specified class (default=0)");
79219820SjeffMODULE_PARM_DESC(attr_id, "Display add MADs of specified attribute ID (default=0)");
80219820SjeffMODULE_PARM_DESC(data, "Display data area of MADs (default=0)");
81219820Sjeff
82219820Sjeffstatic char * get_class_name(u8 mgmt_class)
83219820Sjeff{
84219820Sjeff	switch(mgmt_class) {
85219820Sjeff	case IB_MGMT_CLASS_SUBN_LID_ROUTED:
86219820Sjeff		return "LID routed SMP";
87219820Sjeff	case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE:
88219820Sjeff		return "Directed route SMP";
89219820Sjeff	case IB_MGMT_CLASS_SUBN_ADM:
90219820Sjeff		return "Subnet admin.";
91219820Sjeff	case IB_MGMT_CLASS_PERF_MGMT:
92219820Sjeff		return "Perf. mgmt.";
93219820Sjeff	case IB_MGMT_CLASS_BM:
94219820Sjeff		return "Baseboard mgmt.";
95219820Sjeff	case IB_MGMT_CLASS_DEVICE_MGMT:
96219820Sjeff		return "Device mgmt.";
97219820Sjeff	case IB_MGMT_CLASS_CM:
98219820Sjeff		return "Comm. mgmt.";
99219820Sjeff	case IB_MGMT_CLASS_SNMP:
100219820Sjeff		return "SNMP";
101219820Sjeff	default:
102219820Sjeff		return "Unknown vendor/application";
103219820Sjeff	}
104219820Sjeff}
105219820Sjeff
106219820Sjeffstatic char * get_method_name(u8 mgmt_class, u8 method)
107219820Sjeff{
108219820Sjeff	switch(method) {
109219820Sjeff	case IB_MGMT_METHOD_GET:
110219820Sjeff		return "Get";
111219820Sjeff	case IB_MGMT_METHOD_SET:
112219820Sjeff		return "Set";
113219820Sjeff	case IB_MGMT_METHOD_GET_RESP:
114219820Sjeff		return "Get response";
115219820Sjeff	case IB_MGMT_METHOD_SEND:
116219820Sjeff		return "Send";
117219820Sjeff	case IB_MGMT_METHOD_SEND | IB_MGMT_METHOD_RESP:
118219820Sjeff		return "Send response";
119219820Sjeff	case IB_MGMT_METHOD_TRAP:
120219820Sjeff		return "Trap";
121219820Sjeff	case IB_MGMT_METHOD_REPORT:
122219820Sjeff		return "Report";
123219820Sjeff	case IB_MGMT_METHOD_REPORT_RESP:
124219820Sjeff		return "Report response";
125219820Sjeff	case IB_MGMT_METHOD_TRAP_REPRESS:
126219820Sjeff		return "Trap repress";
127219820Sjeff	default:
128219820Sjeff		break;
129219820Sjeff	}
130219820Sjeff
131219820Sjeff	switch (mgmt_class) {
132219820Sjeff	case IB_MGMT_CLASS_SUBN_ADM:
133219820Sjeff		switch (method) {
134219820Sjeff		case IB_SA_METHOD_GET_TABLE:
135219820Sjeff			return "Get table";
136219820Sjeff		case IB_SA_METHOD_GET_TABLE_RESP:
137219820Sjeff			return "Get table response";
138219820Sjeff		case IB_SA_METHOD_DELETE:
139219820Sjeff			return "Delete";
140219820Sjeff		case IB_SA_METHOD_DELETE_RESP:
141219820Sjeff			return "Delete response";
142219820Sjeff		case IB_SA_METHOD_GET_MULTI:
143219820Sjeff			return "Get Multi";
144219820Sjeff		case IB_SA_METHOD_GET_MULTI_RESP:
145219820Sjeff			return "Get Multi response";
146219820Sjeff		case IB_SA_METHOD_GET_TRACE_TBL:
147219820Sjeff			return "Get Trace Table response";
148219820Sjeff		default:
149219820Sjeff			break;
150219820Sjeff		}
151219820Sjeff	default:
152219820Sjeff		break;
153219820Sjeff	}
154219820Sjeff
155219820Sjeff	return "Unknown";
156219820Sjeff}
157219820Sjeff
158219820Sjeffstatic void print_status_details(u16 status)
159219820Sjeff{
160219820Sjeff	if (status & 0x0001)
161219820Sjeff		printk("               busy\n");
162219820Sjeff	if (status & 0x0002)
163219820Sjeff		printk("               redirection required\n");
164219820Sjeff	switch((status & 0x001C) >> 2) {
165219820Sjeff	case 1:
166219820Sjeff		printk("               bad version\n");
167219820Sjeff		break;
168219820Sjeff	case 2:
169219820Sjeff		printk("               method not supported\n");
170219820Sjeff		break;
171219820Sjeff	case 3:
172219820Sjeff		printk("               method/attribute combo not supported\n");
173219820Sjeff		break;
174219820Sjeff	case 7:
175219820Sjeff		printk("               invalid attribute/modifier value\n");
176219820Sjeff		break;
177219820Sjeff	}
178219820Sjeff}
179219820Sjeff
180219820Sjeffstatic char * get_sa_attr(__be16 attr)
181219820Sjeff{
182219820Sjeff	switch(attr) {
183219820Sjeff	case IB_SA_ATTR_CLASS_PORTINFO:
184219820Sjeff		return "Class Port Info";
185219820Sjeff	case IB_SA_ATTR_NOTICE:
186219820Sjeff		return "Notice";
187219820Sjeff	case IB_SA_ATTR_INFORM_INFO:
188219820Sjeff		return "Inform Info";
189219820Sjeff	case IB_SA_ATTR_NODE_REC:
190219820Sjeff		return "Node Record";
191219820Sjeff	case IB_SA_ATTR_PORT_INFO_REC:
192219820Sjeff		return "PortInfo Record";
193219820Sjeff	case IB_SA_ATTR_SL2VL_REC:
194219820Sjeff		return "SL to VL Record";
195219820Sjeff	case IB_SA_ATTR_SWITCH_REC:
196219820Sjeff		return "Switch Record";
197219820Sjeff	case IB_SA_ATTR_LINEAR_FDB_REC:
198219820Sjeff		return "Linear FDB Record";
199219820Sjeff	case IB_SA_ATTR_RANDOM_FDB_REC:
200219820Sjeff		return "Random FDB Record";
201219820Sjeff	case IB_SA_ATTR_MCAST_FDB_REC:
202219820Sjeff		return "Multicast FDB Record";
203219820Sjeff	case IB_SA_ATTR_SM_INFO_REC:
204219820Sjeff		return "SM Info Record";
205219820Sjeff	case IB_SA_ATTR_LINK_REC:
206219820Sjeff		return "Link Record";
207219820Sjeff	case IB_SA_ATTR_GUID_INFO_REC:
208219820Sjeff		return "Guid Info Record";
209219820Sjeff	case IB_SA_ATTR_SERVICE_REC:
210219820Sjeff		return "Service Record";
211219820Sjeff	case IB_SA_ATTR_PARTITION_REC:
212219820Sjeff		return "Partition Record";
213219820Sjeff	case IB_SA_ATTR_PATH_REC:
214219820Sjeff		return "Path Record";
215219820Sjeff	case IB_SA_ATTR_VL_ARB_REC:
216219820Sjeff		return "VL Arb Record";
217219820Sjeff	case IB_SA_ATTR_MC_MEMBER_REC:
218219820Sjeff		return "MC Member Record";
219219820Sjeff	case IB_SA_ATTR_TRACE_REC:
220219820Sjeff		return "Trace Record";
221219820Sjeff	case IB_SA_ATTR_MULTI_PATH_REC:
222219820Sjeff		return "Multi Path Record";
223219820Sjeff	case IB_SA_ATTR_SERVICE_ASSOC_REC:
224219820Sjeff		return "Service Assoc Record";
225219820Sjeff	case IB_SA_ATTR_INFORM_INFO_REC:
226219820Sjeff		return "Inform Info Record";
227219820Sjeff	default:
228219820Sjeff		return "";
229219820Sjeff	}
230219820Sjeff}
231219820Sjeff
232219820Sjeffstatic void print_mad_hdr(struct ib_mad_hdr *mad_hdr)
233219820Sjeff{
234219820Sjeff	printk("MAD version....0x%01x\n", mad_hdr->base_version);
235219820Sjeff	printk("Class..........0x%01x (%s)\n", mad_hdr->mgmt_class,
236219820Sjeff	       get_class_name(mad_hdr->mgmt_class));
237219820Sjeff	printk("Class version..0x%01x\n", mad_hdr->class_version);
238219820Sjeff	printk("Method.........0x%01x (%s)\n", mad_hdr->method,
239219820Sjeff	       get_method_name(mad_hdr->mgmt_class, mad_hdr->method));
240219820Sjeff	printk("Status.........0x%02x\n", be16_to_cpu(mad_hdr->status));
241219820Sjeff	if (mad_hdr->status)
242219820Sjeff		print_status_details(be16_to_cpu(mad_hdr->status));
243219820Sjeff	printk("Class specific.0x%02x\n", be16_to_cpu(mad_hdr->class_specific));
244219820Sjeff	printk("Trans ID.......0x%llx\n",
245219820Sjeff		(unsigned long long)be64_to_cpu(mad_hdr->tid));
246219820Sjeff	if (mad_hdr->mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
247219820Sjeff		printk("Attr ID........0x%02x (%s)\n",
248219820Sjeff		       be16_to_cpu(mad_hdr->attr_id),
249219820Sjeff		       get_sa_attr(be16_to_cpu(mad_hdr->attr_id)));
250219820Sjeff	else
251219820Sjeff		printk("Attr ID........0x%02x\n",
252219820Sjeff		       be16_to_cpu(mad_hdr->attr_id));
253219820Sjeff	printk("Attr modifier..0x%04x\n", be32_to_cpu(mad_hdr->attr_mod));
254219820Sjeff}
255219820Sjeff
256219820Sjeffstatic char * get_rmpp_type(u8 rmpp_type)
257219820Sjeff{
258219820Sjeff	switch (rmpp_type) {
259219820Sjeff	case IB_MGMT_RMPP_TYPE_DATA:
260219820Sjeff		return "Data";
261219820Sjeff	case IB_MGMT_RMPP_TYPE_ACK:
262219820Sjeff		return "Ack";
263219820Sjeff	case IB_MGMT_RMPP_TYPE_STOP:
264219820Sjeff		return "Stop";
265219820Sjeff	case IB_MGMT_RMPP_TYPE_ABORT:
266219820Sjeff		return "Abort";
267219820Sjeff	default:
268219820Sjeff		return "Unknown";
269219820Sjeff	}
270219820Sjeff}
271219820Sjeff
272219820Sjeffstatic char * get_rmpp_flags(u8 rmpp_flags)
273219820Sjeff{
274219820Sjeff	if (rmpp_flags & IB_MGMT_RMPP_FLAG_ACTIVE)
275219820Sjeff		if (rmpp_flags & IB_MGMT_RMPP_FLAG_FIRST)
276219820Sjeff			if (rmpp_flags & IB_MGMT_RMPP_FLAG_LAST)
277219820Sjeff				return "Active - First & Last";
278219820Sjeff			else
279219820Sjeff				return "Active - First";
280219820Sjeff		else
281219820Sjeff			if (rmpp_flags & IB_MGMT_RMPP_FLAG_LAST)
282219820Sjeff				return "Active - Last";
283219820Sjeff			else
284219820Sjeff				return "Active";
285219820Sjeff	else
286219820Sjeff		return "Inactive";
287219820Sjeff}
288219820Sjeff
289219820Sjeffstatic void print_rmpp_hdr(struct ib_rmpp_hdr *rmpp_hdr)
290219820Sjeff{
291219820Sjeff	printk("RMPP version...0x%01x\n", rmpp_hdr->rmpp_version);
292219820Sjeff	printk("RMPP type......0x%01x (%s)\n", rmpp_hdr->rmpp_type,
293219820Sjeff	       get_rmpp_type(rmpp_hdr->rmpp_type));
294219820Sjeff	printk("RMPP RRespTime.0x%01x\n", ib_get_rmpp_resptime(rmpp_hdr));
295219820Sjeff	printk("RMPP flags.....0x%01x (%s)\n", ib_get_rmpp_flags(rmpp_hdr),
296219820Sjeff	       get_rmpp_flags(ib_get_rmpp_flags(rmpp_hdr)));
297219820Sjeff	printk("RMPP status....0x%01x\n", rmpp_hdr->rmpp_status);
298219820Sjeff	printk("Seg number.....0x%04x\n", be32_to_cpu(rmpp_hdr->seg_num));
299219820Sjeff	switch (rmpp_hdr->rmpp_type) {
300219820Sjeff	case IB_MGMT_RMPP_TYPE_DATA:
301219820Sjeff		printk("Payload len....0x%04x\n",
302219820Sjeff		       be32_to_cpu(rmpp_hdr->paylen_newwin));
303219820Sjeff		break;
304219820Sjeff	case IB_MGMT_RMPP_TYPE_ACK:
305219820Sjeff		printk("New window.....0x%04x\n",
306219820Sjeff		       be32_to_cpu(rmpp_hdr->paylen_newwin));
307219820Sjeff		break;
308219820Sjeff	default:
309219820Sjeff		printk("Data 2.........0x%04x\n",
310219820Sjeff		       be32_to_cpu(rmpp_hdr->paylen_newwin));
311219820Sjeff		break;
312219820Sjeff	}
313219820Sjeff}
314219820Sjeff
315219820Sjeffstatic char * get_smp_attr(__be16 attr)
316219820Sjeff{
317219820Sjeff	switch (attr) {
318219820Sjeff	case IB_SMP_ATTR_NOTICE:
319219820Sjeff		return "notice";
320219820Sjeff	case IB_SMP_ATTR_NODE_DESC:
321219820Sjeff		return "node description";
322219820Sjeff	case IB_SMP_ATTR_NODE_INFO:
323219820Sjeff		return "node info";
324219820Sjeff	case IB_SMP_ATTR_SWITCH_INFO:
325219820Sjeff		return "switch info";
326219820Sjeff	case IB_SMP_ATTR_GUID_INFO:
327219820Sjeff		return "GUID info";
328219820Sjeff	case IB_SMP_ATTR_PORT_INFO:
329219820Sjeff		return "port info";
330219820Sjeff	case IB_SMP_ATTR_PKEY_TABLE:
331219820Sjeff		return "pkey table";
332219820Sjeff	case IB_SMP_ATTR_SL_TO_VL_TABLE:
333219820Sjeff		return "SL to VL table";
334219820Sjeff	case IB_SMP_ATTR_VL_ARB_TABLE:
335219820Sjeff		return "VL arbitration table";
336219820Sjeff	case IB_SMP_ATTR_LINEAR_FORWARD_TABLE:
337219820Sjeff		return "linear forwarding table";
338219820Sjeff	case IB_SMP_ATTR_RANDOM_FORWARD_TABLE:
339219820Sjeff		return "random forward table";
340219820Sjeff	case IB_SMP_ATTR_MCAST_FORWARD_TABLE:
341219820Sjeff		return "multicast forward table";
342219820Sjeff	case IB_SMP_ATTR_SM_INFO:
343219820Sjeff		return "SM info";
344219820Sjeff	case IB_SMP_ATTR_VENDOR_DIAG:
345219820Sjeff		return "vendor diags";
346219820Sjeff	case IB_SMP_ATTR_LED_INFO:
347219820Sjeff		return "LED info";
348219820Sjeff	default:
349219820Sjeff		return "";
350219820Sjeff	}
351219820Sjeff}
352219820Sjeff
353219820Sjeffstatic void print_smp(struct ib_smp *smp)
354219820Sjeff{
355219820Sjeff	int i;
356219820Sjeff
357219820Sjeff	printk("MAD version....0x%01x\n", smp->base_version);
358219820Sjeff	printk("Class..........0x%01x (%s)\n", smp->mgmt_class,
359219820Sjeff	       get_class_name(smp->mgmt_class));
360219820Sjeff	printk("Class version..0x%01x\n", smp->class_version);
361219820Sjeff	printk("Method.........0x%01x (%s)\n", smp->method,
362219820Sjeff	       get_method_name(smp->mgmt_class, smp->method));
363219820Sjeff	printk("Status.........0x%02x\n", be16_to_cpu(smp->status));
364219820Sjeff	if (smp->status)
365219820Sjeff		print_status_details(be16_to_cpu(smp->status));
366219820Sjeff	printk("Hop pointer....0x%01x\n", smp->hop_ptr);
367219820Sjeff	printk("Hop counter....0x%01x\n", smp->hop_cnt);
368219820Sjeff	printk("Trans ID.......0x%llx\n",
369219820Sjeff		(unsigned long long)be64_to_cpu(smp->tid));
370219820Sjeff	printk("Attr ID........0x%02x (%s)\n", be16_to_cpu(smp->attr_id),
371219820Sjeff		get_smp_attr(smp->attr_id));
372219820Sjeff	printk("Attr modifier..0x%04x\n", be32_to_cpu(smp->attr_mod));
373219820Sjeff
374219820Sjeff	printk("Mkey...........0x%llx\n",
375219820Sjeff		(unsigned long long)be64_to_cpu(smp->mkey));
376219820Sjeff	printk("DR SLID........0x%02x\n", be16_to_cpu(smp->dr_slid));
377219820Sjeff	printk("DR DLID........0x%02x", be16_to_cpu(smp->dr_dlid));
378219820Sjeff
379219820Sjeff	if (data) {
380219820Sjeff		for (i = 0; i < IB_SMP_DATA_SIZE; i++) {
381219820Sjeff			if (i % 16 == 0)
382219820Sjeff				printk("\nSMP Data.......");
383219820Sjeff			printk("%01x ", smp->data[i]);
384219820Sjeff		}
385219820Sjeff		for (i = 0; i < IB_SMP_MAX_PATH_HOPS; i++) {
386219820Sjeff			if (i % 16 == 0)
387219820Sjeff				printk("\nInitial path...");
388219820Sjeff			printk("%01x ", smp->initial_path[i]);
389219820Sjeff		}
390219820Sjeff		for (i = 0; i < IB_SMP_MAX_PATH_HOPS; i++) {
391219820Sjeff			if (i % 16 == 0)
392219820Sjeff				printk("\nReturn path....");
393219820Sjeff			printk("%01x ", smp->return_path[i]);
394219820Sjeff		}
395219820Sjeff	}
396219820Sjeff	printk("\n");
397219820Sjeff}
398219820Sjeff
399219820Sjeffstatic void snoop_smi_handler(struct ib_mad_agent *mad_agent,
400219820Sjeff			      struct ib_mad_send_buf *send_buf,
401219820Sjeff			      struct ib_mad_send_wc *mad_send_wc)
402219820Sjeff{
403219820Sjeff	struct ib_mad_hdr *hdr = send_buf->mad;
404219820Sjeff
405219820Sjeff	if (!smp && hdr->mgmt_class != mgmt_class)
406219820Sjeff		return;
407219820Sjeff	if (attr_id && be16_to_cpu(hdr->attr_id) != attr_id)
408219820Sjeff		return;
409219820Sjeff
410219820Sjeff	printk("Madeye:sent SMP\n");
411219820Sjeff	print_smp(send_buf->mad);
412219820Sjeff}
413219820Sjeff
414219820Sjeffstatic void recv_smi_handler(struct ib_mad_agent *mad_agent,
415219820Sjeff			     struct ib_mad_recv_wc *mad_recv_wc)
416219820Sjeff{
417219820Sjeff	if (!smp && mad_recv_wc->recv_buf.mad->mad_hdr.mgmt_class != mgmt_class)
418219820Sjeff		return;
419219820Sjeff	if (attr_id && be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) != attr_id)
420219820Sjeff		return;
421219820Sjeff
422219820Sjeff	printk("Madeye:recv SMP\n");
423219820Sjeff	print_smp((struct ib_smp *)&mad_recv_wc->recv_buf.mad->mad_hdr);
424219820Sjeff}
425219820Sjeff
426219820Sjeffstatic int is_rmpp_mad(struct ib_mad_hdr *mad_hdr)
427219820Sjeff{
428219820Sjeff	if (mad_hdr->mgmt_class == IB_MGMT_CLASS_SUBN_ADM) {
429219820Sjeff		switch (mad_hdr->method) {
430219820Sjeff		case IB_SA_METHOD_GET_TABLE:
431219820Sjeff		case IB_SA_METHOD_GET_TABLE_RESP:
432219820Sjeff		case IB_SA_METHOD_GET_MULTI_RESP:
433219820Sjeff			return 1;
434219820Sjeff		default:
435219820Sjeff			break;
436219820Sjeff		}
437219820Sjeff	} else if ((mad_hdr->mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
438219820Sjeff		   (mad_hdr->mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
439219820Sjeff		return 1;
440219820Sjeff
441219820Sjeff	return 0;
442219820Sjeff}
443219820Sjeff
444219820Sjeffstatic void snoop_gsi_handler(struct ib_mad_agent *mad_agent,
445219820Sjeff			      struct ib_mad_send_buf *send_buf,
446219820Sjeff			      struct ib_mad_send_wc *mad_send_wc)
447219820Sjeff{
448219820Sjeff	struct ib_mad_hdr *hdr = send_buf->mad;
449219820Sjeff
450219820Sjeff	if (!gmp && hdr->mgmt_class != mgmt_class)
451219820Sjeff		return;
452219820Sjeff	if (attr_id && be16_to_cpu(hdr->attr_id) != attr_id)
453219820Sjeff		return;
454219820Sjeff
455219820Sjeff	printk("Madeye:sent GMP\n");
456219820Sjeff	print_mad_hdr(hdr);
457219820Sjeff
458219820Sjeff	if (is_rmpp_mad(hdr))
459219820Sjeff		print_rmpp_hdr(&((struct ib_rmpp_mad *) hdr)->rmpp_hdr);
460219820Sjeff}
461219820Sjeff
462219820Sjeffstatic void recv_gsi_handler(struct ib_mad_agent *mad_agent,
463219820Sjeff			     struct ib_mad_recv_wc *mad_recv_wc)
464219820Sjeff{
465219820Sjeff	struct ib_mad_hdr *hdr = &mad_recv_wc->recv_buf.mad->mad_hdr;
466219820Sjeff	struct ib_rmpp_mad *mad = NULL;
467219820Sjeff	struct ib_sa_mad *sa_mad;
468219820Sjeff	struct ib_vendor_mad *vendor_mad;
469219820Sjeff	u8 *mad_data;
470219820Sjeff	int i, j;
471219820Sjeff
472219820Sjeff	if (!gmp && hdr->mgmt_class != mgmt_class)
473219820Sjeff		return;
474219820Sjeff	if (attr_id && be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) != attr_id)
475219820Sjeff		return;
476219820Sjeff
477219820Sjeff	printk("Madeye:recv GMP\n");
478219820Sjeff	print_mad_hdr(hdr);
479219820Sjeff
480219820Sjeff	if (is_rmpp_mad(hdr)) {
481219820Sjeff		mad = (struct ib_rmpp_mad *) hdr;
482219820Sjeff		print_rmpp_hdr(&mad->rmpp_hdr);
483219820Sjeff	}
484219820Sjeff
485219820Sjeff	if (data) {
486219820Sjeff		if (hdr->mgmt_class == IB_MGMT_CLASS_SUBN_ADM) {
487219820Sjeff			j = IB_MGMT_SA_DATA;
488219820Sjeff			/* Display SA header */
489219820Sjeff			if (is_rmpp_mad(hdr) &&
490219820Sjeff			    mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA)
491219820Sjeff				return;
492219820Sjeff			sa_mad = (struct ib_sa_mad *)
493219820Sjeff				 &mad_recv_wc->recv_buf.mad;
494219820Sjeff			mad_data = sa_mad->data;
495219820Sjeff		} else {
496219820Sjeff			if (is_rmpp_mad(hdr)) {
497219820Sjeff				j = IB_MGMT_VENDOR_DATA;
498219820Sjeff				/* Display OUI */
499219820Sjeff				vendor_mad = (struct ib_vendor_mad *)
500219820Sjeff					     &mad_recv_wc->recv_buf.mad;
501219820Sjeff				printk("Vendor OUI......%01x %01x %01x\n",
502219820Sjeff					vendor_mad->oui[0],
503219820Sjeff					vendor_mad->oui[1],
504219820Sjeff					vendor_mad->oui[2]);
505219820Sjeff				mad_data = vendor_mad->data;
506219820Sjeff			} else {
507219820Sjeff				j = IB_MGMT_MAD_DATA;
508219820Sjeff				mad_data = mad_recv_wc->recv_buf.mad->data;
509219820Sjeff			}
510219820Sjeff		}
511219820Sjeff		for (i = 0; i < j; i++) {
512219820Sjeff			if (i % 16 == 0)
513219820Sjeff				printk("\nData...........");
514219820Sjeff			printk("%01x ", mad_data[i]);
515219820Sjeff		}
516219820Sjeff		printk("\n");
517219820Sjeff	}
518219820Sjeff}
519219820Sjeff
520219820Sjeffstatic void madeye_add_one(struct ib_device *device)
521219820Sjeff{
522219820Sjeff	struct madeye_port *port;
523219820Sjeff	int reg_flags;
524219820Sjeff	u8 i, s, e;
525219820Sjeff
526219820Sjeff	if (device->node_type == RDMA_NODE_IB_SWITCH) {
527219820Sjeff		s = 0;
528219820Sjeff		e = 0;
529219820Sjeff	} else {
530219820Sjeff		s = 1;
531219820Sjeff		e = device->phys_port_cnt;
532219820Sjeff	}
533219820Sjeff
534219820Sjeff	port = kmalloc(sizeof *port * (e - s + 1), GFP_KERNEL);
535219820Sjeff	if (!port)
536219820Sjeff		goto out;
537219820Sjeff
538219820Sjeff	reg_flags = IB_MAD_SNOOP_SEND_COMPLETIONS | IB_MAD_SNOOP_RECVS;
539219820Sjeff	for (i = 0; i <= e - s; i++) {
540219820Sjeff		port[i].smi_agent = ib_register_mad_snoop(device, i + s,
541219820Sjeff							  IB_QPT_SMI,
542219820Sjeff							  reg_flags,
543219820Sjeff							  snoop_smi_handler,
544219820Sjeff							  recv_smi_handler,
545219820Sjeff							  &port[i]);
546219820Sjeff		port[i].gsi_agent = ib_register_mad_snoop(device, i + s,
547219820Sjeff							  IB_QPT_GSI,
548219820Sjeff							  reg_flags,
549219820Sjeff							  snoop_gsi_handler,
550219820Sjeff							  recv_gsi_handler,
551219820Sjeff							  &port[i]);
552219820Sjeff	}
553219820Sjeff
554219820Sjeffout:
555219820Sjeff	ib_set_client_data(device, &madeye_client, port);
556219820Sjeff}
557219820Sjeff
558219820Sjeffstatic void madeye_remove_one(struct ib_device *device)
559219820Sjeff{
560219820Sjeff	struct madeye_port *port;
561219820Sjeff	int i, s, e;
562219820Sjeff
563219820Sjeff	port = (struct madeye_port *)
564219820Sjeff		ib_get_client_data(device, &madeye_client);
565219820Sjeff	if (!port)
566219820Sjeff		return;
567219820Sjeff
568219820Sjeff	if (device->node_type == RDMA_NODE_IB_SWITCH) {
569219820Sjeff		s = 0;
570219820Sjeff		e = 0;
571219820Sjeff	} else {
572219820Sjeff		s = 1;
573219820Sjeff		e = device->phys_port_cnt;
574219820Sjeff	}
575219820Sjeff
576219820Sjeff	for (i = 0; i <= e - s; i++) {
577219820Sjeff		if (!IS_ERR(port[i].smi_agent))
578219820Sjeff			ib_unregister_mad_agent(port[i].smi_agent);
579219820Sjeff		if (!IS_ERR(port[i].gsi_agent))
580219820Sjeff			ib_unregister_mad_agent(port[i].gsi_agent);
581219820Sjeff	}
582219820Sjeff	kfree(port);
583219820Sjeff}
584219820Sjeff
585219820Sjeffstatic int __init ib_madeye_init(void)
586219820Sjeff{
587219820Sjeff	return ib_register_client(&madeye_client);
588219820Sjeff}
589219820Sjeff
590219820Sjeffstatic void __exit ib_madeye_cleanup(void)
591219820Sjeff{
592219820Sjeff	ib_unregister_client(&madeye_client);
593219820Sjeff}
594219820Sjeff
595219820Sjeffmodule_init(ib_madeye_init);
596219820Sjeffmodule_exit(ib_madeye_cleanup);
597