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