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