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