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