1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at 9 * http://www.opensource.org/licenses/cddl1.txt. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2004-2011 Emulex. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #define DUMP_SUPPORT 28 29 #include <emlxs_mdb.h> 30 #include <emlxs_msg.h> 31 #include <emlxs_dump.h> 32 #include <emlxs_device.h> 33 34 /* 35 * MDB module linkage information: 36 */ 37 38 static const mdb_dcmd_t dcmds[] = 39 { 40 { DRIVER_NAME"_msgbuf", "<instance>", "dumps the "DRIVER_NAME 41 " driver internal message buffer", emlxs_msgbuf, emlxs_msgbuf_help}, 42 { DRIVER_NAME"_dump", "<type> <instance>", "dumps the "DRIVER_NAME 43 " driver firmware core", emlxs_dump, emlxs_dump_help}, 44 { NULL } 45 }; 46 47 static const mdb_modinfo_t modinfo = 48 { 49 MDB_API_VERSION, 50 dcmds, 51 NULL 52 }; 53 54 const mdb_modinfo_t * 55 _mdb_init(void) 56 { 57 return (&modinfo); 58 } 59 60 61 /* 62 * emlxs_msgbuf library 63 */ 64 void 65 emlxs_msgbuf_help() 66 { 67 68 mdb_printf("Usage: ::%s_msgbuf <instance(hex)>\n\n", DRIVER_NAME); 69 mdb_printf(" <instance> This is the %s driver instance " \ 70 "number in hex.\n", DRIVER_NAME); 71 mdb_printf(" (e.g. 0, 1,..., e, f, etc.)\n"); 72 73 } /* emlxs_msgbuf_help() */ 74 75 76 /*ARGSUSED*/ 77 int emlxs_msgbuf(uintptr_t base_addr, uint_t flags, int argc, 78 const mdb_arg_t *argv) 79 { 80 uintptr_t addr; 81 emlxs_device_t device; 82 uint32_t brd_no; 83 emlxs_msg_log_t log; 84 uint32_t count; 85 uint32_t first; 86 uint32_t last; 87 uint32_t idx; 88 uint32_t i; 89 char *level; 90 emlxs_msg_t msg; 91 char merge[1024]; 92 93 emlxs_msg_entry_t entry; 94 char buffer[256]; 95 char buffer2[256]; 96 int32_t instance[MAX_FC_BRDS]; 97 char driver[32]; 98 int32_t instance_count; 99 uint32_t ddiinst; 100 101 if (argc != 1) { 102 mdb_printf("Usage: ::%s_msgbuf <instance(hex)>\n", 103 DRIVER_NAME); 104 mdb_printf("mdb: try \"::help %s_msgbuf\" for more information", 105 DRIVER_NAME); 106 107 return (DCMD_ERR); 108 } 109 110 /* Get the device address */ 111 mdb_snprintf(buffer, sizeof (buffer), "%s_device", DRIVER_NAME); 112 if (mdb_readvar(&device, buffer) == -1) { 113 mdb_snprintf(buffer2, sizeof (buffer2), 114 "%s not found.\n", buffer); 115 mdb_warn(buffer2); 116 117 mdb_snprintf(buffer2, sizeof (buffer2), 118 "Is the %s driver loaded ?\n", DRIVER_NAME); 119 mdb_warn(buffer2); 120 return (DCMD_ERR); 121 } 122 123 /* Get the device instance table */ 124 mdb_snprintf(buffer, sizeof (buffer), "%s_instance", DRIVER_NAME); 125 if (mdb_readvar(&instance, buffer) == -1) { 126 mdb_snprintf(buffer2, sizeof (buffer2), "%s not found.\n", 127 buffer); 128 mdb_warn(buffer2); 129 130 mdb_snprintf(buffer2, sizeof (buffer2), 131 "Is the %s driver loaded ?\n", DRIVER_NAME); 132 mdb_warn(buffer2); 133 return (DCMD_ERR); 134 } 135 136 /* Get the device instance count */ 137 mdb_snprintf(buffer, sizeof (buffer), "%s_instance_count", DRIVER_NAME); 138 if (mdb_readvar(&instance_count, buffer) == -1) { 139 mdb_snprintf(buffer2, sizeof (buffer2), "%s not found.\n", 140 buffer); 141 mdb_warn(buffer2); 142 143 mdb_snprintf(buffer2, sizeof (buffer2), 144 "Is the %s driver loaded ?\n", DRIVER_NAME); 145 mdb_warn(buffer2); 146 return (DCMD_ERR); 147 } 148 149 ddiinst = (uint32_t)mdb_strtoull(argv[0].a_un.a_str); 150 151 for (brd_no = 0; brd_no < instance_count; brd_no++) { 152 if (instance[brd_no] == ddiinst) { 153 break; 154 } 155 } 156 157 if (brd_no == instance_count) { 158 mdb_warn("Device instance not found. ddinst=%d\n", ddiinst); 159 return (DCMD_ERR); 160 } 161 162 /* Check if buffer is null */ 163 addr = (uintptr_t)device.log[brd_no]; 164 if (addr == 0) { 165 mdb_warn("Device instance not found. ddinst=%d\n", ddiinst); 166 return (0); 167 } 168 169 if (mdb_vread(&log, sizeof (emlxs_msg_log_t), addr) != 170 sizeof (emlxs_msg_log_t)) { 171 mdb_warn("\nUnable to read %d bytes @ %llx.\n", 172 sizeof (emlxs_msg_log_t), addr); 173 return (0); 174 } 175 176 /* Check if buffer is empty */ 177 if (log.count == 0) { 178 mdb_warn("Log buffer empty.\n"); 179 return (0); 180 } 181 182 /* Get last entry id saved */ 183 last = log.count - 1; 184 185 /* Check if buffer has already been filled once */ 186 if (log.count >= log.size) { 187 first = log.count - log.size; 188 idx = log.next; 189 } else { 190 /* Buffer not yet filled */ 191 first = 0; 192 idx = 0; 193 } 194 195 /* Get the total number of messages available for return */ 196 count = last - first + 1; 197 198 mdb_printf("\n"); 199 200 /* Print the messages */ 201 for (i = 0; i < count; i++) { 202 if (mdb_vread(&entry, sizeof (emlxs_msg_entry_t), 203 (uintptr_t)&log.entry[idx]) != sizeof (emlxs_msg_entry_t)) { 204 mdb_warn("Cannot read log entry. index=%d count=%d\n", 205 idx, count); 206 return (DCMD_ERR); 207 } 208 209 if (mdb_vread(&msg, sizeof (emlxs_msg_t), 210 (uintptr_t)entry.msg) != sizeof (emlxs_msg_t)) { 211 mdb_warn("Cannot read msg. index=%d count=%d\n", 212 idx, count); 213 return (DCMD_ERR); 214 } 215 216 switch (msg.level) { 217 case EMLXS_DEBUG: 218 level = " DEBUG"; 219 break; 220 221 case EMLXS_NOTICE: 222 level = " NOTICE"; 223 break; 224 225 case EMLXS_WARNING: 226 level = "WARNING"; 227 break; 228 229 case EMLXS_ERROR: 230 level = " ERROR"; 231 break; 232 233 case EMLXS_PANIC: 234 level = " PANIC"; 235 break; 236 237 default: 238 level = "UNKNOWN"; 239 break; 240 } 241 242 if (entry.vpi == 0) { 243 mdb_snprintf(driver, sizeof (driver), "%s%d", 244 DRIVER_NAME, entry.instance); 245 } else { 246 mdb_snprintf(driver, sizeof (driver), "%s%d.%d", 247 DRIVER_NAME, entry.instance, entry.vpi); 248 } 249 250 /* Generate the message string */ 251 if (msg.buffer[0] != 0) { 252 if (entry.buffer[0] != 0) { 253 mdb_snprintf(merge, sizeof (merge), 254 "[%Y:%03d:%03d:%03d] " 255 "%6d:[%1X.%04X]%s:%7s:%4d:\n%s\n(%s)\n", 256 entry.id_time.tv_sec, 257 (int)entry.id_time.tv_nsec/1000000, 258 (int)(entry.id_time.tv_nsec/1000)%1000, 259 (int)entry.id_time.tv_nsec%1000, 260 entry.id, entry.fileno, 261 entry.line, driver, level, msg.id, 262 msg.buffer, entry.buffer); 263 264 } else { 265 mdb_snprintf(merge, sizeof (merge), 266 "[%Y:%03d:%03d:%03d] " 267 "%6d:[%1X.%04X]%s:%7s:%4d:\n%s\n", 268 entry.id_time.tv_sec, 269 (int)entry.id_time.tv_nsec/1000000, 270 (int)(entry.id_time.tv_nsec/1000)%1000, 271 (int)entry.id_time.tv_nsec%1000, 272 entry.id, entry.fileno, 273 entry.line, driver, level, msg.id, 274 msg.buffer); 275 } 276 } else { 277 if (entry.buffer[0] != 0) { 278 mdb_snprintf(merge, sizeof (merge), 279 "[%Y:%03d:%03d:%03d] " 280 "%6d:[%1X.%04X]%s:%7s:%4d:\n(%s)\n", 281 entry.id_time.tv_sec, 282 (int)entry.id_time.tv_nsec/1000000, 283 (int)(entry.id_time.tv_nsec/1000)%1000, 284 (int)entry.id_time.tv_nsec%1000, 285 entry.id, entry.fileno, 286 entry.line, driver, level, msg.id, 287 entry.buffer); 288 289 } else { 290 mdb_snprintf(merge, sizeof (merge), 291 "[%Y:%03d:%03d:%03d] " 292 "%6d:[%1X.%04X]%s:%7s:%4d:\n%s\n", 293 entry.id_time.tv_sec, 294 (int)entry.id_time.tv_nsec/1000000, 295 (int)(entry.id_time.tv_nsec/1000)%1000, 296 (int)entry.id_time.tv_nsec%1000, 297 entry.id, entry.fileno, 298 entry.line, driver, level, msg.id, 299 msg.buffer); 300 } 301 } 302 303 mdb_printf("%s", merge); 304 305 /* Increment index */ 306 if (++idx >= log.size) { 307 idx = 0; 308 } 309 } 310 311 mdb_printf("\n"); 312 313 return (0); 314 315 } /* emlxs_msgbuf() */ 316 317 318 void 319 emlxs_dump_help() 320 { 321 mdb_printf("Usage: ::%s_dump all <instance(hex)>\n", DRIVER_NAME); 322 mdb_printf(" ::%s_dump txt <instance(hex)>\n", DRIVER_NAME); 323 mdb_printf(" ::%s_dump dmp <instance(hex)>\n", DRIVER_NAME); 324 mdb_printf(" ::%s_dump cee <instance(hex)>\n", DRIVER_NAME); 325 mdb_printf("\n"); 326 mdb_printf(" txt Display firmware text summary " \ 327 "file.\n"); 328 mdb_printf(" dmp Display firmware dmp binary file.\n"); 329 mdb_printf(" cee Display firmware cee binary file. " \ 330 "(FCOE adapters only)\n"); 331 mdb_printf(" all Display all firmware core files.\n"); 332 mdb_printf(" <instance> This is the %s driver instance " \ 333 "number in hex.\n", DRIVER_NAME); 334 mdb_printf(" (e.g. 0, 1,..., e, f, etc.)\n"); 335 336 } /* emlxs_dump_help() */ 337 338 339 /*ARGSUSED*/ 340 int 341 emlxs_dump(uintptr_t base_addr, uint_t flags, int argc, 342 const mdb_arg_t *argv) 343 { 344 uintptr_t addr; 345 emlxs_device_t device; 346 uint32_t brd_no; 347 uint32_t i; 348 char buffer[256]; 349 char buffer2[256]; 350 int32_t instance[MAX_FC_BRDS]; 351 int32_t instance_count; 352 uint32_t ddiinst; 353 uint8_t *bptr; 354 char *cptr; 355 emlxs_file_t dump_txtfile; 356 emlxs_file_t dump_dmpfile; 357 emlxs_file_t dump_ceefile; 358 uint32_t size; 359 uint32_t file; 360 361 if (argc != 2) { 362 goto usage; 363 } 364 365 if ((strcmp(argv[0].a_un.a_str, "all") == 0) || 366 (strcmp(argv[0].a_un.a_str, "ALL") == 0) || 367 (strcmp(argv[0].a_un.a_str, "All") == 0)) { 368 file = 0; 369 } else if ((strcmp(argv[0].a_un.a_str, "txt") == 0) || 370 (strcmp(argv[0].a_un.a_str, "TXT") == 0) || 371 (strcmp(argv[0].a_un.a_str, "Txt") == 0)) { 372 file = 1; 373 } else if ((strcmp(argv[0].a_un.a_str, "dmp") == 0) || 374 (strcmp(argv[0].a_un.a_str, "DMP") == 0) || 375 (strcmp(argv[0].a_un.a_str, "Dmp") == 0)) { 376 file = 2; 377 } else if ((strcmp(argv[0].a_un.a_str, "cee") == 0) || 378 (strcmp(argv[0].a_un.a_str, "CEE") == 0) || 379 (strcmp(argv[0].a_un.a_str, "Cee") == 0)) { 380 file = 3; 381 } else { 382 goto usage; 383 } 384 385 /* Get the device address */ 386 mdb_snprintf(buffer, sizeof (buffer), "%s_device", DRIVER_NAME); 387 if (mdb_readvar(&device, buffer) == -1) { 388 mdb_snprintf(buffer2, sizeof (buffer2), 389 "%s not found.\n", buffer); 390 mdb_warn(buffer2); 391 392 mdb_snprintf(buffer2, sizeof (buffer2), 393 "Is the %s driver loaded ?\n", DRIVER_NAME); 394 mdb_warn(buffer2); 395 return (DCMD_ERR); 396 } 397 398 /* Get the device instance table */ 399 mdb_snprintf(buffer, sizeof (buffer), "%s_instance", DRIVER_NAME); 400 if (mdb_readvar(&instance, buffer) == -1) { 401 mdb_snprintf(buffer2, sizeof (buffer2), "%s not found.\n", 402 buffer); 403 mdb_warn(buffer2); 404 405 mdb_snprintf(buffer2, sizeof (buffer2), 406 "Is the %s driver loaded ?\n", DRIVER_NAME); 407 mdb_warn(buffer2); 408 return (DCMD_ERR); 409 } 410 411 /* Get the device instance count */ 412 mdb_snprintf(buffer, sizeof (buffer), "%s_instance_count", DRIVER_NAME); 413 if (mdb_readvar(&instance_count, buffer) == -1) { 414 mdb_snprintf(buffer2, sizeof (buffer2), "%s not found.\n", 415 buffer); 416 mdb_warn(buffer2); 417 418 mdb_snprintf(buffer2, sizeof (buffer2), 419 "Is the %s driver loaded ?\n", DRIVER_NAME); 420 mdb_warn(buffer2); 421 return (DCMD_ERR); 422 } 423 424 ddiinst = (uint32_t)mdb_strtoull(argv[1].a_un.a_str); 425 426 for (brd_no = 0; brd_no < instance_count; brd_no++) { 427 if (instance[brd_no] == ddiinst) { 428 break; 429 } 430 } 431 432 if (brd_no == instance_count) { 433 mdb_warn("Device instance not found. ddinst=%d\n", ddiinst); 434 return (DCMD_ERR); 435 } 436 437 if (file == 0 || file == 1) { 438 439 addr = (uintptr_t)device.dump_txtfile[brd_no]; 440 if (addr == 0) { 441 mdb_warn("TXT file: Device instance not found. " \ 442 "ddinst=%d\n", ddiinst); 443 goto dmp_file; 444 } 445 446 if (mdb_vread(&dump_txtfile, sizeof (dump_txtfile), addr) 447 != sizeof (dump_txtfile)) { 448 mdb_warn("TXT file: Unable to read %d bytes @ %llx.\n", 449 sizeof (dump_txtfile), addr); 450 goto dmp_file; 451 } 452 453 size = (uintptr_t)dump_txtfile.ptr - 454 (uintptr_t)dump_txtfile.buffer; 455 456 if (size == 0) { 457 mdb_printf("TXT file: Not available.\n"); 458 goto dmp_file; 459 } 460 bptr = (uint8_t *)mdb_zalloc(size, UM_SLEEP|UM_GC); 461 462 if (bptr == 0) { 463 mdb_warn("TXT file: Unable to allocate file buffer. " \ 464 "ddinst=%d size=%d\n", ddiinst, size); 465 goto dmp_file; 466 } 467 468 if (mdb_vread(bptr, size, (uintptr_t)dump_txtfile.buffer) 469 != size) { 470 mdb_warn("TXT file: Unable to read %d bytes @ %llx.\n", 471 size, dump_txtfile.buffer); 472 goto dmp_file; 473 } 474 475 mdb_printf("<TXT File Start>\n"); 476 mdb_printf("\n"); 477 mdb_printf("%s", bptr); 478 mdb_printf("\n"); 479 mdb_printf("<TXT File End>\n"); 480 } 481 482 dmp_file: 483 484 if (file == 0 || file == 2) { 485 addr = (uintptr_t)device.dump_dmpfile[brd_no]; 486 if (addr == 0) { 487 mdb_warn("DMP file: Device instance not found. " \ 488 "ddinst=%d\n", ddiinst); 489 goto cee_file; 490 } 491 492 if (mdb_vread(&dump_dmpfile, sizeof (dump_dmpfile), addr) 493 != sizeof (dump_dmpfile)) { 494 mdb_warn("DMP file: Unable to read %d bytes @ %llx.\n", 495 sizeof (dump_dmpfile), addr); 496 goto cee_file; 497 } 498 499 size = (uintptr_t)dump_dmpfile.ptr - 500 (uintptr_t)dump_dmpfile.buffer; 501 502 if (size == 0) { 503 mdb_printf("DMP file: Not available.\n"); 504 goto cee_file; 505 } 506 507 bptr = (uint8_t *)mdb_zalloc(size, UM_SLEEP|UM_GC); 508 509 if (bptr == 0) { 510 mdb_warn("DMP file: Unable to allocate file buffer. " \ 511 "ddinst=%d size=%d\n", ddiinst, size); 512 goto cee_file; 513 } 514 515 if (mdb_vread(bptr, size, (uintptr_t)dump_dmpfile.buffer) 516 != size) { 517 mdb_warn("DMP file: Unable to read %d bytes @ %llx.\n", 518 size, dump_dmpfile.buffer); 519 goto cee_file; 520 } 521 522 mdb_printf("<DMP File Start>\n"); 523 mdb_printf("\n"); 524 525 bzero(buffer2, sizeof (buffer2)); 526 cptr = buffer2; 527 for (i = 0; i < size; i++) { 528 if (i && !(i % 16)) { 529 mdb_printf(" %s\n", buffer2); 530 bzero(buffer2, sizeof (buffer2)); 531 cptr = buffer2; 532 } 533 534 if (!(i % 16)) { 535 mdb_printf("%08X: ", i); 536 } 537 538 if (!(i % 4)) { 539 mdb_printf(" "); 540 } 541 542 if ((*bptr >= 32) && (*bptr <= 126)) { 543 *cptr++ = *bptr; 544 } else { 545 *cptr++ = '.'; 546 } 547 548 mdb_printf("%02X ", *bptr++); 549 } 550 551 size = 16 - (i % 16); 552 for (i = 0; size < 16 && i < size; i++) { 553 if (!(i % 4)) { 554 mdb_printf(" "); 555 } 556 557 mdb_printf(" "); 558 } 559 mdb_printf(" %s\n", buffer2); 560 mdb_printf("\n"); 561 mdb_printf("<DMP File End>\n"); 562 } 563 564 cee_file: 565 566 if (file == 0 || file == 3) { 567 568 addr = (uintptr_t)device.dump_ceefile[brd_no]; 569 if (addr == 0) { 570 mdb_warn("CEE file: Device instance not found. " \ 571 "ddinst=%d\n", ddiinst); 572 goto done; 573 } 574 575 if (mdb_vread(&dump_ceefile, sizeof (dump_ceefile), addr) 576 != sizeof (dump_ceefile)) { 577 mdb_warn("CEE file: Unable to read %d bytes @ %llx.\n", 578 sizeof (dump_ceefile), addr); 579 goto done; 580 } 581 582 size = (uintptr_t)dump_ceefile.ptr - 583 (uintptr_t)dump_ceefile.buffer; 584 585 if (size == 0) { 586 mdb_printf("CEE file: Not available.\n"); 587 goto done; 588 } 589 590 bptr = (uint8_t *)mdb_zalloc(size, UM_SLEEP|UM_GC); 591 592 if (bptr == 0) { 593 mdb_warn("CEE file: Unable to allocate file buffer. " \ 594 "ddinst=%d size=%d\n", ddiinst, size); 595 goto done; 596 } 597 598 if (mdb_vread(bptr, size, (uintptr_t)dump_ceefile.buffer) 599 != size) { 600 mdb_warn("CEE file: Unable to read %d bytes @ %llx.\n", 601 size, dump_ceefile.buffer); 602 goto done; 603 } 604 605 mdb_printf("<CEE File Start>\n"); 606 mdb_printf("\n"); 607 608 bzero(buffer2, sizeof (buffer2)); 609 cptr = buffer2; 610 for (i = 0; i < size; i++) { 611 if (i && !(i % 16)) { 612 mdb_printf(" %s\n", buffer2); 613 bzero(buffer2, sizeof (buffer2)); 614 cptr = buffer2; 615 } 616 617 if (!(i % 16)) { 618 mdb_printf("%08X: ", i); 619 } 620 621 if (!(i % 4)) { 622 mdb_printf(" "); 623 } 624 625 if ((*bptr >= 32) && (*bptr <= 126)) { 626 *cptr++ = *bptr; 627 } else { 628 *cptr++ = '.'; 629 } 630 631 mdb_printf("%02X ", *bptr++); 632 } 633 634 size = 16 - (i % 16); 635 for (i = 0; size < 16 && i < size; i++) { 636 if (!(i % 4)) { 637 mdb_printf(" "); 638 } 639 640 mdb_printf(" "); 641 } 642 mdb_printf(" %s\n", buffer2); 643 mdb_printf("\n"); 644 mdb_printf("<CEE File End>\n"); 645 } 646 done: 647 648 mdb_printf("\n"); 649 return (0); 650 651 usage: 652 mdb_printf("Usage: ::%s_dump <file> <instance (hex)>\n", 653 DRIVER_NAME); 654 mdb_printf("mdb: try \"::help %s_dump\" for more information", 655 DRIVER_NAME); 656 657 return (DCMD_ERR); 658 659 } /* emlxs_dump() */ 660