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 46 MODULE_AUTHOR("Sean Hefty"); 47 MODULE_DESCRIPTION("InfiniBand MAD viewer"); 48 MODULE_LICENSE("Dual BSD/GPL"); 49 50 static void madeye_remove_one(struct ib_device *device); 51 static void madeye_add_one(struct ib_device *device); 52 53 static struct ib_client madeye_client = { 54 .name = "madeye", 55 .add = madeye_add_one, 56 .remove = madeye_remove_one 57 }; 58 59 struct madeye_port { 60 struct ib_mad_agent *smi_agent; 61 struct ib_mad_agent *gsi_agent; 62 }; 63 64 static int smp = 1; 65 static int gmp = 1; 66 static int mgmt_class = 0; 67 static int attr_id = 0; 68 static int data = 0; 69 70 module_param(smp, int, 0444); 71 module_param(gmp, int, 0444); 72 module_param(mgmt_class, int, 0444); 73 module_param(attr_id, int, 0444); 74 module_param(data, int, 0444); 75 76 MODULE_PARM_DESC(smp, "Display all SMPs (default=1)"); 77 MODULE_PARM_DESC(gmp, "Display all GMPs (default=1)"); 78 MODULE_PARM_DESC(mgmt_class, "Display all MADs of specified class (default=0)"); 79 MODULE_PARM_DESC(attr_id, "Display add MADs of specified attribute ID (default=0)"); 80 MODULE_PARM_DESC(data, "Display data area of MADs (default=0)"); 81 82 static 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 106 static 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 158 static 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 180 static 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 232 static 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 256 static 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 272 static 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 289 static 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 315 static 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 353 static 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 399 static 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 414 static 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 426 static 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 444 static 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 462 static 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 520 static 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 554 out: 555 ib_set_client_data(device, &madeye_client, port); 556 } 557 558 static 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 585 static int __init ib_madeye_init(void) 586 { 587 return ib_register_client(&madeye_client); 588 } 589 590 static void __exit ib_madeye_cleanup(void) 591 { 592 ib_unregister_client(&madeye_client); 593 } 594 595 module_init(ib_madeye_init); 596 module_exit(ib_madeye_cleanup); 597