1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright (c) 2018 by Chelsio Communications, Inc. 14 */ 15 16 /* 17 * Copyright 2019 Joyent, Inc. 18 * Copyright 2025 Oxide Computer Company 19 */ 20 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <unistd.h> 24 #include <stropts.h> 25 #include <sys/types.h> 26 #include <sys/stat.h> 27 #include <fcntl.h> 28 #include <sys/socket.h> 29 #include <strings.h> 30 #include <sys/varargs.h> 31 #include <errno.h> 32 #include <sys/byteorder.h> 33 #include <inttypes.h> 34 #include <sys/sysmacros.h> 35 #include <err.h> 36 #include <libdevinfo.h> 37 38 #include "t4nex.h" 39 #include "osdep.h" 40 #include "t4fw_interface.h" 41 #include "cudbg.h" 42 #include "cudbg_lib_common.h" 43 #include "cudbg_entity.h" 44 45 #define CUDBG_SIZE (32 * 1024 * 1024) 46 #define CUDBG_MAX_ENTITY_STR_LEN 4096 47 #define MAX_PARAM_LEN 4096 48 #ifndef MAX 49 #define MAX(x, y) ((x) > (y) ? (x) : (y)) 50 #endif 51 52 #define T4_NEXUS_NAME "t4nex" 53 #define T4_PORT_NAME "cxgbe" 54 55 struct reg_info { 56 const char *name; 57 uint32_t addr; 58 uint32_t len; 59 }; 60 61 struct mod_regs { 62 const char *name; 63 const struct reg_info *ri; 64 unsigned int offset; 65 }; 66 67 #include "reg_defs.h" 68 69 static char cxgbetool_nexus[PATH_MAX]; 70 71 char *option_list[] = { 72 "--collect", 73 "--view", 74 }; 75 76 enum { 77 CUDBG_OPT_COLLECT, 78 CUDBG_OPT_VIEW, 79 CUDBG_OPT_VERSION, 80 }; 81 82 /* 83 * Firmware Device Log Dumping 84 */ 85 86 static const char * const devlog_level_strings[] = { 87 [FW_DEVLOG_LEVEL_EMERG] = "EMERG", 88 [FW_DEVLOG_LEVEL_CRIT] = "CRIT", 89 [FW_DEVLOG_LEVEL_ERR] = "ERR", 90 [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", 91 [FW_DEVLOG_LEVEL_INFO] = "INFO", 92 [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" 93 }; 94 95 static const char * const devlog_facility_strings[] = { 96 [FW_DEVLOG_FACILITY_CORE] = "CORE", 97 [FW_DEVLOG_FACILITY_CF] = "CF", 98 [FW_DEVLOG_FACILITY_SCHED] = "SCHED", 99 [FW_DEVLOG_FACILITY_TIMER] = "TIMER", 100 [FW_DEVLOG_FACILITY_RES] = "RES", 101 [FW_DEVLOG_FACILITY_HW] = "HW", 102 [FW_DEVLOG_FACILITY_FLR] = "FLR", 103 [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", 104 [FW_DEVLOG_FACILITY_PHY] = "PHY", 105 [FW_DEVLOG_FACILITY_MAC] = "MAC", 106 [FW_DEVLOG_FACILITY_PORT] = "PORT", 107 [FW_DEVLOG_FACILITY_VI] = "VI", 108 [FW_DEVLOG_FACILITY_FILTER] = "FILTER", 109 [FW_DEVLOG_FACILITY_ACL] = "ACL", 110 [FW_DEVLOG_FACILITY_TM] = "TM", 111 [FW_DEVLOG_FACILITY_QFC] = "QFC", 112 [FW_DEVLOG_FACILITY_DCB] = "DCB", 113 [FW_DEVLOG_FACILITY_ETH] = "ETH", 114 [FW_DEVLOG_FACILITY_OFLD] = "OFLD", 115 [FW_DEVLOG_FACILITY_RI] = "RI", 116 [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", 117 [FW_DEVLOG_FACILITY_FCOE] = "FCOE", 118 [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", 119 [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE", 120 [FW_DEVLOG_FACILITY_CHNET] = "CHNET", 121 }; 122 123 static const char *progname; 124 int set_dbg_entity(u8 *dbg_bitmap, char *dbg_entity_list); 125 126 static int check_option(char *opt) 127 { 128 int i; 129 130 for (i = 0; i < ARRAY_SIZE(option_list); i++) { 131 if (!strcmp(opt, option_list[i])) 132 return i; 133 } 134 return -1; 135 } 136 137 static void usage(FILE *fp) 138 { 139 fprintf(fp, "Usage: %s <t4nex# | cxgbe#> [operation]\n", progname); 140 fprintf(fp, 141 "\tdevlog show device log\n" 142 "\tloadfw <FW image> Flash the FW image\n" 143 "\tcudbg <option> [<args>] Chelsio Unified Debugger\n" 144 "\tregdump [<module>] Dump registers\n" 145 "\treg <address>[=<val>] Read or write the registers\n"); 146 exit(fp == stderr ? 1 : 0); 147 } 148 149 static int 150 doit(const char *iff_name, unsigned long cmd, void *data) 151 { 152 int fd = 0; 153 int rc = 0; 154 155 if ((fd = open(iff_name, O_RDWR)) < 0) 156 return (-1); 157 158 rc = (ioctl(fd, cmd, data) < 0) ? errno : rc; 159 close(fd); 160 return (rc); 161 } 162 163 static void 164 get_devlog(int argc, char *argv[], int start_arg, const char *iff_name) 165 { 166 struct t4_devlog *devlog; 167 struct fw_devlog_e *entry, *buf; 168 int rc = 0, first = 0, nentries, i, j, len; 169 uint64_t ftstamp = UINT64_MAX; 170 171 devlog = malloc(T4_DEVLOG_SIZE + sizeof (struct t4_devlog)); 172 if (!devlog) 173 err(1, "%s: can't allocate devlog buffer", __func__); 174 175 devlog->len = T4_DEVLOG_SIZE; 176 /* Get device log */ 177 rc = doit(iff_name, T4_IOCTL_DEVLOG, devlog); 178 if (rc == ENOBUFS) { 179 /* 180 * Default buffer size is not sufficient to hold device log. 181 * Driver has updated the devlog.len to indicate the expected 182 * size. Free the currently allocated devlog.data, allocate 183 * again with right size and retry. 184 */ 185 len = devlog->len; 186 free(devlog); 187 188 if ((devlog = malloc(len + sizeof (struct t4_devlog))) == NULL) 189 err(1, "%s: can't reallocate devlog buffer", __func__); 190 191 rc = doit(iff_name, T4_IOCTL_DEVLOG, devlog); 192 } 193 if (rc) { 194 free(devlog); 195 errx(1, "%s: can't get device log", __func__); 196 } 197 198 /* There are nentries number of entries in the buffer */ 199 nentries = (devlog->len / sizeof (struct fw_devlog_e)); 200 201 buf = (struct fw_devlog_e *)devlog->data; 202 203 /* Find the first entry */ 204 for (i = 0; i < nentries; i++) { 205 entry = &buf[i]; 206 207 if (entry->timestamp == 0) 208 break; 209 210 entry->timestamp = BE_64(entry->timestamp); 211 entry->seqno = BE_32(entry->seqno); 212 for (j = 0; j < 8; j++) 213 entry->params[j] = BE_32(entry->params[j]); 214 215 if (entry->timestamp < ftstamp) { 216 ftstamp = entry->timestamp; 217 first = i; 218 } 219 } 220 221 printf("%10s %15s %8s %8s %s\n", "Seq#", "Tstamp", "Level", 222 "Facility", "Message"); 223 224 i = first; 225 226 do { 227 entry = &buf[i]; 228 229 if (entry->timestamp == 0) 230 break; 231 232 printf("%10d %15llu %8s %8s ", entry->seqno, 233 entry->timestamp, 234 (entry->level < ARRAY_SIZE(devlog_level_strings) ? 235 devlog_level_strings[entry->level] : "UNKNOWN"), 236 (entry->facility < ARRAY_SIZE(devlog_facility_strings) ? 237 devlog_facility_strings[entry->facility] : "UNKNOWN")); 238 239 printf((const char *)entry->fmt, entry->params[0], 240 entry->params[1], entry->params[2], entry->params[3], 241 entry->params[4], entry->params[5], entry->params[6], 242 entry->params[7]); 243 244 if (++i == nentries) 245 i = 0; 246 247 } while (i != first); 248 249 free(devlog); 250 } 251 252 static uint32_t xtract(uint32_t val, int shift, int len) 253 { 254 return (val >> shift) & ((1 << len) - 1); 255 } 256 257 int dump_block_regs(const struct reg_info *reg_array, const u32 *regs) 258 { 259 uint32_t reg_val = 0; 260 261 for ( ; reg_array->name; ++reg_array) { 262 if (!reg_array->len) { 263 reg_val = regs[reg_array->addr / 4]; 264 printf("[%#7x] %-47s %#-10x %u\n", reg_array->addr, 265 reg_array->name, reg_val, reg_val); 266 } else { 267 uint32_t v = xtract(reg_val, reg_array->addr, 268 reg_array->len); 269 printf(" %*u:%u %-47s %#-10x %u\n", 270 reg_array->addr < 10 ? 3 : 2, 271 reg_array->addr + reg_array->len - 1, 272 reg_array->addr, reg_array->name, v, v); 273 } 274 } 275 return 1; 276 } 277 278 int dump_regs_table(int argc, char *argv[], int start_arg, 279 const u32 *regs, const struct mod_regs *modtab, 280 int nmodules, const char *modnames) 281 { 282 int match = 0; 283 const char *block_name = NULL; 284 285 if (argc == start_arg + 1) 286 block_name = argv[start_arg]; 287 else if (argc != start_arg) 288 return -1; 289 290 for ( ; nmodules; nmodules--, modtab++) { 291 if (!block_name || !strcmp(block_name, modtab->name)) 292 match += dump_block_regs(modtab->ri, 293 regs + modtab->offset); 294 } 295 if (!match) 296 errx(1, "unknown block \"%s\"\navailable: %s", block_name, 297 modnames); 298 return 0; 299 } 300 301 #define T5_MODREGS(name) { #name, t5_##name##_regs } 302 static int 303 dump_regs_t5(int argc, char *argv[], int start_arg, uint32_t *regs) 304 { 305 static struct mod_regs t5_mod[] = { 306 T5_MODREGS(sge), 307 { "pci", t5_pcie_regs }, 308 T5_MODREGS(dbg), 309 { "mc0", t5_mc_0_regs }, 310 { "mc1", t5_mc_1_regs }, 311 T5_MODREGS(ma), 312 { "edc0", t5_edc_t50_regs }, 313 { "edc1", t5_edc_t51_regs }, 314 T5_MODREGS(cim), 315 T5_MODREGS(tp), 316 { "ulprx", t5_ulp_rx_regs }, 317 { "ulptx", t5_ulp_tx_regs }, 318 { "pmrx", t5_pm_rx_regs }, 319 { "pmtx", t5_pm_tx_regs }, 320 T5_MODREGS(mps), 321 { "cplsw", t5_cpl_switch_regs }, 322 T5_MODREGS(smb), 323 { "i2c", t5_i2cm_regs }, 324 T5_MODREGS(mi), 325 T5_MODREGS(uart), 326 T5_MODREGS(pmu), 327 T5_MODREGS(sf), 328 T5_MODREGS(pl), 329 T5_MODREGS(le), 330 T5_MODREGS(ncsi), 331 T5_MODREGS(mac), 332 { "hma", t5_hma_t5_regs } 333 }; 334 335 return dump_regs_table(argc, argv, start_arg, regs, t5_mod, 336 ARRAY_SIZE(t5_mod), 337 "sge, pci, dbg, mc0, mc1, ma, edc0, edc1, cim, " 338 "tp, ulprx, ulptx, pmrx, pmtx, mps, cplsw, smb, " 339 "i2c, mi, uart, pmu, sf, pl, le, ncsi, " 340 "mac, hma"); 341 } 342 343 #undef T5_MODREGS 344 345 #define T6_MODREGS(name) { #name, t6_##name##_regs } 346 static int dump_regs_t6(int argc, char *argv[], int start_arg, const u32 *regs) 347 { 348 static struct mod_regs t6_mod[] = { 349 T6_MODREGS(sge), 350 { "pci", t6_pcie_regs }, 351 T6_MODREGS(dbg), 352 { "mc0", t6_mc_0_regs }, 353 T6_MODREGS(ma), 354 { "edc0", t6_edc_t60_regs }, 355 { "edc1", t6_edc_t61_regs }, 356 T6_MODREGS(cim), 357 T6_MODREGS(tp), 358 { "ulprx", t6_ulp_rx_regs }, 359 { "ulptx", t6_ulp_tx_regs }, 360 { "pmrx", t6_pm_rx_regs }, 361 { "pmtx", t6_pm_tx_regs }, 362 T6_MODREGS(mps), 363 { "cplsw", t6_cpl_switch_regs }, 364 T6_MODREGS(smb), 365 { "i2c", t6_i2cm_regs }, 366 T6_MODREGS(mi), 367 T6_MODREGS(uart), 368 T6_MODREGS(pmu), 369 T6_MODREGS(sf), 370 T6_MODREGS(pl), 371 T6_MODREGS(le), 372 T6_MODREGS(ncsi), 373 T6_MODREGS(mac), 374 { "hma", t6_hma_t6_regs } 375 }; 376 377 return dump_regs_table(argc, argv, start_arg, regs, t6_mod, 378 ARRAY_SIZE(t6_mod), 379 "sge, pci, dbg, mc0, ma, edc0, edc1, cim, " 380 "tp, ulprx, ulptx, pmrx, pmtx, mps, cplsw, smb, " 381 "i2c, mi, uart, pmu, sf, pl, le, ncsi, " 382 "mac, hma"); 383 } 384 #undef T6_MODREGS 385 386 static int 387 get_regdump(int argc, char *argv[], int start_arg, const char *iff_name) 388 { 389 int rc, vers, revision, is_pcie; 390 uint32_t len, length; 391 struct t4_regdump *regs; 392 393 len = MAX(T5_REGDUMP_SIZE, T6_REGDUMP_SIZE); 394 395 regs = malloc(len + sizeof(struct t4_regdump)); 396 if (!regs) 397 err(1, "%s: can't allocate reg dump buffer", __func__); 398 399 regs->len = len; 400 401 rc = doit(iff_name, T4_IOCTL_REGDUMP, regs); 402 403 if (rc == ENOBUFS) { 404 length = regs->len; 405 free(regs); 406 407 regs = malloc(length + sizeof(struct t4_regdump)); 408 if (regs == NULL) 409 err(1, "%s: can't reallocate regs buffer", __func__); 410 411 rc = doit(iff_name, T4_IOCTL_REGDUMP, regs); 412 } 413 414 if (rc) { 415 free(regs); 416 errx(1, "%s: can't get register dumps", __func__); 417 } 418 419 vers = regs->version & 0x3ff; 420 revision = (regs->version >> 10) & 0x3f; 421 is_pcie = (regs->version & 0x80000000) != 0; 422 423 if (vers == 5) { 424 return dump_regs_t5(argc, argv, start_arg, regs->data); 425 } else if (vers == 6) { 426 return dump_regs_t6(argc, argv, start_arg, regs->data); 427 } else { 428 errx(1, "unknown card type %d.%d.%d", vers, revision, is_pcie); 429 } 430 431 return 0; 432 } 433 434 static void 435 write_reg(const char *iff_name, uint32_t addr, uint32_t val) 436 { 437 struct t4_reg32_cmd reg; 438 439 reg.reg = addr; 440 reg.value = val; 441 442 if (doit(iff_name, T4_IOCTL_PUT32, ®) < 0) 443 err(1, "register write"); 444 } 445 446 static uint32_t 447 read_reg(const char *iff_name, uint32_t addr) 448 { 449 struct t4_reg32_cmd reg; 450 451 reg.reg = addr; 452 453 if (doit(iff_name, T4_IOCTL_GET32, ®) < 0) 454 err(1, "register read"); 455 return reg.value; 456 } 457 458 static void register_io(int argc, char *argv[], int start_arg, 459 const char *iff_name) 460 { 461 char *p; 462 uint32_t addr = 0, val = 0, write = 0; 463 464 if (argc != start_arg + 1) { 465 errx(1, "incorrect number of arguments"); 466 } 467 errno = 0; 468 addr = strtoul(argv[start_arg], &p, 0); 469 if (addr == 0 || errno != 0) { 470 errx(1, "invalid arguments"); 471 } 472 473 if (p == argv[start_arg]) 474 return; 475 if (*p == '=' && p[1]) { 476 val = strtoul(p + 1, &p, 0); 477 write = 1; 478 } 479 if (*p) { 480 errx(1, "bad parameter \"%s\"", argv[start_arg]); 481 } 482 483 if (write) { 484 write_reg(iff_name, addr, val); 485 } else { 486 val = read_reg(iff_name, addr); 487 printf("%#x [%u]\n", val, val); 488 } 489 } 490 491 static void 492 load_fw(int argc, char *argv[], int start_arg, const char *iff_name) 493 { 494 const char *fname = argv[start_arg]; 495 struct t4_ldfw *fw; 496 struct stat sb; 497 size_t len; 498 int fd; 499 500 if (argc != 4) 501 errx(1, "incorrect number of arguments"); 502 503 fd = open(fname, O_RDONLY); 504 if (fd < 0) 505 err(1, "%s: opening %s failed", __func__, fname); 506 if (fstat(fd, &sb) < 0) { 507 warn("%s: fstat %s failed", __func__, fname); 508 close(fd); 509 exit(1); 510 } 511 len = (size_t)sb.st_size; 512 513 fw = malloc(sizeof (struct t4_ldfw) + len); 514 if (!fw) { 515 warn("%s: %s allocate %zu bytes failed", 516 __func__, fname, sizeof (struct t4_ldfw) + len); 517 close(fd); 518 exit(1); 519 } 520 521 if (read(fd, fw->data, len) < len) { 522 warn("%s: %s read failed", __func__, fname); 523 close(fd); 524 free(fw); 525 exit(1); 526 } 527 528 close(fd); 529 530 fw->len = len; 531 532 if (doit(iff_name, T4_IOCTL_LOAD_FW, fw)) { 533 free(fw); 534 err(1, "%s: IOCTL failed", __func__); 535 } else { 536 printf("FW flash success, reload driver/reboot to take " 537 "effect\n"); 538 } 539 540 free(fw); 541 } 542 543 int read_input_file(char *in_file, void **buf, int *buf_size) 544 { 545 FILE *fptr = NULL; 546 size_t count; 547 int rc = 0; 548 549 fptr = fopen(in_file, "rb"); 550 if (!fptr) { 551 perror("error in opening file "); 552 rc = -1; 553 goto out; 554 } 555 rc = fseek(fptr, 0, SEEK_END); 556 if (rc < 0) { 557 perror("error in seeking file "); 558 rc = -1; 559 goto out; 560 } 561 *buf_size = ftell(fptr); 562 rc = fseek(fptr, 0, SEEK_SET); 563 if (rc < 0) { 564 perror("error in seeking file "); 565 rc = -1; 566 goto out; 567 } 568 *buf = (void *) malloc(*buf_size); 569 if (*buf == NULL) { 570 rc = CUDBG_STATUS_NOSPACE; 571 goto out; 572 } 573 memset(*buf, 0, *buf_size); 574 575 count = fread(*buf, 1, *buf_size, fptr); 576 if (count != *buf_size) { 577 perror("error in reading from file "); 578 goto out; 579 } 580 581 out: 582 if (fptr) 583 fclose(fptr); 584 585 return rc; 586 } 587 588 static void 589 do_collect(char *dbg_entity_list, const char *iff_name, const char *fname) 590 { 591 struct t4_cudbg_dump *cudbg; 592 int fd; 593 594 cudbg = malloc(sizeof(struct t4_cudbg_dump) + CUDBG_SIZE); 595 if (!cudbg) { 596 err(1, "%s:allocate %d bytes failed", __func__, CUDBG_SIZE); 597 } 598 599 memset(cudbg, 0, sizeof(struct t4_cudbg_dump) + CUDBG_SIZE); 600 601 cudbg->len = CUDBG_SIZE; 602 603 set_dbg_entity(cudbg->bitmap, dbg_entity_list); 604 605 if (doit(iff_name, T4_IOCTL_GET_CUDBG, cudbg)) { 606 free(cudbg); 607 err(1, "%s: IOCTL failed", __func__); 608 } 609 610 fd = open(fname, O_CREAT | O_TRUNC | O_EXCL | O_WRONLY, 611 S_IRUSR | S_IRGRP | S_IROTH); 612 if (fd < 0) { 613 err(1, "%s: file open failed", __func__); 614 } 615 616 write(fd, cudbg->data, cudbg->len); 617 close(fd); 618 free(cudbg); 619 } 620 621 static void 622 do_view(char *dbg_entity_list, char *in_file) 623 { 624 void *handle = NULL; 625 void *buf = NULL; 626 int buf_size = 32 * 1024 * 1024; 627 int next_offset = 0; 628 int data_len; 629 int rc = 0; 630 631 handle = cudbg_alloc_handle(); 632 if (!handle) 633 goto out; 634 /* rcad from file */ 635 rc = read_input_file(in_file, &buf, &buf_size); 636 if (rc < 0) { 637 goto out; 638 } 639 640 set_dbg_entity(((struct cudbg_private *)handle)->dbg_init.dbg_bitmap, 641 dbg_entity_list); 642 do { 643 if (buf_size - next_offset <= 0) 644 break; 645 646 data_len = cudbg_view(handle, buf+next_offset, 647 buf_size-next_offset, NULL, 0); 648 next_offset += data_len; 649 if (data_len > 0) 650 printf("\n\t\t<========================END============="\ 651 "===========>\t\t\n\n\n"); 652 } while (data_len > 0); 653 654 out: 655 if (buf) 656 free(buf); 657 if (handle) 658 cudbg_free_handle(handle); 659 return; 660 } 661 662 typedef void (*cudbg_alias_get_entities_cb)(char *dst, u32 dst_size); 663 664 struct entity_access_list { 665 const char *name; 666 cudbg_alias_get_entities_cb get_entities_cb; 667 }; 668 669 void 670 cudbg_append_string(char *dst, u32 dst_size, char *src) 671 { 672 strlcat(dst, src, dst_size); 673 strlcat(dst, ",", dst_size); 674 } 675 676 static void 677 cudbg_alias_get_allregs(char *dst, u32 dst_size) 678 { 679 u32 i; 680 681 for (i = 0; i < ARRAY_SIZE(entity_list); i++) 682 if (entity_list[i].flag & (1 << ENTITY_FLAG_REGISTER)) 683 cudbg_append_string(dst, dst_size, entity_list[i].name); 684 } 685 686 static struct entity_access_list ATTRIBUTE_UNUSED entity_alias_list[] = { 687 {"allregs", cudbg_alias_get_allregs}, 688 }; 689 690 static int 691 check_dbg_entity(char *entity) 692 { 693 u32 i; 694 695 for (i = 0; i < ARRAY_SIZE(entity_list); i++) 696 if (!strcmp(entity, entity_list[i].name)) 697 return entity_list[i].bit; 698 return -1; 699 } 700 701 /* Get matching alias index from entity_alias_list[] */ 702 static 703 int get_alias(const char *entity) 704 { 705 u32 i; 706 707 for (i = 0; i < ARRAY_SIZE(entity_alias_list); i++) 708 if (!strcmp(entity, entity_alias_list[i].name)) 709 return i; 710 return -1; 711 } 712 713 static int 714 parse_entity_list(const char *dbg_entity_list, char *dst, 715 u32 dst_size) 716 { 717 char *tmp_dbg_entity_list; 718 char *dbg_entity; 719 int rc, i; 720 721 /* Holds single entity name de-limited by comma */ 722 tmp_dbg_entity_list = malloc(CUDBG_MAX_ENTITY_STR_LEN); 723 if (!tmp_dbg_entity_list) 724 return ENOMEM; 725 726 strlcpy(tmp_dbg_entity_list, dbg_entity_list, CUDBG_MAX_ENTITY_STR_LEN); 727 dbg_entity = strtok(tmp_dbg_entity_list, ","); 728 while (dbg_entity != NULL) { 729 /* See if specified entity name exists. If it doesn't 730 * exist, see if the entity name is an alias. 731 * If it's not a valid entity name, bail with error. 732 */ 733 rc = check_dbg_entity(dbg_entity); 734 if (rc < 0) { 735 i = get_alias(dbg_entity); 736 if (i < 0) { 737 /* Not an alias, and not a valid entity name */ 738 printf("\nUnknown entity: %s\n", dbg_entity); 739 rc = CUDBG_STATUS_ENTITY_NOT_FOUND; 740 goto out_err; 741 } else { 742 /* If alias is found, get all the corresponding 743 * debug entities related to the alias. 744 */ 745 entity_alias_list[i].get_entities_cb(dst, dst_size); 746 } 747 } else { 748 /* Not an alias, but is a valid entity name. 749 * So, append the corresponding debug entity. 750 */ 751 cudbg_append_string(dst, dst_size, entity_list[rc].name); 752 } 753 dbg_entity = strtok(NULL, ","); 754 } 755 756 rc = 0; 757 758 out_err: 759 free(tmp_dbg_entity_list); 760 return rc; 761 } 762 763 static 764 int get_entity_list(const char *in_buff, char **out_buff) 765 { 766 char *dbg_entity_list; 767 int rc; 768 769 /* Allocate enough to hold converted alias string. 770 * Must be freed by caller 771 */ 772 dbg_entity_list = malloc(CUDBG_MAX_ENTITY_STR_LEN); 773 if (!dbg_entity_list) 774 return ENOMEM; 775 776 memset(dbg_entity_list, 0, CUDBG_MAX_ENTITY_STR_LEN); 777 rc = parse_entity_list(in_buff, dbg_entity_list, 778 CUDBG_MAX_ENTITY_STR_LEN); 779 if (rc) { 780 free(dbg_entity_list); 781 return rc; 782 } 783 784 /* Remove the last comma */ 785 dbg_entity_list[strlen(dbg_entity_list) - 1] = '\0'; 786 *out_buff = dbg_entity_list; 787 return 0; 788 } 789 790 static void 791 put_entity_list(char *buf) 792 { 793 if (buf) 794 free(buf); 795 } 796 797 int 798 set_dbg_entity(u8 *dbg_bitmap, char *dbg_entity_list) 799 { 800 int i, dbg_entity_bit, rc = 0; 801 char *dbg_entity; 802 char *dbg_entity_list_tmp; 803 804 dbg_entity_list_tmp = malloc(MAX_PARAM_LEN); 805 if (!dbg_entity_list_tmp) { 806 rc = CUDBG_STATUS_NOSPACE; 807 return rc; 808 } 809 810 if (dbg_entity_list != NULL) { 811 strlcpy(dbg_entity_list_tmp, dbg_entity_list, MAX_PARAM_LEN); 812 dbg_entity = strtok(dbg_entity_list_tmp, ","); 813 } 814 else 815 dbg_entity = NULL; 816 817 while (dbg_entity != NULL) { 818 rc = check_dbg_entity(dbg_entity); 819 if (rc < 0) { 820 printf("\n\tInvalid debug entity: %s\n", dbg_entity); 821 //Vishal cudbg_usage(); 822 goto out_free; 823 } 824 825 dbg_entity_bit = rc; 826 827 if (dbg_entity_bit == CUDBG_ALL) { 828 for (i = 1; i < CUDBG_MAX_ENTITY; i++) 829 set_dbg_bitmap(dbg_bitmap, i); 830 set_dbg_bitmap(dbg_bitmap, CUDBG_ALL); 831 break; 832 } else { 833 set_dbg_bitmap(dbg_bitmap, dbg_entity_bit); 834 } 835 836 dbg_entity = strtok(NULL, ","); 837 } 838 839 rc = 0; 840 841 out_free: 842 free(dbg_entity_list_tmp); 843 return rc; 844 } 845 846 847 static void 848 get_cudbg(int argc, char *argv[], int start_arg, const char *iff_name) 849 { 850 char *dbg_entity_list = NULL; 851 int rc = 0, option; 852 853 if (start_arg >= argc) 854 errx(1, "no option provided"); 855 856 rc = check_option(argv[start_arg++]); 857 if (rc < 0) { 858 errx(1, "%s:Invalid option provided", __func__); 859 } 860 option = rc; 861 862 if (option == CUDBG_OPT_VERSION) { 863 printf("Library Version %d.%d.%d\n", CUDBG_MAJOR_VERSION, 864 CUDBG_MINOR_VERSION, CUDBG_BUILD_VERSION); 865 return; 866 } 867 868 if (argc < 5) { 869 errx(1, "Invalid number of arguments\n"); 870 } 871 rc = get_entity_list(argv[start_arg++], 872 &dbg_entity_list); 873 if (rc) { 874 errx(1, "Error in parsing entity\n"); 875 } 876 877 if (argc < 6) { 878 errx(1, "File name is missing\n"); 879 } 880 881 switch (option) { 882 case CUDBG_OPT_COLLECT: 883 do_collect(dbg_entity_list, iff_name, argv[start_arg]); 884 break; 885 case CUDBG_OPT_VIEW: 886 do_view(dbg_entity_list, argv[start_arg]); 887 break; 888 default: 889 errx(1, "Wrong option provided\n"); 890 } 891 892 put_entity_list(dbg_entity_list); 893 } 894 895 static void 896 run_cmd(int argc, char *argv[], const char *iff_name) 897 { 898 if (strcmp(argv[2], "devlog") == 0) 899 get_devlog(argc, argv, 3, iff_name); 900 else if (strcmp(argv[2], "loadfw") == 0) 901 load_fw(argc, argv, 3, iff_name); 902 else if (strcmp(argv[2], "cudbg") == 0) 903 get_cudbg(argc, argv, 3, iff_name); 904 else if (strcmp(argv[2], "regdump") == 0) 905 get_regdump(argc, argv, 3, iff_name); 906 else if (strcmp(argv[2], "reg") == 0) 907 register_io(argc, argv, 3, iff_name); 908 else 909 usage(stderr); 910 } 911 912 /* 913 * Traditionally we expect to be given a path to the t4nex device control file 914 * hidden in /devices. To make life easier, we want to also support folks using 915 * the driver instance numbers for either a given t4nex%d or cxgbe%d. We check 916 * to see if we've been given a path to a character device and if so, just 917 * continue straight on with the given argument. Otherwise we attempt to map it 918 * to something known. 919 */ 920 static const char * 921 cxgbetool_parse_path(char *arg) 922 { 923 struct stat st; 924 di_node_t root, node; 925 const char *numptr, *errstr; 926 size_t drvlen; 927 int inst; 928 boolean_t is_t4nex = B_TRUE; 929 char mname[64]; 930 931 if (stat(arg, &st) == 0) { 932 if (S_ISCHR(st.st_mode)) { 933 return (arg); 934 } 935 } 936 937 if (strncmp(arg, T4_NEXUS_NAME, sizeof (T4_NEXUS_NAME) - 1) == 0) { 938 drvlen = sizeof (T4_NEXUS_NAME) - 1; 939 } else if (strncmp(arg, T4_PORT_NAME, sizeof (T4_PORT_NAME) - 1) == 0) { 940 is_t4nex = B_FALSE; 941 drvlen = sizeof (T4_PORT_NAME) - 1; 942 } else { 943 errx(EXIT_FAILURE, "cannot use device %s: not a character " 944 "device or a %s/%s device instance", arg, T4_PORT_NAME, 945 T4_NEXUS_NAME); 946 } 947 948 numptr = arg + drvlen; 949 inst = (int)strtonum(numptr, 0, INT_MAX, &errstr); 950 if (errstr != NULL) { 951 errx(EXIT_FAILURE, "failed to parse instance number '%s': %s", 952 numptr, errstr); 953 } 954 955 /* 956 * Now that we have the instance here, we need to truncate the string at 957 * the end of the driver name otherwise di_drv_first_node() will be very 958 * confused as there is no driver called say 't4nex0'. 959 */ 960 arg[drvlen] = '\0'; 961 root = di_init("/", DINFOCPYALL); 962 if (root == DI_NODE_NIL) { 963 err(EXIT_FAILURE, "failed to initialize libdevinfo while " 964 "trying to map device name %s", arg); 965 } 966 967 for (node = di_drv_first_node(arg, root); node != DI_NODE_NIL; 968 node = di_drv_next_node(node)) { 969 char *bpath; 970 di_minor_t minor = DI_MINOR_NIL; 971 972 if (di_instance(node) != inst) { 973 continue; 974 } 975 976 if (!is_t4nex) { 977 const char *pdrv; 978 node = di_parent_node(node); 979 pdrv = di_driver_name(node); 980 if (pdrv == NULL || strcmp(pdrv, T4_NEXUS_NAME) != 0) { 981 errx(EXIT_FAILURE, "%s does not have %s " 982 "parent, found %s%d", arg, T4_NEXUS_NAME, 983 pdrv != NULL ? pdrv : "unknown", 984 pdrv != NULL ? di_instance(node) : -1); 985 } 986 } 987 988 (void) snprintf(mname, sizeof (mname), "%s,%d", T4_NEXUS_NAME, 989 di_instance(node)); 990 991 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 992 if (strcmp(di_minor_name(minor), mname) == 0) { 993 break; 994 } 995 } 996 997 if (minor == DI_MINOR_NIL) { 998 errx(EXIT_FAILURE, "failed to find minor %s on %s%d", 999 mname, di_driver_name(node), di_instance(node)); 1000 } 1001 1002 bpath = di_devfs_minor_path(minor); 1003 if (bpath == NULL) { 1004 err(EXIT_FAILURE, "failed to get minor path for " 1005 "%s%d:%s", di_driver_name(node), di_instance(node), 1006 di_minor_name(minor)); 1007 } 1008 if (snprintf(cxgbetool_nexus, sizeof (cxgbetool_nexus), 1009 "/devices%s", bpath) >= sizeof (cxgbetool_nexus)) { 1010 errx(EXIT_FAILURE, "failed to construct full /devices " 1011 "path for %s: internal path buffer would have " 1012 "overflowed", bpath); 1013 } 1014 di_devfs_path_free(bpath); 1015 1016 di_fini(root); 1017 return (cxgbetool_nexus); 1018 } 1019 1020 errx(EXIT_FAILURE, "failed to map %s%d to a %s or %s instance", 1021 arg, inst, T4_PORT_NAME, T4_NEXUS_NAME); 1022 } 1023 1024 int 1025 main(int argc, char *argv[]) 1026 { 1027 const char *iff_name; 1028 1029 progname = argv[0]; 1030 1031 if (argc == 2) { 1032 if (strcmp(argv[1], "-h") == 0 || 1033 strcmp(argv[1], "--help") == 0) { 1034 usage(stdout); 1035 } 1036 } 1037 1038 if (argc < 3) 1039 usage(stderr); 1040 1041 iff_name = cxgbetool_parse_path(argv[1]); 1042 1043 run_cmd(argc, argv, iff_name); 1044 1045 return (0); 1046 } 1047