cxgbetool.c revision 284984
1222900Snp/*- 2222900Snp * Copyright (c) 2011 Chelsio Communications, Inc. 3222900Snp * All rights reserved. 4222900Snp * Written by: Navdeep Parhar <np@FreeBSD.org> 5222900Snp * 6222900Snp * Redistribution and use in source and binary forms, with or without 7222900Snp * modification, are permitted provided that the following conditions 8222900Snp * are met: 9222900Snp * 1. Redistributions of source code must retain the above copyright 10222900Snp * notice, this list of conditions and the following disclaimer. 11222900Snp * 2. Redistributions in binary form must reproduce the above copyright 12222900Snp * notice, this list of conditions and the following disclaimer in the 13222900Snp * documentation and/or other materials provided with the distribution. 14222900Snp * 15222900Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16222900Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17222900Snp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18222900Snp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19222900Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20222900Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21222900Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22222900Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23222900Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24222900Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25222900Snp * SUCH DAMAGE. 26222900Snp */ 27222900Snp 28222900Snp#include <sys/cdefs.h> 29222900Snp__FBSDID("$FreeBSD: head/tools/tools/cxgbetool/cxgbetool.c 284984 2015-06-30 22:30:21Z np $"); 30222900Snp 31222900Snp#include <stdint.h> 32222900Snp#include <stdlib.h> 33228594Snp#include <unistd.h> 34247854Snp#include <ctype.h> 35222900Snp#include <errno.h> 36222900Snp#include <err.h> 37222900Snp#include <fcntl.h> 38222900Snp#include <string.h> 39222900Snp#include <stdio.h> 40222900Snp#include <sys/ioctl.h> 41241401Snp#include <limits.h> 42228594Snp#include <sys/mman.h> 43222900Snp#include <sys/types.h> 44222900Snp#include <sys/socket.h> 45228594Snp#include <sys/stat.h> 46222900Snp#include <net/ethernet.h> 47222900Snp#include <netinet/in.h> 48222900Snp#include <arpa/inet.h> 49258698Snp#include <net/sff8472.h> 50222900Snp 51222900Snp#include "t4_ioctl.h" 52222900Snp 53222900Snp#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 54259048Snp#define in_range(val, lo, hi) ( val < 0 || (val <= hi && val >= lo)) 55222974Snp#define max(x, y) ((x) > (y) ? (x) : (y)) 56222974Snp 57222900Snpstatic const char *progname, *nexus; 58253870Snpstatic int chip_id; /* 4 for T4, 5 for T5 */ 59222900Snp 60222900Snpstruct reg_info { 61222900Snp const char *name; 62222900Snp uint32_t addr; 63222900Snp uint32_t len; 64222900Snp}; 65222900Snp 66222900Snpstruct mod_regs { 67222900Snp const char *name; 68222900Snp const struct reg_info *ri; 69222900Snp}; 70222900Snp 71222974Snpstruct field_desc { 72222974Snp const char *name; /* Field name */ 73222974Snp unsigned short start; /* Start bit position */ 74222974Snp unsigned short end; /* End bit position */ 75222974Snp unsigned char shift; /* # of low order bits omitted and implicitly 0 */ 76222974Snp unsigned char hex; /* Print field in hex instead of decimal */ 77222974Snp unsigned char islog2; /* Field contains the base-2 log of the value */ 78222974Snp}; 79222974Snp 80222900Snp#include "reg_defs_t4.c" 81222900Snp#include "reg_defs_t4vf.c" 82248925Snp#include "reg_defs_t5.c" 83222900Snp 84222900Snpstatic void 85222900Snpusage(FILE *fp) 86222900Snp{ 87222900Snp fprintf(fp, "Usage: %s <nexus> [operation]\n", progname); 88222900Snp fprintf(fp, 89241416Snp "\tclearstats <port> clear port statistics\n" 90222974Snp "\tcontext <type> <id> show an SGE context\n" 91222900Snp "\tfilter <idx> [<param> <val>] ... set a filter\n" 92222900Snp "\tfilter <idx> delete|clear delete a filter\n" 93222900Snp "\tfilter list list all filters\n" 94222900Snp "\tfilter mode [<match>] ... get/set global filter mode\n" 95241401Snp "\ti2c <port> <devaddr> <addr> [<len>] read from i2c device\n" 96228594Snp "\tloadfw <fw-image.bin> install firmware\n" 97228594Snp "\tmemdump <addr> <len> dump a memory range\n" 98269106Snp "\tmodinfo <port> [raw] optics/cable information\n" 99222900Snp "\treg <address>[=<val>] read/write register\n" 100222900Snp "\treg64 <address>[=<val>] read/write 64 bit register\n" 101222900Snp "\tregdump [<module>] ... dump registers\n" 102259048Snp "\tsched-class params <param> <val> .. configure TX scheduler class\n" 103259048Snp "\tsched-queue <port> <queue> <class> bind NIC queues to TX Scheduling class\n" 104222900Snp "\tstdio interactive mode\n" 105228594Snp "\ttcb <tid> read TCB\n" 106259048Snp "\ttracer <idx> tx<n>|rx<n> set and enable a tracer\n" 107253691Snp "\ttracer <idx> disable|enable disable or enable a tracer\n" 108253691Snp "\ttracer list list all tracers\n" 109222900Snp ); 110222900Snp} 111222900Snp 112222900Snpstatic inline unsigned int 113222900Snpget_card_vers(unsigned int version) 114222900Snp{ 115222900Snp return (version & 0x3ff); 116222900Snp} 117222900Snp 118222900Snpstatic int 119222900Snpreal_doit(unsigned long cmd, void *data, const char *cmdstr) 120222900Snp{ 121222900Snp static int fd = -1; 122222900Snp int rc = 0; 123222900Snp 124222900Snp if (fd == -1) { 125222900Snp char buf[64]; 126222900Snp 127222900Snp snprintf(buf, sizeof(buf), "/dev/%s", nexus); 128222900Snp if ((fd = open(buf, O_RDWR)) < 0) { 129222900Snp warn("open(%s)", nexus); 130222900Snp rc = errno; 131222900Snp return (rc); 132222900Snp } 133253870Snp chip_id = nexus[1] - '0'; 134222900Snp } 135222900Snp 136222900Snp rc = ioctl(fd, cmd, data); 137222900Snp if (rc < 0) { 138222900Snp warn("%s", cmdstr); 139222900Snp rc = errno; 140222900Snp } 141222900Snp 142222900Snp return (rc); 143222900Snp} 144222900Snp#define doit(x, y) real_doit(x, y, #x) 145222900Snp 146222900Snpstatic char * 147222900Snpstr_to_number(const char *s, long *val, long long *vall) 148222900Snp{ 149222900Snp char *p; 150222900Snp 151222900Snp if (vall) 152222900Snp *vall = strtoll(s, &p, 0); 153222900Snp else if (val) 154222900Snp *val = strtol(s, &p, 0); 155222900Snp else 156222900Snp p = NULL; 157222900Snp 158222900Snp return (p); 159222900Snp} 160222900Snp 161222900Snpstatic int 162222900Snpread_reg(long addr, int size, long long *val) 163222900Snp{ 164222900Snp struct t4_reg reg; 165222900Snp int rc; 166222900Snp 167222900Snp reg.addr = (uint32_t) addr; 168222900Snp reg.size = (uint32_t) size; 169222900Snp reg.val = 0; 170222900Snp 171222900Snp rc = doit(CHELSIO_T4_GETREG, ®); 172222900Snp 173222900Snp *val = reg.val; 174222900Snp 175222900Snp return (rc); 176222900Snp} 177222900Snp 178222900Snpstatic int 179222900Snpwrite_reg(long addr, int size, long long val) 180222900Snp{ 181222900Snp struct t4_reg reg; 182222900Snp 183222900Snp reg.addr = (uint32_t) addr; 184222900Snp reg.size = (uint32_t) size; 185222900Snp reg.val = (uint64_t) val; 186222900Snp 187222900Snp return doit(CHELSIO_T4_SETREG, ®); 188222900Snp} 189222900Snp 190222900Snpstatic int 191222900Snpregister_io(int argc, const char *argv[], int size) 192222900Snp{ 193222900Snp char *p, *v; 194222900Snp long addr; 195222900Snp long long val; 196222900Snp int w = 0, rc; 197222900Snp 198222900Snp if (argc == 1) { 199222900Snp /* <reg> OR <reg>=<value> */ 200222900Snp 201222900Snp p = str_to_number(argv[0], &addr, NULL); 202222900Snp if (*p) { 203222900Snp if (*p != '=') { 204222900Snp warnx("invalid register \"%s\"", argv[0]); 205222900Snp return (EINVAL); 206222900Snp } 207222900Snp 208222900Snp w = 1; 209222900Snp v = p + 1; 210222900Snp p = str_to_number(v, NULL, &val); 211222900Snp 212222900Snp if (*p) { 213222900Snp warnx("invalid value \"%s\"", v); 214222900Snp return (EINVAL); 215222900Snp } 216222900Snp } 217222900Snp 218222900Snp } else if (argc == 2) { 219222900Snp /* <reg> <value> */ 220222900Snp 221222900Snp w = 1; 222222900Snp 223222900Snp p = str_to_number(argv[0], &addr, NULL); 224222900Snp if (*p) { 225222900Snp warnx("invalid register \"%s\"", argv[0]); 226222900Snp return (EINVAL); 227222900Snp } 228222900Snp 229222900Snp p = str_to_number(argv[1], NULL, &val); 230222900Snp if (*p) { 231222900Snp warnx("invalid value \"%s\"", argv[1]); 232222900Snp return (EINVAL); 233222900Snp } 234222900Snp } else { 235222900Snp warnx("reg: invalid number of arguments (%d)", argc); 236222900Snp return (EINVAL); 237222900Snp } 238222900Snp 239222900Snp if (w) 240222900Snp rc = write_reg(addr, size, val); 241222900Snp else { 242222900Snp rc = read_reg(addr, size, &val); 243222900Snp if (rc == 0) 244222900Snp printf("0x%llx [%llu]\n", val, val); 245222900Snp } 246222900Snp 247222900Snp return (rc); 248222900Snp} 249222900Snp 250222900Snpstatic inline uint32_t 251222900Snpxtract(uint32_t val, int shift, int len) 252222900Snp{ 253222900Snp return (val >> shift) & ((1 << len) - 1); 254222900Snp} 255222900Snp 256222900Snpstatic int 257222900Snpdump_block_regs(const struct reg_info *reg_array, const uint32_t *regs) 258222900Snp{ 259222900Snp uint32_t reg_val = 0; 260222900Snp 261222900Snp for ( ; reg_array->name; ++reg_array) 262222900Snp if (!reg_array->len) { 263222900Snp reg_val = regs[reg_array->addr / 4]; 264222900Snp printf("[%#7x] %-47s %#-10x %u\n", reg_array->addr, 265222900Snp reg_array->name, reg_val, reg_val); 266222900Snp } else { 267222900Snp uint32_t v = xtract(reg_val, reg_array->addr, 268222900Snp reg_array->len); 269222900Snp 270222900Snp printf(" %*u:%u %-47s %#-10x %u\n", 271222900Snp reg_array->addr < 10 ? 3 : 2, 272222900Snp reg_array->addr + reg_array->len - 1, 273222900Snp reg_array->addr, reg_array->name, v, v); 274222900Snp } 275222900Snp 276222900Snp return (1); 277222900Snp} 278222900Snp 279222900Snpstatic int 280222900Snpdump_regs_table(int argc, const char *argv[], const uint32_t *regs, 281222900Snp const struct mod_regs *modtab, int nmodules) 282222900Snp{ 283222900Snp int i, j, match; 284222900Snp 285222900Snp for (i = 0; i < argc; i++) { 286222900Snp for (j = 0; j < nmodules; j++) { 287222900Snp if (!strcmp(argv[i], modtab[j].name)) 288222900Snp break; 289222900Snp } 290222900Snp 291222900Snp if (j == nmodules) { 292222900Snp warnx("invalid register block \"%s\"", argv[i]); 293222900Snp fprintf(stderr, "\nAvailable blocks:"); 294222900Snp for ( ; nmodules; nmodules--, modtab++) 295222900Snp fprintf(stderr, " %s", modtab->name); 296222900Snp fprintf(stderr, "\n"); 297222900Snp return (EINVAL); 298222900Snp } 299222900Snp } 300222900Snp 301222900Snp for ( ; nmodules; nmodules--, modtab++) { 302222900Snp 303222900Snp match = argc == 0 ? 1 : 0; 304222900Snp for (i = 0; !match && i < argc; i++) { 305222900Snp if (!strcmp(argv[i], modtab->name)) 306222900Snp match = 1; 307222900Snp } 308222900Snp 309222900Snp if (match) 310222900Snp dump_block_regs(modtab->ri, regs); 311222900Snp } 312222900Snp 313222900Snp return (0); 314222900Snp} 315222900Snp 316222900Snp#define T4_MODREGS(name) { #name, t4_##name##_regs } 317222900Snpstatic int 318222900Snpdump_regs_t4(int argc, const char *argv[], const uint32_t *regs) 319222900Snp{ 320222900Snp static struct mod_regs t4_mod[] = { 321222900Snp T4_MODREGS(sge), 322222900Snp { "pci", t4_pcie_regs }, 323222900Snp T4_MODREGS(dbg), 324222900Snp T4_MODREGS(mc), 325222900Snp T4_MODREGS(ma), 326222900Snp { "edc0", t4_edc_0_regs }, 327222900Snp { "edc1", t4_edc_1_regs }, 328259048Snp T4_MODREGS(cim), 329222900Snp T4_MODREGS(tp), 330222900Snp T4_MODREGS(ulp_rx), 331222900Snp T4_MODREGS(ulp_tx), 332222900Snp { "pmrx", t4_pm_rx_regs }, 333222900Snp { "pmtx", t4_pm_tx_regs }, 334222900Snp T4_MODREGS(mps), 335222900Snp { "cplsw", t4_cpl_switch_regs }, 336222900Snp T4_MODREGS(smb), 337222900Snp { "i2c", t4_i2cm_regs }, 338222900Snp T4_MODREGS(mi), 339222900Snp T4_MODREGS(uart), 340259048Snp T4_MODREGS(pmu), 341222900Snp T4_MODREGS(sf), 342222900Snp T4_MODREGS(pl), 343222900Snp T4_MODREGS(le), 344222900Snp T4_MODREGS(ncsi), 345222900Snp T4_MODREGS(xgmac) 346222900Snp }; 347222900Snp 348222900Snp return dump_regs_table(argc, argv, regs, t4_mod, ARRAY_SIZE(t4_mod)); 349222900Snp} 350222900Snp#undef T4_MODREGS 351222900Snp 352222900Snpstatic int 353222900Snpdump_regs_t4vf(int argc, const char *argv[], const uint32_t *regs) 354222900Snp{ 355222900Snp static struct mod_regs t4vf_mod[] = { 356222900Snp { "sge", t4vf_sge_regs }, 357222900Snp { "mps", t4vf_mps_regs }, 358222900Snp { "pl", t4vf_pl_regs }, 359222900Snp { "mbdata", t4vf_mbdata_regs }, 360222900Snp { "cim", t4vf_cim_regs }, 361222900Snp }; 362222900Snp 363222900Snp return dump_regs_table(argc, argv, regs, t4vf_mod, 364222900Snp ARRAY_SIZE(t4vf_mod)); 365222900Snp} 366222900Snp 367248925Snp#define T5_MODREGS(name) { #name, t5_##name##_regs } 368222900Snpstatic int 369248925Snpdump_regs_t5(int argc, const char *argv[], const uint32_t *regs) 370248925Snp{ 371248925Snp static struct mod_regs t5_mod[] = { 372248925Snp T5_MODREGS(sge), 373248925Snp { "pci", t5_pcie_regs }, 374248925Snp T5_MODREGS(dbg), 375248925Snp { "mc0", t5_mc_0_regs }, 376248925Snp { "mc1", t5_mc_1_regs }, 377248925Snp T5_MODREGS(ma), 378248925Snp { "edc0", t5_edc_t50_regs }, 379248925Snp { "edc1", t5_edc_t51_regs }, 380248925Snp T5_MODREGS(cim), 381248925Snp T5_MODREGS(tp), 382248925Snp { "ulprx", t5_ulp_rx_regs }, 383248925Snp { "ulptx", t5_ulp_tx_regs }, 384248925Snp { "pmrx", t5_pm_rx_regs }, 385248925Snp { "pmtx", t5_pm_tx_regs }, 386248925Snp T5_MODREGS(mps), 387248925Snp { "cplsw", t5_cpl_switch_regs }, 388248925Snp T5_MODREGS(smb), 389248925Snp { "i2c", t5_i2cm_regs }, 390248925Snp T5_MODREGS(mi), 391248925Snp T5_MODREGS(uart), 392248925Snp T5_MODREGS(pmu), 393248925Snp T5_MODREGS(sf), 394248925Snp T5_MODREGS(pl), 395248925Snp T5_MODREGS(le), 396248925Snp T5_MODREGS(ncsi), 397248925Snp T5_MODREGS(mac), 398248925Snp { "hma", t5_hma_t5_regs } 399248925Snp }; 400248925Snp 401248925Snp return dump_regs_table(argc, argv, regs, t5_mod, ARRAY_SIZE(t5_mod)); 402248925Snp} 403248925Snp#undef T5_MODREGS 404248925Snp 405248925Snpstatic int 406222900Snpdump_regs(int argc, const char *argv[]) 407222900Snp{ 408248925Snp int vers, revision, rc; 409222900Snp struct t4_regdump regs; 410248925Snp uint32_t len; 411222900Snp 412248925Snp len = max(T4_REGDUMP_SIZE, T5_REGDUMP_SIZE); 413248925Snp regs.data = calloc(1, len); 414222900Snp if (regs.data == NULL) { 415222900Snp warnc(ENOMEM, "regdump"); 416222900Snp return (ENOMEM); 417222900Snp } 418222900Snp 419248925Snp regs.len = len; 420222900Snp rc = doit(CHELSIO_T4_REGDUMP, ®s); 421222900Snp if (rc != 0) 422222900Snp return (rc); 423222900Snp 424222900Snp vers = get_card_vers(regs.version); 425222900Snp revision = (regs.version >> 10) & 0x3f; 426222900Snp 427222900Snp if (vers == 4) { 428222900Snp if (revision == 0x3f) 429222900Snp rc = dump_regs_t4vf(argc, argv, regs.data); 430222900Snp else 431222900Snp rc = dump_regs_t4(argc, argv, regs.data); 432248925Snp } else if (vers == 5) 433248925Snp rc = dump_regs_t5(argc, argv, regs.data); 434248925Snp else { 435248925Snp warnx("%s (type %d, rev %d) is not a known card.", 436222900Snp nexus, vers, revision); 437222900Snp return (ENOTSUP); 438222900Snp } 439222900Snp 440222900Snp free(regs.data); 441222900Snp return (rc); 442222900Snp} 443222900Snp 444222900Snpstatic void 445222900Snpdo_show_info_header(uint32_t mode) 446222900Snp{ 447222900Snp uint32_t i; 448222900Snp 449222900Snp printf ("%4s %8s", "Idx", "Hits"); 450222900Snp for (i = T4_FILTER_FCoE; i <= T4_FILTER_IP_FRAGMENT; i <<= 1) { 451222900Snp switch (mode & i) { 452222900Snp case T4_FILTER_FCoE: 453222900Snp printf (" FCoE"); 454222900Snp break; 455222900Snp 456222900Snp case T4_FILTER_PORT: 457222900Snp printf (" Port"); 458222900Snp break; 459222900Snp 460228561Snp case T4_FILTER_VNIC: 461228561Snp printf (" vld:VNIC"); 462222900Snp break; 463222900Snp 464228561Snp case T4_FILTER_VLAN: 465228561Snp printf (" vld:VLAN"); 466222900Snp break; 467222900Snp 468222900Snp case T4_FILTER_IP_TOS: 469222900Snp printf (" TOS"); 470222900Snp break; 471222900Snp 472222900Snp case T4_FILTER_IP_PROTO: 473222900Snp printf (" Prot"); 474222900Snp break; 475222900Snp 476222900Snp case T4_FILTER_ETH_TYPE: 477222900Snp printf (" EthType"); 478222900Snp break; 479222900Snp 480222900Snp case T4_FILTER_MAC_IDX: 481222900Snp printf (" MACIdx"); 482222900Snp break; 483222900Snp 484222900Snp case T4_FILTER_MPS_HIT_TYPE: 485222900Snp printf (" MPS"); 486222900Snp break; 487222900Snp 488222900Snp case T4_FILTER_IP_FRAGMENT: 489222900Snp printf (" Frag"); 490222900Snp break; 491222900Snp 492222900Snp default: 493222900Snp /* compressed filter field not enabled */ 494222900Snp break; 495222900Snp } 496222900Snp } 497222900Snp printf(" %20s %20s %9s %9s %s\n", 498222900Snp "DIP", "SIP", "DPORT", "SPORT", "Action"); 499222900Snp} 500222900Snp 501222900Snp/* 502222900Snp * Parse an argument sub-vector as a { <parameter name> <value>[:<mask>] } 503222900Snp * ordered tuple. If the parameter name in the argument sub-vector does not 504222900Snp * match the passed in parameter name, then a zero is returned for the 505222900Snp * function and no parsing is performed. If there is a match, then the value 506222900Snp * and optional mask are parsed and returned in the provided return value 507222900Snp * pointers. If no optional mask is specified, then a default mask of all 1s 508222900Snp * will be returned. 509222900Snp * 510222900Snp * An error in parsing the value[:mask] will result in an error message and 511222900Snp * program termination. 512222900Snp */ 513222900Snpstatic int 514222900Snpparse_val_mask(const char *param, const char *args[], uint32_t *val, 515222900Snp uint32_t *mask) 516222900Snp{ 517222900Snp char *p; 518222900Snp 519222900Snp if (strcmp(param, args[0]) != 0) 520222900Snp return (EINVAL); 521222900Snp 522222900Snp *val = strtoul(args[1], &p, 0); 523222900Snp if (p > args[1]) { 524222900Snp if (p[0] == 0) { 525222900Snp *mask = ~0; 526222900Snp return (0); 527222900Snp } 528222900Snp 529222900Snp if (p[0] == ':' && p[1] != 0) { 530222900Snp *mask = strtoul(p+1, &p, 0); 531222900Snp if (p[0] == 0) 532222900Snp return (0); 533222900Snp } 534222900Snp } 535222900Snp 536222900Snp warnx("parameter \"%s\" has bad \"value[:mask]\" %s", 537222900Snp args[0], args[1]); 538222900Snp 539222900Snp return (EINVAL); 540222900Snp} 541222900Snp 542222900Snp/* 543222900Snp * Parse an argument sub-vector as a { <parameter name> <addr>[/<mask>] } 544222900Snp * ordered tuple. If the parameter name in the argument sub-vector does not 545222900Snp * match the passed in parameter name, then a zero is returned for the 546222900Snp * function and no parsing is performed. If there is a match, then the value 547222900Snp * and optional mask are parsed and returned in the provided return value 548222900Snp * pointers. If no optional mask is specified, then a default mask of all 1s 549222900Snp * will be returned. 550222900Snp * 551222900Snp * The value return parameter "afp" is used to specify the expected address 552222900Snp * family -- IPv4 or IPv6 -- of the address[/mask] and return its actual 553222900Snp * format. A passed in value of AF_UNSPEC indicates that either IPv4 or IPv6 554222900Snp * is acceptable; AF_INET means that only IPv4 addresses are acceptable; and 555222900Snp * AF_INET6 means that only IPv6 are acceptable. AF_INET is returned for IPv4 556222900Snp * and AF_INET6 for IPv6 addresses, respectively. IPv4 address/mask pairs are 557222900Snp * returned in the first four bytes of the address and mask return values with 558222900Snp * the address A.B.C.D returned with { A, B, C, D } returned in addresses { 0, 559222900Snp * 1, 2, 3}, respectively. 560222900Snp * 561222900Snp * An error in parsing the value[:mask] will result in an error message and 562222900Snp * program termination. 563222900Snp */ 564222900Snpstatic int 565222900Snpparse_ipaddr(const char *param, const char *args[], int *afp, uint8_t addr[], 566222900Snp uint8_t mask[]) 567222900Snp{ 568222900Snp const char *colon, *afn; 569222900Snp char *slash; 570222900Snp uint8_t *m; 571222900Snp int af, ret; 572222900Snp unsigned int masksize; 573222900Snp 574222900Snp /* 575222900Snp * Is this our parameter? 576222900Snp */ 577222900Snp if (strcmp(param, args[0]) != 0) 578222900Snp return (EINVAL); 579222900Snp 580222900Snp /* 581222900Snp * Fundamental IPv4 versus IPv6 selection. 582222900Snp */ 583222900Snp colon = strchr(args[1], ':'); 584222900Snp if (!colon) { 585222900Snp afn = "IPv4"; 586222900Snp af = AF_INET; 587222900Snp masksize = 32; 588222900Snp } else { 589222900Snp afn = "IPv6"; 590222900Snp af = AF_INET6; 591222900Snp masksize = 128; 592222900Snp } 593222900Snp if (*afp == AF_UNSPEC) 594222900Snp *afp = af; 595222900Snp else if (*afp != af) { 596222900Snp warnx("address %s is not of expected family %s", 597222900Snp args[1], *afp == AF_INET ? "IP" : "IPv6"); 598222900Snp return (EINVAL); 599222900Snp } 600222900Snp 601222900Snp /* 602222900Snp * Parse address (temporarily stripping off any "/mask" 603222900Snp * specification). 604222900Snp */ 605222900Snp slash = strchr(args[1], '/'); 606222900Snp if (slash) 607222900Snp *slash = 0; 608222900Snp ret = inet_pton(af, args[1], addr); 609222900Snp if (slash) 610222900Snp *slash = '/'; 611222900Snp if (ret <= 0) { 612222900Snp warnx("Cannot parse %s %s address %s", param, afn, args[1]); 613222900Snp return (EINVAL); 614222900Snp } 615222900Snp 616222900Snp /* 617222900Snp * Parse optional mask specification. 618222900Snp */ 619222900Snp if (slash) { 620222900Snp char *p; 621222900Snp unsigned int prefix = strtoul(slash + 1, &p, 10); 622222900Snp 623222900Snp if (p == slash + 1) { 624222900Snp warnx("missing address prefix for %s", param); 625222900Snp return (EINVAL); 626222900Snp } 627222900Snp if (*p) { 628222900Snp warnx("%s is not a valid address prefix", slash + 1); 629222900Snp return (EINVAL); 630222900Snp } 631222900Snp if (prefix > masksize) { 632222900Snp warnx("prefix %u is too long for an %s address", 633222900Snp prefix, afn); 634222900Snp return (EINVAL); 635222900Snp } 636222900Snp memset(mask, 0, masksize / 8); 637222900Snp masksize = prefix; 638222900Snp } 639222900Snp 640222900Snp /* 641222900Snp * Fill in mask. 642222900Snp */ 643222900Snp for (m = mask; masksize >= 8; m++, masksize -= 8) 644222900Snp *m = ~0; 645222900Snp if (masksize) 646222900Snp *m = ~0 << (8 - masksize); 647222900Snp 648222900Snp return (0); 649222900Snp} 650222900Snp 651222900Snp/* 652222900Snp * Parse an argument sub-vector as a { <parameter name> <value> } ordered 653222900Snp * tuple. If the parameter name in the argument sub-vector does not match the 654222900Snp * passed in parameter name, then a zero is returned for the function and no 655222900Snp * parsing is performed. If there is a match, then the value is parsed and 656222900Snp * returned in the provided return value pointer. 657222900Snp */ 658222900Snpstatic int 659222900Snpparse_val(const char *param, const char *args[], uint32_t *val) 660222900Snp{ 661222900Snp char *p; 662222900Snp 663222900Snp if (strcmp(param, args[0]) != 0) 664222900Snp return (EINVAL); 665222900Snp 666222900Snp *val = strtoul(args[1], &p, 0); 667222900Snp if (p > args[1] && p[0] == 0) 668222900Snp return (0); 669222900Snp 670222900Snp warnx("parameter \"%s\" has bad \"value\" %s", args[0], args[1]); 671222900Snp return (EINVAL); 672222900Snp} 673222900Snp 674222900Snpstatic void 675222900Snpfilters_show_ipaddr(int type, uint8_t *addr, uint8_t *addrm) 676222900Snp{ 677222900Snp int noctets, octet; 678222900Snp 679222900Snp printf(" "); 680222900Snp if (type == 0) { 681222900Snp noctets = 4; 682222900Snp printf("%3s", " "); 683222900Snp } else 684222900Snp noctets = 16; 685222900Snp 686222900Snp for (octet = 0; octet < noctets; octet++) 687222900Snp printf("%02x", addr[octet]); 688222900Snp printf("/"); 689222900Snp for (octet = 0; octet < noctets; octet++) 690222900Snp printf("%02x", addrm[octet]); 691222900Snp} 692222900Snp 693222900Snpstatic void 694222900Snpdo_show_one_filter_info(struct t4_filter *t, uint32_t mode) 695222900Snp{ 696222900Snp uint32_t i; 697222900Snp 698222900Snp printf("%4d", t->idx); 699222900Snp if (t->hits == UINT64_MAX) 700222900Snp printf(" %8s", "-"); 701222900Snp else 702222900Snp printf(" %8ju", t->hits); 703222900Snp 704222900Snp /* 705222900Snp * Compressed header portion of filter. 706222900Snp */ 707222900Snp for (i = T4_FILTER_FCoE; i <= T4_FILTER_IP_FRAGMENT; i <<= 1) { 708222900Snp switch (mode & i) { 709222900Snp case T4_FILTER_FCoE: 710222900Snp printf(" %1d/%1d", t->fs.val.fcoe, t->fs.mask.fcoe); 711222900Snp break; 712222900Snp 713222900Snp case T4_FILTER_PORT: 714222900Snp printf(" %1d/%1d", t->fs.val.iport, t->fs.mask.iport); 715222900Snp break; 716222900Snp 717228561Snp case T4_FILTER_VNIC: 718222900Snp printf(" %1d:%1x:%02x/%1d:%1x:%02x", 719228561Snp t->fs.val.vnic_vld, (t->fs.val.vnic >> 7) & 0x7, 720228561Snp t->fs.val.vnic & 0x7f, t->fs.mask.vnic_vld, 721228561Snp (t->fs.mask.vnic >> 7) & 0x7, 722228561Snp t->fs.mask.vnic & 0x7f); 723222900Snp break; 724222900Snp 725228561Snp case T4_FILTER_VLAN: 726222900Snp printf(" %1d:%04x/%1d:%04x", 727228561Snp t->fs.val.vlan_vld, t->fs.val.vlan, 728228561Snp t->fs.mask.vlan_vld, t->fs.mask.vlan); 729222900Snp break; 730222900Snp 731222900Snp case T4_FILTER_IP_TOS: 732222900Snp printf(" %02x/%02x", t->fs.val.tos, t->fs.mask.tos); 733222900Snp break; 734222900Snp 735222900Snp case T4_FILTER_IP_PROTO: 736222900Snp printf(" %02x/%02x", t->fs.val.proto, t->fs.mask.proto); 737222900Snp break; 738222900Snp 739222900Snp case T4_FILTER_ETH_TYPE: 740222900Snp printf(" %04x/%04x", t->fs.val.ethtype, 741222900Snp t->fs.mask.ethtype); 742222900Snp break; 743222900Snp 744222900Snp case T4_FILTER_MAC_IDX: 745222900Snp printf(" %03x/%03x", t->fs.val.macidx, 746222900Snp t->fs.mask.macidx); 747222900Snp break; 748222900Snp 749222900Snp case T4_FILTER_MPS_HIT_TYPE: 750222900Snp printf(" %1x/%1x", t->fs.val.matchtype, 751222900Snp t->fs.mask.matchtype); 752222900Snp break; 753222900Snp 754222900Snp case T4_FILTER_IP_FRAGMENT: 755222900Snp printf(" %1d/%1d", t->fs.val.frag, t->fs.mask.frag); 756222900Snp break; 757222900Snp 758222900Snp default: 759222900Snp /* compressed filter field not enabled */ 760222900Snp break; 761222900Snp } 762222900Snp } 763222900Snp 764222900Snp /* 765222900Snp * Fixed portion of filter. 766222900Snp */ 767222900Snp filters_show_ipaddr(t->fs.type, t->fs.val.dip, t->fs.mask.dip); 768222900Snp filters_show_ipaddr(t->fs.type, t->fs.val.sip, t->fs.mask.sip); 769222900Snp printf(" %04x/%04x %04x/%04x", 770222900Snp t->fs.val.dport, t->fs.mask.dport, 771222900Snp t->fs.val.sport, t->fs.mask.sport); 772222900Snp 773222900Snp /* 774222900Snp * Variable length filter action. 775222900Snp */ 776222900Snp if (t->fs.action == FILTER_DROP) 777222900Snp printf(" Drop"); 778222900Snp else if (t->fs.action == FILTER_SWITCH) { 779222900Snp printf(" Switch: port=%d", t->fs.eport); 780222900Snp if (t->fs.newdmac) 781222900Snp printf( 782222900Snp ", dmac=%02x:%02x:%02x:%02x:%02x:%02x " 783222900Snp ", l2tidx=%d", 784222900Snp t->fs.dmac[0], t->fs.dmac[1], 785222900Snp t->fs.dmac[2], t->fs.dmac[3], 786222900Snp t->fs.dmac[4], t->fs.dmac[5], 787222900Snp t->l2tidx); 788222900Snp if (t->fs.newsmac) 789222900Snp printf( 790222900Snp ", smac=%02x:%02x:%02x:%02x:%02x:%02x " 791222900Snp ", smtidx=%d", 792222900Snp t->fs.smac[0], t->fs.smac[1], 793222900Snp t->fs.smac[2], t->fs.smac[3], 794222900Snp t->fs.smac[4], t->fs.smac[5], 795222900Snp t->smtidx); 796222900Snp if (t->fs.newvlan == VLAN_REMOVE) 797222900Snp printf(", vlan=none"); 798222900Snp else if (t->fs.newvlan == VLAN_INSERT) 799222900Snp printf(", vlan=insert(%x)", t->fs.vlan); 800222900Snp else if (t->fs.newvlan == VLAN_REWRITE) 801222900Snp printf(", vlan=rewrite(%x)", t->fs.vlan); 802222900Snp } else { 803222900Snp printf(" Pass: Q="); 804222900Snp if (t->fs.dirsteer == 0) { 805222900Snp printf("RSS"); 806222900Snp if (t->fs.maskhash) 807222900Snp printf("(TCB=hash)"); 808222900Snp } else { 809222900Snp printf("%d", t->fs.iq); 810222900Snp if (t->fs.dirsteerhash == 0) 811222900Snp printf("(QID)"); 812222900Snp else 813222900Snp printf("(hash)"); 814222900Snp } 815222900Snp } 816222900Snp if (t->fs.prio) 817222900Snp printf(" Prio"); 818222900Snp if (t->fs.rpttid) 819222900Snp printf(" RptTID"); 820222900Snp printf("\n"); 821222900Snp} 822222900Snp 823222900Snpstatic int 824222900Snpshow_filters(void) 825222900Snp{ 826222900Snp uint32_t mode = 0, header = 0; 827222900Snp struct t4_filter t; 828222900Snp int rc; 829222900Snp 830222900Snp /* Get the global filter mode first */ 831222900Snp rc = doit(CHELSIO_T4_GET_FILTER_MODE, &mode); 832222900Snp if (rc != 0) 833222900Snp return (rc); 834222900Snp 835222900Snp t.idx = 0; 836222900Snp for (t.idx = 0; ; t.idx++) { 837222900Snp rc = doit(CHELSIO_T4_GET_FILTER, &t); 838222900Snp if (rc != 0 || t.idx == 0xffffffff) 839222900Snp break; 840222900Snp 841222900Snp if (!header) { 842222900Snp do_show_info_header(mode); 843222900Snp header = 1; 844222900Snp } 845222900Snp do_show_one_filter_info(&t, mode); 846222900Snp }; 847222900Snp 848222900Snp return (rc); 849222900Snp} 850222900Snp 851222900Snpstatic int 852222900Snpget_filter_mode(void) 853222900Snp{ 854222900Snp uint32_t mode = 0; 855222900Snp int rc; 856222900Snp 857222900Snp rc = doit(CHELSIO_T4_GET_FILTER_MODE, &mode); 858222900Snp if (rc != 0) 859222900Snp return (rc); 860222900Snp 861222900Snp if (mode & T4_FILTER_IPv4) 862222900Snp printf("ipv4 "); 863222900Snp 864222900Snp if (mode & T4_FILTER_IPv6) 865222900Snp printf("ipv6 "); 866222900Snp 867222900Snp if (mode & T4_FILTER_IP_SADDR) 868222900Snp printf("sip "); 869222900Snp 870222900Snp if (mode & T4_FILTER_IP_DADDR) 871222900Snp printf("dip "); 872222900Snp 873222900Snp if (mode & T4_FILTER_IP_SPORT) 874222900Snp printf("sport "); 875222900Snp 876222900Snp if (mode & T4_FILTER_IP_DPORT) 877222900Snp printf("dport "); 878222900Snp 879249368Snp if (mode & T4_FILTER_IP_FRAGMENT) 880249368Snp printf("frag "); 881249368Snp 882222900Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 883222900Snp printf("matchtype "); 884222900Snp 885222900Snp if (mode & T4_FILTER_MAC_IDX) 886222900Snp printf("macidx "); 887222900Snp 888222900Snp if (mode & T4_FILTER_ETH_TYPE) 889222900Snp printf("ethtype "); 890222900Snp 891222900Snp if (mode & T4_FILTER_IP_PROTO) 892222900Snp printf("proto "); 893222900Snp 894222900Snp if (mode & T4_FILTER_IP_TOS) 895222900Snp printf("tos "); 896222900Snp 897228561Snp if (mode & T4_FILTER_VLAN) 898228561Snp printf("vlan "); 899222900Snp 900228561Snp if (mode & T4_FILTER_VNIC) 901249368Snp printf("vnic/ovlan "); 902222900Snp 903222900Snp if (mode & T4_FILTER_PORT) 904222900Snp printf("iport "); 905222900Snp 906222900Snp if (mode & T4_FILTER_FCoE) 907222900Snp printf("fcoe "); 908222900Snp 909222900Snp printf("\n"); 910222900Snp 911222900Snp return (0); 912222900Snp} 913222900Snp 914222900Snpstatic int 915222900Snpset_filter_mode(int argc, const char *argv[]) 916222900Snp{ 917222900Snp uint32_t mode = 0; 918222900Snp 919222900Snp for (; argc; argc--, argv++) { 920249368Snp if (!strcmp(argv[0], "frag")) 921249368Snp mode |= T4_FILTER_IP_FRAGMENT; 922249368Snp 923222900Snp if (!strcmp(argv[0], "matchtype")) 924222900Snp mode |= T4_FILTER_MPS_HIT_TYPE; 925222900Snp 926222900Snp if (!strcmp(argv[0], "macidx")) 927222900Snp mode |= T4_FILTER_MAC_IDX; 928222900Snp 929222900Snp if (!strcmp(argv[0], "ethtype")) 930222900Snp mode |= T4_FILTER_ETH_TYPE; 931222900Snp 932222900Snp if (!strcmp(argv[0], "proto")) 933222900Snp mode |= T4_FILTER_IP_PROTO; 934222900Snp 935222900Snp if (!strcmp(argv[0], "tos")) 936222900Snp mode |= T4_FILTER_IP_TOS; 937222900Snp 938228561Snp if (!strcmp(argv[0], "vlan")) 939228561Snp mode |= T4_FILTER_VLAN; 940222900Snp 941228561Snp if (!strcmp(argv[0], "ovlan") || 942228561Snp !strcmp(argv[0], "vnic")) 943228561Snp mode |= T4_FILTER_VNIC; 944222900Snp 945222900Snp if (!strcmp(argv[0], "iport")) 946222900Snp mode |= T4_FILTER_PORT; 947222900Snp 948222900Snp if (!strcmp(argv[0], "fcoe")) 949222900Snp mode |= T4_FILTER_FCoE; 950222900Snp } 951222900Snp 952222900Snp return doit(CHELSIO_T4_SET_FILTER_MODE, &mode); 953222900Snp} 954222900Snp 955222900Snpstatic int 956222900Snpdel_filter(uint32_t idx) 957222900Snp{ 958222900Snp struct t4_filter t; 959222900Snp 960222900Snp t.idx = idx; 961222900Snp 962222900Snp return doit(CHELSIO_T4_DEL_FILTER, &t); 963222900Snp} 964222900Snp 965222900Snpstatic int 966222900Snpset_filter(uint32_t idx, int argc, const char *argv[]) 967222900Snp{ 968222900Snp int af = AF_UNSPEC, start_arg = 0; 969222900Snp struct t4_filter t; 970222900Snp 971222900Snp if (argc < 2) { 972222900Snp warnc(EINVAL, "%s", __func__); 973222900Snp return (EINVAL); 974222900Snp }; 975222900Snp bzero(&t, sizeof (t)); 976222900Snp t.idx = idx; 977252470Snp t.fs.hitcnts = 1; 978222900Snp 979222900Snp for (start_arg = 0; start_arg + 2 <= argc; start_arg += 2) { 980222900Snp const char **args = &argv[start_arg]; 981222900Snp uint32_t val, mask; 982222900Snp 983222900Snp if (!strcmp(argv[start_arg], "type")) { 984222900Snp int newaf; 985222900Snp if (!strcasecmp(argv[start_arg + 1], "ipv4")) 986222900Snp newaf = AF_INET; 987222900Snp else if (!strcasecmp(argv[start_arg + 1], "ipv6")) 988222900Snp newaf = AF_INET6; 989222900Snp else { 990222900Snp warnx("invalid type \"%s\"; " 991222900Snp "must be one of \"ipv4\" or \"ipv6\"", 992222900Snp argv[start_arg + 1]); 993222900Snp return (EINVAL); 994222900Snp } 995222900Snp 996222900Snp if (af != AF_UNSPEC && af != newaf) { 997222900Snp warnx("conflicting IPv4/IPv6 specifications."); 998222900Snp return (EINVAL); 999222900Snp } 1000222900Snp af = newaf; 1001222900Snp } else if (!parse_val_mask("fcoe", args, &val, &mask)) { 1002222900Snp t.fs.val.fcoe = val; 1003222900Snp t.fs.mask.fcoe = mask; 1004222900Snp } else if (!parse_val_mask("iport", args, &val, &mask)) { 1005222900Snp t.fs.val.iport = val; 1006222900Snp t.fs.mask.iport = mask; 1007222900Snp } else if (!parse_val_mask("ovlan", args, &val, &mask)) { 1008228561Snp t.fs.val.vnic = val; 1009228561Snp t.fs.mask.vnic = mask; 1010228561Snp t.fs.val.vnic_vld = 1; 1011228561Snp t.fs.mask.vnic_vld = 1; 1012228561Snp } else if (!parse_val_mask("vnic", args, &val, &mask)) { 1013228561Snp t.fs.val.vnic = val; 1014228561Snp t.fs.mask.vnic = mask; 1015228561Snp t.fs.val.vnic_vld = 1; 1016228561Snp t.fs.mask.vnic_vld = 1; 1017245520Snp } else if (!parse_val_mask("ivlan", args, &val, &mask)) { 1018228561Snp t.fs.val.vlan = val; 1019228561Snp t.fs.mask.vlan = mask; 1020228561Snp t.fs.val.vlan_vld = 1; 1021228561Snp t.fs.mask.vlan_vld = 1; 1022222900Snp } else if (!parse_val_mask("tos", args, &val, &mask)) { 1023222900Snp t.fs.val.tos = val; 1024222900Snp t.fs.mask.tos = mask; 1025222900Snp } else if (!parse_val_mask("proto", args, &val, &mask)) { 1026222900Snp t.fs.val.proto = val; 1027222900Snp t.fs.mask.proto = mask; 1028222900Snp } else if (!parse_val_mask("ethtype", args, &val, &mask)) { 1029222900Snp t.fs.val.ethtype = val; 1030222900Snp t.fs.mask.ethtype = mask; 1031222900Snp } else if (!parse_val_mask("macidx", args, &val, &mask)) { 1032222900Snp t.fs.val.macidx = val; 1033222900Snp t.fs.mask.macidx = mask; 1034222900Snp } else if (!parse_val_mask("matchtype", args, &val, &mask)) { 1035222900Snp t.fs.val.matchtype = val; 1036222900Snp t.fs.mask.matchtype = mask; 1037222900Snp } else if (!parse_val_mask("frag", args, &val, &mask)) { 1038222900Snp t.fs.val.frag = val; 1039222900Snp t.fs.mask.frag = mask; 1040222900Snp } else if (!parse_val_mask("dport", args, &val, &mask)) { 1041222900Snp t.fs.val.dport = val; 1042222900Snp t.fs.mask.dport = mask; 1043222900Snp } else if (!parse_val_mask("sport", args, &val, &mask)) { 1044222900Snp t.fs.val.sport = val; 1045222900Snp t.fs.mask.sport = mask; 1046222900Snp } else if (!parse_ipaddr("dip", args, &af, t.fs.val.dip, 1047222900Snp t.fs.mask.dip)) { 1048222900Snp /* nada */; 1049222900Snp } else if (!parse_ipaddr("sip", args, &af, t.fs.val.sip, 1050222900Snp t.fs.mask.sip)) { 1051222900Snp /* nada */; 1052222900Snp } else if (!strcmp(argv[start_arg], "action")) { 1053222900Snp if (!strcmp(argv[start_arg + 1], "pass")) 1054222900Snp t.fs.action = FILTER_PASS; 1055222900Snp else if (!strcmp(argv[start_arg + 1], "drop")) 1056222900Snp t.fs.action = FILTER_DROP; 1057222900Snp else if (!strcmp(argv[start_arg + 1], "switch")) 1058222900Snp t.fs.action = FILTER_SWITCH; 1059222900Snp else { 1060222900Snp warnx("invalid action \"%s\"; must be one of" 1061222900Snp " \"pass\", \"drop\" or \"switch\"", 1062222900Snp argv[start_arg + 1]); 1063222900Snp return (EINVAL); 1064222900Snp } 1065222900Snp } else if (!parse_val("hitcnts", args, &val)) { 1066222900Snp t.fs.hitcnts = val; 1067222900Snp } else if (!parse_val("prio", args, &val)) { 1068222900Snp t.fs.prio = val; 1069222900Snp } else if (!parse_val("rpttid", args, &val)) { 1070222900Snp t.fs.rpttid = 1; 1071222900Snp } else if (!parse_val("queue", args, &val)) { 1072222900Snp t.fs.dirsteer = 1; 1073222900Snp t.fs.iq = val; 1074222900Snp } else if (!parse_val("tcbhash", args, &val)) { 1075222900Snp t.fs.maskhash = 1; 1076222900Snp t.fs.dirsteerhash = 1; 1077222900Snp } else if (!parse_val("eport", args, &val)) { 1078222900Snp t.fs.eport = val; 1079222900Snp } else if (!strcmp(argv[start_arg], "dmac")) { 1080222900Snp struct ether_addr *daddr; 1081222900Snp 1082222900Snp daddr = ether_aton(argv[start_arg + 1]); 1083222900Snp if (daddr == NULL) { 1084222900Snp warnx("invalid dmac address \"%s\"", 1085222900Snp argv[start_arg + 1]); 1086222900Snp return (EINVAL); 1087222900Snp } 1088222900Snp memcpy(t.fs.dmac, daddr, ETHER_ADDR_LEN); 1089222900Snp t.fs.newdmac = 1; 1090222900Snp } else if (!strcmp(argv[start_arg], "smac")) { 1091222900Snp struct ether_addr *saddr; 1092222900Snp 1093222900Snp saddr = ether_aton(argv[start_arg + 1]); 1094222900Snp if (saddr == NULL) { 1095222900Snp warnx("invalid smac address \"%s\"", 1096222900Snp argv[start_arg + 1]); 1097222900Snp return (EINVAL); 1098222900Snp } 1099222900Snp memcpy(t.fs.smac, saddr, ETHER_ADDR_LEN); 1100222900Snp t.fs.newsmac = 1; 1101222900Snp } else if (!strcmp(argv[start_arg], "vlan")) { 1102222900Snp char *p; 1103222900Snp if (!strcmp(argv[start_arg + 1], "none")) { 1104222900Snp t.fs.newvlan = VLAN_REMOVE; 1105222900Snp } else if (argv[start_arg + 1][0] == '=') { 1106222900Snp t.fs.newvlan = VLAN_REWRITE; 1107222900Snp } else if (argv[start_arg + 1][0] == '+') { 1108222900Snp t.fs.newvlan = VLAN_INSERT; 1109245520Snp } else if (isdigit(argv[start_arg + 1][0]) && 1110245520Snp !parse_val_mask("vlan", args, &val, &mask)) { 1111245520Snp t.fs.val.vlan = val; 1112245520Snp t.fs.mask.vlan = mask; 1113245520Snp t.fs.val.vlan_vld = 1; 1114245520Snp t.fs.mask.vlan_vld = 1; 1115222900Snp } else { 1116222900Snp warnx("unknown vlan parameter \"%s\"; must" 1117245520Snp " be one of \"none\", \"=<vlan>\", " 1118245520Snp " \"+<vlan>\", or \"<vlan>\"", 1119245520Snp argv[start_arg + 1]); 1120222900Snp return (EINVAL); 1121222900Snp } 1122222900Snp if (t.fs.newvlan == VLAN_REWRITE || 1123222900Snp t.fs.newvlan == VLAN_INSERT) { 1124222900Snp t.fs.vlan = strtoul(argv[start_arg + 1] + 1, 1125222900Snp &p, 0); 1126222900Snp if (p == argv[start_arg + 1] + 1 || p[0] != 0) { 1127222900Snp warnx("invalid vlan \"%s\"", 1128222900Snp argv[start_arg + 1]); 1129222900Snp return (EINVAL); 1130222900Snp } 1131222900Snp } 1132222900Snp } else { 1133222900Snp warnx("invalid parameter \"%s\"", argv[start_arg]); 1134222900Snp return (EINVAL); 1135222900Snp } 1136222900Snp } 1137222900Snp if (start_arg != argc) { 1138222900Snp warnx("no value for \"%s\"", argv[start_arg]); 1139222900Snp return (EINVAL); 1140222900Snp } 1141222900Snp 1142222900Snp /* 1143222900Snp * Check basic sanity of option combinations. 1144222900Snp */ 1145222900Snp if (t.fs.action != FILTER_SWITCH && 1146222900Snp (t.fs.eport || t.fs.newdmac || t.fs.newsmac || t.fs.newvlan)) { 1147222900Snp warnx("prio, port dmac, smac and vlan only make sense with" 1148222900Snp " \"action switch\""); 1149222900Snp return (EINVAL); 1150222900Snp } 1151222900Snp if (t.fs.action != FILTER_PASS && 1152222900Snp (t.fs.rpttid || t.fs.dirsteer || t.fs.maskhash)) { 1153222900Snp warnx("rpttid, queue and tcbhash don't make sense with" 1154222900Snp " action \"drop\" or \"switch\""); 1155222900Snp return (EINVAL); 1156222900Snp } 1157222900Snp 1158222900Snp t.fs.type = (af == AF_INET6 ? 1 : 0); /* default IPv4 */ 1159222900Snp return doit(CHELSIO_T4_SET_FILTER, &t); 1160222900Snp} 1161222900Snp 1162222900Snpstatic int 1163222900Snpfilter_cmd(int argc, const char *argv[]) 1164222900Snp{ 1165222900Snp long long val; 1166222900Snp uint32_t idx; 1167222900Snp char *s; 1168222900Snp 1169222900Snp if (argc == 0) { 1170222900Snp warnx("filter: no arguments."); 1171222900Snp return (EINVAL); 1172222900Snp }; 1173222900Snp 1174222900Snp /* list */ 1175222900Snp if (strcmp(argv[0], "list") == 0) { 1176222900Snp if (argc != 1) 1177222900Snp warnx("trailing arguments after \"list\" ignored."); 1178222900Snp 1179222900Snp return show_filters(); 1180222900Snp } 1181222900Snp 1182222900Snp /* mode */ 1183222900Snp if (argc == 1 && strcmp(argv[0], "mode") == 0) 1184222900Snp return get_filter_mode(); 1185222900Snp 1186222900Snp /* mode <mode> */ 1187222900Snp if (strcmp(argv[0], "mode") == 0) 1188222900Snp return set_filter_mode(argc - 1, argv + 1); 1189222900Snp 1190222900Snp /* <idx> ... */ 1191222900Snp s = str_to_number(argv[0], NULL, &val); 1192222900Snp if (*s || val > 0xffffffffU) { 1193222900Snp warnx("\"%s\" is neither an index nor a filter subcommand.", 1194222900Snp argv[0]); 1195222900Snp return (EINVAL); 1196222900Snp } 1197222900Snp idx = (uint32_t) val; 1198222900Snp 1199222900Snp /* <idx> delete|clear */ 1200222900Snp if (argc == 2 && 1201222900Snp (strcmp(argv[1], "delete") == 0 || strcmp(argv[1], "clear") == 0)) { 1202222900Snp return del_filter(idx); 1203222900Snp } 1204222900Snp 1205222900Snp /* <idx> [<param> <val>] ... */ 1206222900Snp return set_filter(idx, argc - 1, argv + 1); 1207222900Snp} 1208222900Snp 1209222974Snp/* 1210222974Snp * Shows the fields of a multi-word structure. The structure is considered to 1211222974Snp * consist of @nwords 32-bit words (i.e, it's an (@nwords * 32)-bit structure) 1212222974Snp * whose fields are described by @fd. The 32-bit words are given in @words 1213222974Snp * starting with the least significant 32-bit word. 1214222974Snp */ 1215222974Snpstatic void 1216222974Snpshow_struct(const uint32_t *words, int nwords, const struct field_desc *fd) 1217222974Snp{ 1218222974Snp unsigned int w = 0; 1219222974Snp const struct field_desc *p; 1220222974Snp 1221222974Snp for (p = fd; p->name; p++) 1222222974Snp w = max(w, strlen(p->name)); 1223222974Snp 1224222974Snp while (fd->name) { 1225222974Snp unsigned long long data; 1226222974Snp int first_word = fd->start / 32; 1227222974Snp int shift = fd->start % 32; 1228222974Snp int width = fd->end - fd->start + 1; 1229222974Snp unsigned long long mask = (1ULL << width) - 1; 1230222974Snp 1231222974Snp data = (words[first_word] >> shift) | 1232222974Snp ((uint64_t)words[first_word + 1] << (32 - shift)); 1233222974Snp if (shift) 1234222974Snp data |= ((uint64_t)words[first_word + 2] << (64 - shift)); 1235222974Snp data &= mask; 1236222974Snp if (fd->islog2) 1237222974Snp data = 1 << data; 1238222974Snp printf("%-*s ", w, fd->name); 1239222974Snp printf(fd->hex ? "%#llx\n" : "%llu\n", data << fd->shift); 1240222974Snp fd++; 1241222974Snp } 1242222974Snp} 1243222974Snp 1244222974Snp#define FIELD(name, start, end) { name, start, end, 0, 0, 0 } 1245222974Snp#define FIELD1(name, start) FIELD(name, start, start) 1246222974Snp 1247222974Snpstatic void 1248284984Snpshow_t5_ctxt(const struct t4_sge_context *p) 1249222974Snp{ 1250284984Snp static struct field_desc egress_t5[] = { 1251284984Snp FIELD("DCA_ST:", 181, 191), 1252222974Snp FIELD1("StatusPgNS:", 180), 1253222974Snp FIELD1("StatusPgRO:", 179), 1254222974Snp FIELD1("FetchNS:", 178), 1255222974Snp FIELD1("FetchRO:", 177), 1256222974Snp FIELD1("Valid:", 176), 1257222974Snp FIELD("PCIeDataChannel:", 174, 175), 1258284984Snp FIELD1("StatusPgTPHintEn:", 173), 1259284984Snp FIELD("StatusPgTPHint:", 171, 172), 1260284984Snp FIELD1("FetchTPHintEn:", 170), 1261284984Snp FIELD("FetchTPHint:", 168, 169), 1262284984Snp FIELD1("FCThreshOverride:", 167), 1263284984Snp { "WRLength:", 162, 166, 9, 0, 1 }, 1264284984Snp FIELD1("WRLengthKnown:", 161), 1265284984Snp FIELD1("ReschedulePending:", 160), 1266284984Snp FIELD1("OnChipQueue:", 159), 1267284984Snp FIELD1("FetchSizeMode:", 158), 1268284984Snp { "FetchBurstMin:", 156, 157, 4, 0, 1 }, 1269284984Snp FIELD1("FLMPacking:", 155), 1270284984Snp FIELD("FetchBurstMax:", 153, 154), 1271284984Snp FIELD("uPToken:", 133, 152), 1272284984Snp FIELD1("uPTokenEn:", 132), 1273284984Snp FIELD1("UserModeIO:", 131), 1274284984Snp FIELD("uPFLCredits:", 123, 130), 1275284984Snp FIELD1("uPFLCreditEn:", 122), 1276284984Snp FIELD("FID:", 111, 121), 1277284984Snp FIELD("HostFCMode:", 109, 110), 1278284984Snp FIELD1("HostFCOwner:", 108), 1279284984Snp { "CIDXFlushThresh:", 105, 107, 0, 0, 1 }, 1280284984Snp FIELD("CIDX:", 89, 104), 1281284984Snp FIELD("PIDX:", 73, 88), 1282284984Snp { "BaseAddress:", 18, 72, 9, 1 }, 1283284984Snp FIELD("QueueSize:", 2, 17), 1284284984Snp FIELD1("QueueType:", 1), 1285284984Snp FIELD1("CachePriority:", 0), 1286284984Snp { NULL } 1287284984Snp }; 1288284984Snp static struct field_desc fl_t5[] = { 1289284984Snp FIELD("DCA_ST:", 181, 191), 1290284984Snp FIELD1("StatusPgNS:", 180), 1291284984Snp FIELD1("StatusPgRO:", 179), 1292284984Snp FIELD1("FetchNS:", 178), 1293284984Snp FIELD1("FetchRO:", 177), 1294284984Snp FIELD1("Valid:", 176), 1295284984Snp FIELD("PCIeDataChannel:", 174, 175), 1296284984Snp FIELD1("StatusPgTPHintEn:", 173), 1297284984Snp FIELD("StatusPgTPHint:", 171, 172), 1298284984Snp FIELD1("FetchTPHintEn:", 170), 1299284984Snp FIELD("FetchTPHint:", 168, 169), 1300284984Snp FIELD1("FCThreshOverride:", 167), 1301284984Snp FIELD1("ReschedulePending:", 160), 1302284984Snp FIELD1("OnChipQueue:", 159), 1303284984Snp FIELD1("FetchSizeMode:", 158), 1304284984Snp { "FetchBurstMin:", 156, 157, 4, 0, 1 }, 1305284984Snp FIELD1("FLMPacking:", 155), 1306284984Snp FIELD("FetchBurstMax:", 153, 154), 1307284984Snp FIELD1("FLMcongMode:", 152), 1308284984Snp FIELD("MaxuPFLCredits:", 144, 151), 1309284984Snp FIELD("FLMcontextID:", 133, 143), 1310284984Snp FIELD1("uPTokenEn:", 132), 1311284984Snp FIELD1("UserModeIO:", 131), 1312284984Snp FIELD("uPFLCredits:", 123, 130), 1313284984Snp FIELD1("uPFLCreditEn:", 122), 1314284984Snp FIELD("FID:", 111, 121), 1315284984Snp FIELD("HostFCMode:", 109, 110), 1316284984Snp FIELD1("HostFCOwner:", 108), 1317284984Snp { "CIDXFlushThresh:", 105, 107, 0, 0, 1 }, 1318284984Snp FIELD("CIDX:", 89, 104), 1319284984Snp FIELD("PIDX:", 73, 88), 1320284984Snp { "BaseAddress:", 18, 72, 9, 1 }, 1321284984Snp FIELD("QueueSize:", 2, 17), 1322284984Snp FIELD1("QueueType:", 1), 1323284984Snp FIELD1("CachePriority:", 0), 1324284984Snp { NULL } 1325284984Snp }; 1326284984Snp static struct field_desc ingress_t5[] = { 1327284984Snp FIELD("DCA_ST:", 143, 153), 1328284984Snp FIELD1("ISCSICoalescing:", 142), 1329284984Snp FIELD1("Queue_Valid:", 141), 1330284984Snp FIELD1("TimerPending:", 140), 1331284984Snp FIELD1("DropRSS:", 139), 1332284984Snp FIELD("PCIeChannel:", 137, 138), 1333284984Snp FIELD1("SEInterruptArmed:", 136), 1334284984Snp FIELD1("CongestionMgtEnable:", 135), 1335284984Snp FIELD1("NoSnoop:", 134), 1336284984Snp FIELD1("RelaxedOrdering:", 133), 1337284984Snp FIELD1("GTSmode:", 132), 1338284984Snp FIELD1("TPHintEn:", 131), 1339284984Snp FIELD("TPHint:", 129, 130), 1340284984Snp FIELD1("UpdateScheduling:", 128), 1341284984Snp FIELD("UpdateDelivery:", 126, 127), 1342284984Snp FIELD1("InterruptSent:", 125), 1343284984Snp FIELD("InterruptIDX:", 114, 124), 1344284984Snp FIELD1("InterruptDestination:", 113), 1345284984Snp FIELD1("InterruptArmed:", 112), 1346284984Snp FIELD("RxIntCounter:", 106, 111), 1347284984Snp FIELD("RxIntCounterThreshold:", 104, 105), 1348284984Snp FIELD1("Generation:", 103), 1349284984Snp { "BaseAddress:", 48, 102, 9, 1 }, 1350284984Snp FIELD("PIDX:", 32, 47), 1351284984Snp FIELD("CIDX:", 16, 31), 1352284984Snp { "QueueSize:", 4, 15, 4, 0 }, 1353284984Snp { "QueueEntrySize:", 2, 3, 4, 0, 1 }, 1354284984Snp FIELD1("QueueEntryOverride:", 1), 1355284984Snp FIELD1("CachePriority:", 0), 1356284984Snp { NULL } 1357284984Snp }; 1358284984Snp static struct field_desc flm_t5[] = { 1359284984Snp FIELD1("Valid:", 89), 1360284984Snp FIELD("SplitLenMode:", 87, 88), 1361284984Snp FIELD1("TPHintEn:", 86), 1362284984Snp FIELD("TPHint:", 84, 85), 1363284984Snp FIELD1("NoSnoop:", 83), 1364284984Snp FIELD1("RelaxedOrdering:", 82), 1365284984Snp FIELD("DCA_ST:", 71, 81), 1366284984Snp FIELD("EQid:", 54, 70), 1367284984Snp FIELD("SplitEn:", 52, 53), 1368284984Snp FIELD1("PadEn:", 51), 1369284984Snp FIELD1("PackEn:", 50), 1370284984Snp FIELD1("Cache_Lock :", 49), 1371284984Snp FIELD1("CongDrop:", 48), 1372284984Snp FIELD("PackOffset:", 16, 47), 1373284984Snp FIELD("CIDX:", 8, 15), 1374284984Snp FIELD("PIDX:", 0, 7), 1375284984Snp { NULL } 1376284984Snp }; 1377284984Snp static struct field_desc conm_t5[] = { 1378284984Snp FIELD1("CngMPSEnable:", 21), 1379284984Snp FIELD("CngTPMode:", 19, 20), 1380284984Snp FIELD1("CngDBPHdr:", 18), 1381284984Snp FIELD1("CngDBPData:", 17), 1382284984Snp FIELD1("CngIMSG:", 16), 1383284984Snp { "CngChMap:", 0, 15, 0, 1, 0 }, 1384284984Snp { NULL } 1385284984Snp }; 1386284984Snp 1387284984Snp if (p->mem_id == SGE_CONTEXT_EGRESS) 1388284984Snp show_struct(p->data, 6, (p->data[0] & 2) ? fl_t5 : egress_t5); 1389284984Snp else if (p->mem_id == SGE_CONTEXT_FLM) 1390284984Snp show_struct(p->data, 3, flm_t5); 1391284984Snp else if (p->mem_id == SGE_CONTEXT_INGRESS) 1392284984Snp show_struct(p->data, 5, ingress_t5); 1393284984Snp else if (p->mem_id == SGE_CONTEXT_CNM) 1394284984Snp show_struct(p->data, 1, conm_t5); 1395284984Snp} 1396284984Snp 1397284984Snpstatic void 1398284984Snpshow_t4_ctxt(const struct t4_sge_context *p) 1399284984Snp{ 1400284984Snp static struct field_desc egress_t4[] = { 1401284984Snp FIELD1("StatusPgNS:", 180), 1402284984Snp FIELD1("StatusPgRO:", 179), 1403284984Snp FIELD1("FetchNS:", 178), 1404284984Snp FIELD1("FetchRO:", 177), 1405284984Snp FIELD1("Valid:", 176), 1406284984Snp FIELD("PCIeDataChannel:", 174, 175), 1407222974Snp FIELD1("DCAEgrQEn:", 173), 1408222974Snp FIELD("DCACPUID:", 168, 172), 1409222974Snp FIELD1("FCThreshOverride:", 167), 1410222974Snp FIELD("WRLength:", 162, 166), 1411222974Snp FIELD1("WRLengthKnown:", 161), 1412222974Snp FIELD1("ReschedulePending:", 160), 1413222974Snp FIELD1("OnChipQueue:", 159), 1414222974Snp FIELD1("FetchSizeMode", 158), 1415222974Snp { "FetchBurstMin:", 156, 157, 4, 0, 1 }, 1416222974Snp { "FetchBurstMax:", 153, 154, 6, 0, 1 }, 1417222974Snp FIELD("uPToken:", 133, 152), 1418222974Snp FIELD1("uPTokenEn:", 132), 1419222974Snp FIELD1("UserModeIO:", 131), 1420222974Snp FIELD("uPFLCredits:", 123, 130), 1421222974Snp FIELD1("uPFLCreditEn:", 122), 1422222974Snp FIELD("FID:", 111, 121), 1423222974Snp FIELD("HostFCMode:", 109, 110), 1424222974Snp FIELD1("HostFCOwner:", 108), 1425222974Snp { "CIDXFlushThresh:", 105, 107, 0, 0, 1 }, 1426222974Snp FIELD("CIDX:", 89, 104), 1427222974Snp FIELD("PIDX:", 73, 88), 1428222974Snp { "BaseAddress:", 18, 72, 9, 1 }, 1429222974Snp FIELD("QueueSize:", 2, 17), 1430222974Snp FIELD1("QueueType:", 1), 1431222974Snp FIELD1("CachePriority:", 0), 1432222974Snp { NULL } 1433222974Snp }; 1434284984Snp static struct field_desc fl_t4[] = { 1435222974Snp FIELD1("StatusPgNS:", 180), 1436222974Snp FIELD1("StatusPgRO:", 179), 1437222974Snp FIELD1("FetchNS:", 178), 1438222974Snp FIELD1("FetchRO:", 177), 1439222974Snp FIELD1("Valid:", 176), 1440222974Snp FIELD("PCIeDataChannel:", 174, 175), 1441222974Snp FIELD1("DCAEgrQEn:", 173), 1442222974Snp FIELD("DCACPUID:", 168, 172), 1443222974Snp FIELD1("FCThreshOverride:", 167), 1444222974Snp FIELD1("ReschedulePending:", 160), 1445222974Snp FIELD1("OnChipQueue:", 159), 1446222974Snp FIELD1("FetchSizeMode", 158), 1447222974Snp { "FetchBurstMin:", 156, 157, 4, 0, 1 }, 1448222974Snp { "FetchBurstMax:", 153, 154, 6, 0, 1 }, 1449222974Snp FIELD1("FLMcongMode:", 152), 1450222974Snp FIELD("MaxuPFLCredits:", 144, 151), 1451222974Snp FIELD("FLMcontextID:", 133, 143), 1452222974Snp FIELD1("uPTokenEn:", 132), 1453222974Snp FIELD1("UserModeIO:", 131), 1454222974Snp FIELD("uPFLCredits:", 123, 130), 1455222974Snp FIELD1("uPFLCreditEn:", 122), 1456222974Snp FIELD("FID:", 111, 121), 1457222974Snp FIELD("HostFCMode:", 109, 110), 1458222974Snp FIELD1("HostFCOwner:", 108), 1459222974Snp { "CIDXFlushThresh:", 105, 107, 0, 0, 1 }, 1460222974Snp FIELD("CIDX:", 89, 104), 1461222974Snp FIELD("PIDX:", 73, 88), 1462222974Snp { "BaseAddress:", 18, 72, 9, 1 }, 1463222974Snp FIELD("QueueSize:", 2, 17), 1464222974Snp FIELD1("QueueType:", 1), 1465222974Snp FIELD1("CachePriority:", 0), 1466222974Snp { NULL } 1467222974Snp }; 1468284984Snp static struct field_desc ingress_t4[] = { 1469222974Snp FIELD1("NoSnoop:", 145), 1470222974Snp FIELD1("RelaxedOrdering:", 144), 1471222974Snp FIELD1("GTSmode:", 143), 1472222974Snp FIELD1("ISCSICoalescing:", 142), 1473222974Snp FIELD1("Valid:", 141), 1474222974Snp FIELD1("TimerPending:", 140), 1475222974Snp FIELD1("DropRSS:", 139), 1476222974Snp FIELD("PCIeChannel:", 137, 138), 1477222974Snp FIELD1("SEInterruptArmed:", 136), 1478222974Snp FIELD1("CongestionMgtEnable:", 135), 1479222974Snp FIELD1("DCAIngQEnable:", 134), 1480222974Snp FIELD("DCACPUID:", 129, 133), 1481222974Snp FIELD1("UpdateScheduling:", 128), 1482222974Snp FIELD("UpdateDelivery:", 126, 127), 1483222974Snp FIELD1("InterruptSent:", 125), 1484222974Snp FIELD("InterruptIDX:", 114, 124), 1485222974Snp FIELD1("InterruptDestination:", 113), 1486222974Snp FIELD1("InterruptArmed:", 112), 1487222974Snp FIELD("RxIntCounter:", 106, 111), 1488222974Snp FIELD("RxIntCounterThreshold:", 104, 105), 1489222974Snp FIELD1("Generation:", 103), 1490222974Snp { "BaseAddress:", 48, 102, 9, 1 }, 1491222974Snp FIELD("PIDX:", 32, 47), 1492222974Snp FIELD("CIDX:", 16, 31), 1493222974Snp { "QueueSize:", 4, 15, 4, 0 }, 1494222974Snp { "QueueEntrySize:", 2, 3, 4, 0, 1 }, 1495222974Snp FIELD1("QueueEntryOverride:", 1), 1496222974Snp FIELD1("CachePriority:", 0), 1497222974Snp { NULL } 1498222974Snp }; 1499284984Snp static struct field_desc flm_t4[] = { 1500222974Snp FIELD1("NoSnoop:", 79), 1501222974Snp FIELD1("RelaxedOrdering:", 78), 1502222974Snp FIELD1("Valid:", 77), 1503222974Snp FIELD("DCACPUID:", 72, 76), 1504222974Snp FIELD1("DCAFLEn:", 71), 1505222974Snp FIELD("EQid:", 54, 70), 1506222974Snp FIELD("SplitEn:", 52, 53), 1507222974Snp FIELD1("PadEn:", 51), 1508222974Snp FIELD1("PackEn:", 50), 1509222974Snp FIELD1("DBpriority:", 48), 1510222974Snp FIELD("PackOffset:", 16, 47), 1511222974Snp FIELD("CIDX:", 8, 15), 1512222974Snp FIELD("PIDX:", 0, 7), 1513222974Snp { NULL } 1514222974Snp }; 1515284984Snp static struct field_desc conm_t4[] = { 1516222974Snp FIELD1("CngDBPHdr:", 6), 1517222974Snp FIELD1("CngDBPData:", 5), 1518222974Snp FIELD1("CngIMSG:", 4), 1519261534Snp { "CngChMap:", 0, 3, 0, 1, 0}, 1520222974Snp { NULL } 1521222974Snp }; 1522222974Snp 1523222974Snp if (p->mem_id == SGE_CONTEXT_EGRESS) 1524284984Snp show_struct(p->data, 6, (p->data[0] & 2) ? fl_t4 : egress_t4); 1525222974Snp else if (p->mem_id == SGE_CONTEXT_FLM) 1526284984Snp show_struct(p->data, 3, flm_t4); 1527222974Snp else if (p->mem_id == SGE_CONTEXT_INGRESS) 1528284984Snp show_struct(p->data, 5, ingress_t4); 1529222974Snp else if (p->mem_id == SGE_CONTEXT_CNM) 1530284984Snp show_struct(p->data, 1, conm_t4); 1531222974Snp} 1532222974Snp 1533222974Snp#undef FIELD 1534222974Snp#undef FIELD1 1535222974Snp 1536222900Snpstatic int 1537222974Snpget_sge_context(int argc, const char *argv[]) 1538222974Snp{ 1539222974Snp int rc; 1540222974Snp char *p; 1541222974Snp long cid; 1542222974Snp struct t4_sge_context cntxt = {0}; 1543222974Snp 1544222974Snp if (argc != 2) { 1545222974Snp warnx("sge_context: incorrect number of arguments."); 1546222974Snp return (EINVAL); 1547222974Snp } 1548222974Snp 1549222974Snp if (!strcmp(argv[0], "egress")) 1550222974Snp cntxt.mem_id = SGE_CONTEXT_EGRESS; 1551222974Snp else if (!strcmp(argv[0], "ingress")) 1552222974Snp cntxt.mem_id = SGE_CONTEXT_INGRESS; 1553222974Snp else if (!strcmp(argv[0], "fl")) 1554222974Snp cntxt.mem_id = SGE_CONTEXT_FLM; 1555222974Snp else if (!strcmp(argv[0], "cong")) 1556222974Snp cntxt.mem_id = SGE_CONTEXT_CNM; 1557222974Snp else { 1558222974Snp warnx("unknown context type \"%s\"; known types are egress, " 1559222974Snp "ingress, fl, and cong.", argv[0]); 1560222974Snp return (EINVAL); 1561222974Snp } 1562222974Snp 1563222974Snp p = str_to_number(argv[1], &cid, NULL); 1564222974Snp if (*p) { 1565222974Snp warnx("invalid context id \"%s\"", argv[1]); 1566222974Snp return (EINVAL); 1567222974Snp } 1568222974Snp cntxt.cid = cid; 1569222974Snp 1570222974Snp rc = doit(CHELSIO_T4_GET_SGE_CONTEXT, &cntxt); 1571222974Snp if (rc != 0) 1572222974Snp return (rc); 1573222974Snp 1574284984Snp if (chip_id == 4) 1575284984Snp show_t4_ctxt(&cntxt); 1576284984Snp else 1577284984Snp show_t5_ctxt(&cntxt); 1578284984Snp 1579222974Snp return (0); 1580222974Snp} 1581222974Snp 1582222974Snpstatic int 1583228594Snploadfw(int argc, const char *argv[]) 1584228594Snp{ 1585228594Snp int rc, fd; 1586228594Snp struct t4_data data = {0}; 1587228594Snp const char *fname = argv[0]; 1588228594Snp struct stat st = {0}; 1589228594Snp 1590228594Snp if (argc != 1) { 1591228594Snp warnx("loadfw: incorrect number of arguments."); 1592228594Snp return (EINVAL); 1593228594Snp } 1594228594Snp 1595228594Snp fd = open(fname, O_RDONLY); 1596228594Snp if (fd < 0) { 1597228594Snp warn("open(%s)", fname); 1598228594Snp return (errno); 1599228594Snp } 1600228594Snp 1601228594Snp if (fstat(fd, &st) < 0) { 1602228594Snp warn("fstat"); 1603228594Snp close(fd); 1604228594Snp return (errno); 1605228594Snp } 1606228594Snp 1607228594Snp data.len = st.st_size; 1608273360Snp data.data = mmap(0, data.len, PROT_READ, MAP_PRIVATE, fd, 0); 1609228594Snp if (data.data == MAP_FAILED) { 1610228594Snp warn("mmap"); 1611228594Snp close(fd); 1612228594Snp return (errno); 1613228594Snp } 1614228594Snp 1615228594Snp rc = doit(CHELSIO_T4_LOAD_FW, &data); 1616228594Snp munmap(data.data, data.len); 1617228594Snp close(fd); 1618228594Snp return (rc); 1619228594Snp} 1620228594Snp 1621228594Snpstatic int 1622228594Snpread_mem(uint32_t addr, uint32_t len, void (*output)(uint32_t *, uint32_t)) 1623228594Snp{ 1624228594Snp int rc; 1625228594Snp struct t4_mem_range mr; 1626228594Snp 1627228594Snp mr.addr = addr; 1628228594Snp mr.len = len; 1629228594Snp mr.data = malloc(mr.len); 1630228594Snp 1631228594Snp if (mr.data == 0) { 1632228594Snp warn("read_mem: malloc"); 1633228594Snp return (errno); 1634228594Snp } 1635228594Snp 1636228594Snp rc = doit(CHELSIO_T4_GET_MEM, &mr); 1637228594Snp if (rc != 0) 1638228594Snp goto done; 1639228594Snp 1640228594Snp if (output) 1641228594Snp (*output)(mr.data, mr.len); 1642228594Snpdone: 1643228594Snp free(mr.data); 1644228594Snp return (rc); 1645228594Snp} 1646228594Snp 1647228594Snp/* 1648228594Snp * Display memory as list of 'n' 4-byte values per line. 1649228594Snp */ 1650228594Snpstatic void 1651228594Snpshow_mem(uint32_t *buf, uint32_t len) 1652228594Snp{ 1653228594Snp const char *s; 1654228594Snp int i, n = 8; 1655228594Snp 1656228594Snp while (len) { 1657228594Snp for (i = 0; len && i < n; i++, buf++, len -= 4) { 1658228594Snp s = i ? " " : ""; 1659228594Snp printf("%s%08x", s, htonl(*buf)); 1660228594Snp } 1661228594Snp printf("\n"); 1662228594Snp } 1663228594Snp} 1664228594Snp 1665228594Snpstatic int 1666228594Snpmemdump(int argc, const char *argv[]) 1667228594Snp{ 1668228594Snp char *p; 1669228594Snp long l; 1670228594Snp uint32_t addr, len; 1671228594Snp 1672228594Snp if (argc != 2) { 1673228594Snp warnx("incorrect number of arguments."); 1674228594Snp return (EINVAL); 1675228594Snp } 1676228594Snp 1677228594Snp p = str_to_number(argv[0], &l, NULL); 1678228594Snp if (*p) { 1679228594Snp warnx("invalid address \"%s\"", argv[0]); 1680228594Snp return (EINVAL); 1681228594Snp } 1682228594Snp addr = l; 1683228594Snp 1684228594Snp p = str_to_number(argv[1], &l, NULL); 1685228594Snp if (*p) { 1686228594Snp warnx("memdump: invalid length \"%s\"", argv[1]); 1687228594Snp return (EINVAL); 1688228594Snp } 1689228594Snp len = l; 1690228594Snp 1691228594Snp return (read_mem(addr, len, show_mem)); 1692228594Snp} 1693228594Snp 1694228594Snp/* 1695228594Snp * Display TCB as list of 'n' 4-byte values per line. 1696228594Snp */ 1697228594Snpstatic void 1698228594Snpshow_tcb(uint32_t *buf, uint32_t len) 1699228594Snp{ 1700228594Snp const char *s; 1701228594Snp int i, n = 8; 1702228594Snp 1703228594Snp while (len) { 1704228594Snp for (i = 0; len && i < n; i++, buf++, len -= 4) { 1705228594Snp s = i ? " " : ""; 1706228594Snp printf("%s%08x", s, htonl(*buf)); 1707228594Snp } 1708228594Snp printf("\n"); 1709228594Snp } 1710228594Snp} 1711228594Snp 1712228594Snp#define A_TP_CMM_TCB_BASE 0x7d10 1713228594Snp#define TCB_SIZE 128 1714228594Snpstatic int 1715228594Snpread_tcb(int argc, const char *argv[]) 1716228594Snp{ 1717228594Snp char *p; 1718228594Snp long l; 1719228594Snp long long val; 1720228594Snp unsigned int tid; 1721228594Snp uint32_t addr; 1722228594Snp int rc; 1723228594Snp 1724228594Snp if (argc != 1) { 1725228594Snp warnx("incorrect number of arguments."); 1726228594Snp return (EINVAL); 1727228594Snp } 1728228594Snp 1729228594Snp p = str_to_number(argv[0], &l, NULL); 1730228594Snp if (*p) { 1731228594Snp warnx("invalid tid \"%s\"", argv[0]); 1732228594Snp return (EINVAL); 1733228594Snp } 1734228594Snp tid = l; 1735228594Snp 1736228594Snp rc = read_reg(A_TP_CMM_TCB_BASE, 4, &val); 1737228594Snp if (rc != 0) 1738228594Snp return (rc); 1739228594Snp 1740228594Snp addr = val + tid * TCB_SIZE; 1741228594Snp 1742228594Snp return (read_mem(addr, TCB_SIZE, show_tcb)); 1743228594Snp} 1744228594Snp 1745228594Snpstatic int 1746241401Snpread_i2c(int argc, const char *argv[]) 1747241401Snp{ 1748241401Snp char *p; 1749241401Snp long l; 1750241401Snp struct t4_i2c_data i2cd; 1751241401Snp int rc, i; 1752241401Snp 1753241401Snp if (argc < 3 || argc > 4) { 1754241401Snp warnx("incorrect number of arguments."); 1755241401Snp return (EINVAL); 1756241401Snp } 1757241401Snp 1758241401Snp p = str_to_number(argv[0], &l, NULL); 1759241401Snp if (*p || l > UCHAR_MAX) { 1760241401Snp warnx("invalid port id \"%s\"", argv[0]); 1761241401Snp return (EINVAL); 1762241401Snp } 1763241401Snp i2cd.port_id = l; 1764241401Snp 1765241401Snp p = str_to_number(argv[1], &l, NULL); 1766241401Snp if (*p || l > UCHAR_MAX) { 1767241401Snp warnx("invalid i2c device address \"%s\"", argv[1]); 1768241401Snp return (EINVAL); 1769241401Snp } 1770241401Snp i2cd.dev_addr = l; 1771241401Snp 1772241401Snp p = str_to_number(argv[2], &l, NULL); 1773241401Snp if (*p || l > UCHAR_MAX) { 1774241401Snp warnx("invalid byte offset \"%s\"", argv[2]); 1775241401Snp return (EINVAL); 1776241401Snp } 1777241401Snp i2cd.offset = l; 1778241401Snp 1779241401Snp if (argc == 4) { 1780241401Snp p = str_to_number(argv[3], &l, NULL); 1781241401Snp if (*p || l > sizeof(i2cd.data)) { 1782241401Snp warnx("invalid number of bytes \"%s\"", argv[3]); 1783241401Snp return (EINVAL); 1784241401Snp } 1785241401Snp i2cd.len = l; 1786241401Snp } else 1787241401Snp i2cd.len = 1; 1788241401Snp 1789241401Snp rc = doit(CHELSIO_T4_GET_I2C, &i2cd); 1790241401Snp if (rc != 0) 1791241401Snp return (rc); 1792241401Snp 1793241401Snp for (i = 0; i < i2cd.len; i++) 1794241401Snp printf("0x%x [%u]\n", i2cd.data[i], i2cd.data[i]); 1795241401Snp 1796241401Snp return (0); 1797241401Snp} 1798241401Snp 1799241401Snpstatic int 1800241416Snpclearstats(int argc, const char *argv[]) 1801241416Snp{ 1802241416Snp char *p; 1803241416Snp long l; 1804241416Snp uint32_t port; 1805241416Snp 1806241416Snp if (argc != 1) { 1807241416Snp warnx("incorrect number of arguments."); 1808241416Snp return (EINVAL); 1809241416Snp } 1810241416Snp 1811241416Snp p = str_to_number(argv[0], &l, NULL); 1812241416Snp if (*p) { 1813241416Snp warnx("invalid port id \"%s\"", argv[0]); 1814241416Snp return (EINVAL); 1815241416Snp } 1816241416Snp port = l; 1817241416Snp 1818241416Snp return doit(CHELSIO_T4_CLEAR_STATS, &port); 1819241416Snp} 1820241416Snp 1821241416Snpstatic int 1822253691Snpshow_tracers(void) 1823253691Snp{ 1824253691Snp struct t4_tracer t; 1825253691Snp char *s; 1826253691Snp int rc, port_idx, i; 1827253691Snp long long val; 1828253691Snp 1829253691Snp /* Magic values: MPS_TRC_CFG = 0x9800. MPS_TRC_CFG[1:1] = TrcEn */ 1830253691Snp rc = read_reg(0x9800, 4, &val); 1831253691Snp if (rc != 0) 1832253691Snp return (rc); 1833253691Snp printf("tracing is %s\n", val & 2 ? "ENABLED" : "DISABLED"); 1834253691Snp 1835253691Snp t.idx = 0; 1836253691Snp for (t.idx = 0; ; t.idx++) { 1837253691Snp rc = doit(CHELSIO_T4_GET_TRACER, &t); 1838253691Snp if (rc != 0 || t.idx == 0xff) 1839253691Snp break; 1840253691Snp 1841253691Snp if (t.tp.port < 4) { 1842253691Snp s = "Rx"; 1843253691Snp port_idx = t.tp.port; 1844253691Snp } else if (t.tp.port < 8) { 1845253691Snp s = "Tx"; 1846253691Snp port_idx = t.tp.port - 4; 1847253691Snp } else if (t.tp.port < 12) { 1848253691Snp s = "loopback"; 1849253691Snp port_idx = t.tp.port - 8; 1850253691Snp } else if (t.tp.port < 16) { 1851253691Snp s = "MPS Rx"; 1852253691Snp port_idx = t.tp.port - 12; 1853253691Snp } else if (t.tp.port < 20) { 1854253691Snp s = "MPS Tx"; 1855253691Snp port_idx = t.tp.port - 16; 1856253691Snp } else { 1857253691Snp s = "unknown"; 1858253691Snp port_idx = t.tp.port; 1859253691Snp } 1860253691Snp 1861253691Snp printf("\ntracer %u (currently %s) captures ", t.idx, 1862253691Snp t.enabled ? "ENABLED" : "DISABLED"); 1863253691Snp if (t.tp.port < 8) 1864253691Snp printf("port %u %s, ", port_idx, s); 1865253691Snp else 1866253691Snp printf("%s %u, ", s, port_idx); 1867253691Snp printf("snap length: %u, min length: %u\n", t.tp.snap_len, 1868253691Snp t.tp.min_len); 1869253691Snp printf("packets captured %smatch filter\n", 1870253691Snp t.tp.invert ? "do not " : ""); 1871253691Snp if (t.tp.skip_ofst) { 1872253691Snp printf("filter pattern: "); 1873253691Snp for (i = 0; i < t.tp.skip_ofst * 2; i += 2) 1874253691Snp printf("%08x%08x", t.tp.data[i], 1875253691Snp t.tp.data[i + 1]); 1876253691Snp printf("/"); 1877253691Snp for (i = 0; i < t.tp.skip_ofst * 2; i += 2) 1878253691Snp printf("%08x%08x", t.tp.mask[i], 1879253691Snp t.tp.mask[i + 1]); 1880253691Snp printf("@0\n"); 1881253691Snp } 1882253691Snp printf("filter pattern: "); 1883253691Snp for (i = t.tp.skip_ofst * 2; i < T4_TRACE_LEN / 4; i += 2) 1884253691Snp printf("%08x%08x", t.tp.data[i], t.tp.data[i + 1]); 1885253691Snp printf("/"); 1886253691Snp for (i = t.tp.skip_ofst * 2; i < T4_TRACE_LEN / 4; i += 2) 1887253691Snp printf("%08x%08x", t.tp.mask[i], t.tp.mask[i + 1]); 1888253691Snp printf("@%u\n", (t.tp.skip_ofst + t.tp.skip_len) * 8); 1889253691Snp } 1890253691Snp 1891253691Snp return (rc); 1892253691Snp} 1893253691Snp 1894253691Snpstatic int 1895253691Snptracer_onoff(uint8_t idx, int enabled) 1896253691Snp{ 1897253691Snp struct t4_tracer t; 1898253691Snp 1899253691Snp t.idx = idx; 1900253691Snp t.enabled = enabled; 1901253691Snp t.valid = 0; 1902253691Snp 1903253691Snp return doit(CHELSIO_T4_SET_TRACER, &t); 1904253691Snp} 1905253691Snp 1906253691Snpstatic void 1907253691Snpcreate_tracing_ifnet() 1908253691Snp{ 1909253691Snp char *cmd[] = { 1910253691Snp "/sbin/ifconfig", __DECONST(char *, nexus), "create", NULL 1911253691Snp }; 1912253691Snp char *env[] = {NULL}; 1913253691Snp 1914253691Snp if (vfork() == 0) { 1915253691Snp close(STDERR_FILENO); 1916253691Snp execve(cmd[0], cmd, env); 1917253691Snp _exit(0); 1918253691Snp } 1919253691Snp} 1920253691Snp 1921253691Snp/* 1922253691Snp * XXX: Allow user to specify snaplen, minlen, and pattern (including inverted 1923253691Snp * matching). Right now this is a quick-n-dirty implementation that traces the 1924253691Snp * first 128B of all tx or rx on a port 1925253691Snp */ 1926253691Snpstatic int 1927253691Snpset_tracer(uint8_t idx, int argc, const char *argv[]) 1928253691Snp{ 1929253691Snp struct t4_tracer t; 1930253691Snp int len, port; 1931253691Snp 1932253691Snp bzero(&t, sizeof (t)); 1933253691Snp t.idx = idx; 1934253691Snp t.enabled = 1; 1935253691Snp t.valid = 1; 1936253691Snp 1937253691Snp if (argc != 1) { 1938253691Snp warnx("must specify tx<n> or rx<n>."); 1939253691Snp return (EINVAL); 1940253691Snp } 1941253691Snp 1942253691Snp len = strlen(argv[0]); 1943253691Snp if (len != 3) { 1944253691Snp warnx("argument must be 3 characters (tx<n> or rx<n>)"); 1945253691Snp return (EINVAL); 1946253691Snp } 1947253691Snp 1948253691Snp if (strncmp(argv[0], "tx", 2) == 0) { 1949253691Snp port = argv[0][2] - '0'; 1950253691Snp if (port < 0 || port > 3) { 1951253691Snp warnx("'%c' in %s is invalid", argv[0][2], argv[0]); 1952253691Snp return (EINVAL); 1953253691Snp } 1954253691Snp port += 4; 1955253691Snp } else if (strncmp(argv[0], "rx", 2) == 0) { 1956253691Snp port = argv[0][2] - '0'; 1957253691Snp if (port < 0 || port > 3) { 1958253691Snp warnx("'%c' in %s is invalid", argv[0][2], argv[0]); 1959253691Snp return (EINVAL); 1960253691Snp } 1961253691Snp } else { 1962253691Snp warnx("argument '%s' isn't tx<n> or rx<n>", argv[0]); 1963253691Snp return (EINVAL); 1964253691Snp } 1965253691Snp 1966253691Snp t.tp.snap_len = 128; 1967253691Snp t.tp.min_len = 0; 1968253691Snp t.tp.skip_ofst = 0; 1969253691Snp t.tp.skip_len = 0; 1970253691Snp t.tp.invert = 0; 1971253691Snp t.tp.port = port; 1972253691Snp 1973253691Snp create_tracing_ifnet(); 1974253691Snp return doit(CHELSIO_T4_SET_TRACER, &t); 1975253691Snp} 1976253691Snp 1977253691Snpstatic int 1978259048Snptracer_cmd(int argc, const char *argv[]) 1979259048Snp{ 1980259048Snp long long val; 1981259048Snp uint8_t idx; 1982259048Snp char *s; 1983259048Snp 1984259048Snp if (argc == 0) { 1985259048Snp warnx("tracer: no arguments."); 1986259048Snp return (EINVAL); 1987259048Snp }; 1988259048Snp 1989259048Snp /* list */ 1990259048Snp if (strcmp(argv[0], "list") == 0) { 1991259048Snp if (argc != 1) 1992259048Snp warnx("trailing arguments after \"list\" ignored."); 1993259048Snp 1994259048Snp return show_tracers(); 1995259048Snp } 1996259048Snp 1997259048Snp /* <idx> ... */ 1998259048Snp s = str_to_number(argv[0], NULL, &val); 1999259048Snp if (*s || val > 0xff) { 2000259048Snp warnx("\"%s\" is neither an index nor a tracer subcommand.", 2001259048Snp argv[0]); 2002259048Snp return (EINVAL); 2003259048Snp } 2004259048Snp idx = (int8_t)val; 2005259048Snp 2006259048Snp /* <idx> disable */ 2007259048Snp if (argc == 2 && strcmp(argv[1], "disable") == 0) 2008259048Snp return tracer_onoff(idx, 0); 2009259048Snp 2010259048Snp /* <idx> enable */ 2011259048Snp if (argc == 2 && strcmp(argv[1], "enable") == 0) 2012259048Snp return tracer_onoff(idx, 1); 2013259048Snp 2014259048Snp /* <idx> ... */ 2015259048Snp return set_tracer(idx, argc - 1, argv + 1); 2016259048Snp} 2017259048Snp 2018259048Snpstatic int 2019269106Snpmodinfo_raw(int port_id) 2020269106Snp{ 2021269106Snp uint8_t offset; 2022269106Snp struct t4_i2c_data i2cd; 2023269106Snp int rc; 2024269106Snp 2025269106Snp for (offset = 0; offset < 96; offset += sizeof(i2cd.data)) { 2026269106Snp bzero(&i2cd, sizeof(i2cd)); 2027269106Snp i2cd.port_id = port_id; 2028269106Snp i2cd.dev_addr = 0xa0; 2029269106Snp i2cd.offset = offset; 2030269106Snp i2cd.len = sizeof(i2cd.data); 2031269106Snp rc = doit(CHELSIO_T4_GET_I2C, &i2cd); 2032269106Snp if (rc != 0) 2033269106Snp return (rc); 2034269106Snp printf("%02x: %02x %02x %02x %02x %02x %02x %02x %02x", 2035269106Snp offset, i2cd.data[0], i2cd.data[1], i2cd.data[2], 2036269106Snp i2cd.data[3], i2cd.data[4], i2cd.data[5], i2cd.data[6], 2037269106Snp i2cd.data[7]); 2038269106Snp 2039269106Snp printf(" %c%c%c%c %c%c%c%c\n", 2040269106Snp isprint(i2cd.data[0]) ? i2cd.data[0] : '.', 2041269106Snp isprint(i2cd.data[1]) ? i2cd.data[1] : '.', 2042269106Snp isprint(i2cd.data[2]) ? i2cd.data[2] : '.', 2043269106Snp isprint(i2cd.data[3]) ? i2cd.data[3] : '.', 2044269106Snp isprint(i2cd.data[4]) ? i2cd.data[4] : '.', 2045269106Snp isprint(i2cd.data[5]) ? i2cd.data[5] : '.', 2046269106Snp isprint(i2cd.data[6]) ? i2cd.data[6] : '.', 2047269106Snp isprint(i2cd.data[7]) ? i2cd.data[7] : '.'); 2048269106Snp } 2049269106Snp 2050269106Snp return (0); 2051269106Snp} 2052269106Snp 2053269106Snpstatic int 2054258698Snpmodinfo(int argc, const char *argv[]) 2055258698Snp{ 2056258698Snp long port; 2057258698Snp char string[16], *p; 2058258698Snp struct t4_i2c_data i2cd; 2059258698Snp int rc, i; 2060258698Snp uint16_t temp, vcc, tx_bias, tx_power, rx_power; 2061258698Snp 2062269106Snp if (argc < 1) { 2063258698Snp warnx("must supply a port"); 2064258698Snp return (EINVAL); 2065258698Snp } 2066258698Snp 2067269106Snp if (argc > 2) { 2068269106Snp warnx("too many arguments"); 2069269106Snp return (EINVAL); 2070269106Snp } 2071269106Snp 2072258698Snp p = str_to_number(argv[0], &port, NULL); 2073258698Snp if (*p || port > UCHAR_MAX) { 2074258698Snp warnx("invalid port id \"%s\"", argv[0]); 2075258698Snp return (EINVAL); 2076258698Snp } 2077258698Snp 2078269106Snp if (argc == 2) { 2079269106Snp if (!strcmp(argv[1], "raw")) 2080269106Snp return (modinfo_raw(port)); 2081269106Snp else { 2082269106Snp warnx("second argument can only be \"raw\""); 2083269106Snp return (EINVAL); 2084269106Snp } 2085269106Snp } 2086269106Snp 2087258698Snp bzero(&i2cd, sizeof(i2cd)); 2088258698Snp i2cd.len = 1; 2089258698Snp i2cd.port_id = port; 2090258698Snp i2cd.dev_addr = SFF_8472_BASE; 2091258698Snp 2092258698Snp i2cd.offset = SFF_8472_ID; 2093258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2094258698Snp goto fail; 2095258698Snp 2096258698Snp if (i2cd.data[0] > SFF_8472_ID_LAST) 2097258698Snp printf("Unknown ID\n"); 2098258698Snp else 2099258698Snp printf("ID: %s\n", sff_8472_id[i2cd.data[0]]); 2100258698Snp 2101258698Snp bzero(&string, sizeof(string)); 2102258698Snp for (i = SFF_8472_VENDOR_START; i < SFF_8472_VENDOR_END; i++) { 2103258698Snp i2cd.offset = i; 2104258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2105258698Snp goto fail; 2106258698Snp string[i - SFF_8472_VENDOR_START] = i2cd.data[0]; 2107258698Snp } 2108258698Snp printf("Vendor %s\n", string); 2109258698Snp 2110258698Snp bzero(&string, sizeof(string)); 2111258698Snp for (i = SFF_8472_SN_START; i < SFF_8472_SN_END; i++) { 2112258698Snp i2cd.offset = i; 2113258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2114258698Snp goto fail; 2115258698Snp string[i - SFF_8472_SN_START] = i2cd.data[0]; 2116258698Snp } 2117258698Snp printf("SN %s\n", string); 2118258698Snp 2119258698Snp bzero(&string, sizeof(string)); 2120258698Snp for (i = SFF_8472_PN_START; i < SFF_8472_PN_END; i++) { 2121258698Snp i2cd.offset = i; 2122258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2123258698Snp goto fail; 2124258698Snp string[i - SFF_8472_PN_START] = i2cd.data[0]; 2125258698Snp } 2126258698Snp printf("PN %s\n", string); 2127258698Snp 2128258698Snp bzero(&string, sizeof(string)); 2129258698Snp for (i = SFF_8472_REV_START; i < SFF_8472_REV_END; i++) { 2130258698Snp i2cd.offset = i; 2131258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2132258698Snp goto fail; 2133258698Snp string[i - SFF_8472_REV_START] = i2cd.data[0]; 2134258698Snp } 2135258698Snp printf("Rev %s\n", string); 2136258698Snp 2137258698Snp i2cd.offset = SFF_8472_DIAG_TYPE; 2138258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2139258698Snp goto fail; 2140258698Snp 2141258698Snp if ((char )i2cd.data[0] & (SFF_8472_DIAG_IMPL | 2142258698Snp SFF_8472_DIAG_INTERNAL)) { 2143258698Snp 2144258698Snp /* Switch to reading from the Diagnostic address. */ 2145258698Snp i2cd.dev_addr = SFF_8472_DIAG; 2146258698Snp i2cd.len = 1; 2147258698Snp 2148258698Snp i2cd.offset = SFF_8472_TEMP; 2149258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2150258698Snp goto fail; 2151258698Snp temp = i2cd.data[0] << 8; 2152258698Snp printf("Temp: "); 2153258698Snp if ((temp & SFF_8472_TEMP_SIGN) == SFF_8472_TEMP_SIGN) 2154258698Snp printf("-"); 2155258698Snp else 2156258698Snp printf("+"); 2157258698Snp printf("%dC\n", (temp & SFF_8472_TEMP_MSK) >> 2158258698Snp SFF_8472_TEMP_SHIFT); 2159258698Snp 2160258698Snp i2cd.offset = SFF_8472_VCC; 2161258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2162258698Snp goto fail; 2163258698Snp vcc = i2cd.data[0] << 8; 2164258698Snp printf("Vcc %fV\n", vcc / SFF_8472_VCC_FACTOR); 2165258698Snp 2166258698Snp i2cd.offset = SFF_8472_TX_BIAS; 2167258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2168258698Snp goto fail; 2169258698Snp tx_bias = i2cd.data[0] << 8; 2170258698Snp printf("TX Bias %fuA\n", tx_bias / SFF_8472_BIAS_FACTOR); 2171258698Snp 2172258698Snp i2cd.offset = SFF_8472_TX_POWER; 2173258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2174258698Snp goto fail; 2175258698Snp tx_power = i2cd.data[0] << 8; 2176258698Snp printf("TX Power %fmW\n", tx_power / SFF_8472_POWER_FACTOR); 2177258698Snp 2178258698Snp i2cd.offset = SFF_8472_RX_POWER; 2179258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2180258698Snp goto fail; 2181258698Snp rx_power = i2cd.data[0] << 8; 2182258698Snp printf("RX Power %fmW\n", rx_power / SFF_8472_POWER_FACTOR); 2183258698Snp 2184258698Snp } else 2185258698Snp printf("Diagnostics not supported.\n"); 2186258698Snp 2187258698Snp return(0); 2188258698Snp 2189258698Snpfail: 2190258698Snp if (rc == EPERM) 2191258698Snp warnx("No module/cable in port %ld", port); 2192258698Snp return (rc); 2193258698Snp 2194258698Snp} 2195258698Snp 2196259048Snp/* XXX: pass in a low/high and do range checks as well */ 2197258698Snpstatic int 2198259048Snpget_sched_param(const char *param, const char *args[], long *val) 2199253691Snp{ 2200259048Snp char *p; 2201253691Snp 2202259048Snp if (strcmp(param, args[0]) != 0) 2203259048Snp return (EINVAL); 2204259048Snp 2205259048Snp p = str_to_number(args[1], val, NULL); 2206259048Snp if (*p) { 2207259048Snp warnx("parameter \"%s\" has bad value \"%s\"", args[0], 2208259048Snp args[1]); 2209259048Snp return (EINVAL); 2210259048Snp } 2211259048Snp 2212259048Snp return (0); 2213259048Snp} 2214259048Snp 2215259048Snpstatic int 2216259048Snpsched_class(int argc, const char *argv[]) 2217259048Snp{ 2218259048Snp struct t4_sched_params op; 2219259048Snp int errs, i; 2220259048Snp 2221259048Snp memset(&op, 0xff, sizeof(op)); 2222259048Snp op.subcmd = -1; 2223259048Snp op.type = -1; 2224253691Snp if (argc == 0) { 2225259048Snp warnx("missing scheduling sub-command"); 2226253691Snp return (EINVAL); 2227259048Snp } 2228259048Snp if (!strcmp(argv[0], "config")) { 2229259048Snp op.subcmd = SCHED_CLASS_SUBCMD_CONFIG; 2230259048Snp op.u.config.minmax = -1; 2231259048Snp } else if (!strcmp(argv[0], "params")) { 2232259048Snp op.subcmd = SCHED_CLASS_SUBCMD_PARAMS; 2233259048Snp op.u.params.level = op.u.params.mode = op.u.params.rateunit = 2234259048Snp op.u.params.ratemode = op.u.params.channel = 2235259048Snp op.u.params.cl = op.u.params.minrate = op.u.params.maxrate = 2236259048Snp op.u.params.weight = op.u.params.pktsize = -1; 2237259048Snp } else { 2238259048Snp warnx("invalid scheduling sub-command \"%s\"", argv[0]); 2239259048Snp return (EINVAL); 2240259048Snp } 2241253691Snp 2242259048Snp /* Decode remaining arguments ... */ 2243259048Snp errs = 0; 2244259048Snp for (i = 1; i < argc; i += 2) { 2245259048Snp const char **args = &argv[i]; 2246259048Snp long l; 2247253691Snp 2248259048Snp if (i + 1 == argc) { 2249259048Snp warnx("missing argument for \"%s\"", args[0]); 2250259048Snp errs++; 2251259048Snp break; 2252259048Snp } 2253259048Snp 2254259048Snp if (!strcmp(args[0], "type")) { 2255259048Snp if (!strcmp(args[1], "packet")) 2256259048Snp op.type = SCHED_CLASS_TYPE_PACKET; 2257259048Snp else { 2258259048Snp warnx("invalid type parameter \"%s\"", args[1]); 2259259048Snp errs++; 2260259048Snp } 2261259048Snp 2262259048Snp continue; 2263259048Snp } 2264259048Snp 2265259048Snp if (op.subcmd == SCHED_CLASS_SUBCMD_CONFIG) { 2266259048Snp if(!get_sched_param("minmax", args, &l)) 2267259048Snp op.u.config.minmax = (int8_t)l; 2268259048Snp else { 2269259048Snp warnx("unknown scheduler config parameter " 2270259048Snp "\"%s\"", args[0]); 2271259048Snp errs++; 2272259048Snp } 2273259048Snp 2274259048Snp continue; 2275259048Snp } 2276259048Snp 2277259048Snp /* Rest applies only to SUBCMD_PARAMS */ 2278259048Snp if (op.subcmd != SCHED_CLASS_SUBCMD_PARAMS) 2279259048Snp continue; 2280259048Snp 2281259048Snp if (!strcmp(args[0], "level")) { 2282259048Snp if (!strcmp(args[1], "cl-rl")) 2283259048Snp op.u.params.level = SCHED_CLASS_LEVEL_CL_RL; 2284259048Snp else if (!strcmp(args[1], "cl-wrr")) 2285259048Snp op.u.params.level = SCHED_CLASS_LEVEL_CL_WRR; 2286259048Snp else if (!strcmp(args[1], "ch-rl")) 2287259048Snp op.u.params.level = SCHED_CLASS_LEVEL_CH_RL; 2288259048Snp else { 2289259048Snp warnx("invalid level parameter \"%s\"", 2290259048Snp args[1]); 2291259048Snp errs++; 2292259048Snp } 2293259048Snp } else if (!strcmp(args[0], "mode")) { 2294259048Snp if (!strcmp(args[1], "class")) 2295259048Snp op.u.params.mode = SCHED_CLASS_MODE_CLASS; 2296259048Snp else if (!strcmp(args[1], "flow")) 2297259048Snp op.u.params.mode = SCHED_CLASS_MODE_FLOW; 2298259048Snp else { 2299259048Snp warnx("invalid mode parameter \"%s\"", args[1]); 2300259048Snp errs++; 2301259048Snp } 2302259048Snp } else if (!strcmp(args[0], "rate-unit")) { 2303259048Snp if (!strcmp(args[1], "bits")) 2304259048Snp op.u.params.rateunit = SCHED_CLASS_RATEUNIT_BITS; 2305259048Snp else if (!strcmp(args[1], "pkts")) 2306259048Snp op.u.params.rateunit = SCHED_CLASS_RATEUNIT_PKTS; 2307259048Snp else { 2308259048Snp warnx("invalid rate-unit parameter \"%s\"", 2309259048Snp args[1]); 2310259048Snp errs++; 2311259048Snp } 2312259048Snp } else if (!strcmp(args[0], "rate-mode")) { 2313259048Snp if (!strcmp(args[1], "relative")) 2314259048Snp op.u.params.ratemode = SCHED_CLASS_RATEMODE_REL; 2315259048Snp else if (!strcmp(args[1], "absolute")) 2316259048Snp op.u.params.ratemode = SCHED_CLASS_RATEMODE_ABS; 2317259048Snp else { 2318259048Snp warnx("invalid rate-mode parameter \"%s\"", 2319259048Snp args[1]); 2320259048Snp errs++; 2321259048Snp } 2322259048Snp } else if (!get_sched_param("channel", args, &l)) 2323259048Snp op.u.params.channel = (int8_t)l; 2324259048Snp else if (!get_sched_param("class", args, &l)) 2325259048Snp op.u.params.cl = (int8_t)l; 2326259048Snp else if (!get_sched_param("min-rate", args, &l)) 2327259048Snp op.u.params.minrate = (int32_t)l; 2328259048Snp else if (!get_sched_param("max-rate", args, &l)) 2329259048Snp op.u.params.maxrate = (int32_t)l; 2330259048Snp else if (!get_sched_param("weight", args, &l)) 2331259048Snp op.u.params.weight = (int16_t)l; 2332259048Snp else if (!get_sched_param("pkt-size", args, &l)) 2333259048Snp op.u.params.pktsize = (int16_t)l; 2334259048Snp else { 2335259048Snp warnx("unknown scheduler parameter \"%s\"", args[0]); 2336259048Snp errs++; 2337259048Snp } 2338253691Snp } 2339253691Snp 2340259048Snp /* 2341259048Snp * Catch some logical fallacies in terms of argument combinations here 2342259048Snp * so we can offer more than just the EINVAL return from the driver. 2343259048Snp * The driver will be able to catch a lot more issues since it knows 2344259048Snp * the specifics of the device hardware capabilities like how many 2345259048Snp * channels, classes, etc. the device supports. 2346259048Snp */ 2347259048Snp if (op.type < 0) { 2348259048Snp warnx("sched \"type\" parameter missing"); 2349259048Snp errs++; 2350259048Snp } 2351259048Snp if (op.subcmd == SCHED_CLASS_SUBCMD_CONFIG) { 2352259048Snp if (op.u.config.minmax < 0) { 2353259048Snp warnx("sched config \"minmax\" parameter missing"); 2354259048Snp errs++; 2355259048Snp } 2356259048Snp } 2357259048Snp if (op.subcmd == SCHED_CLASS_SUBCMD_PARAMS) { 2358259048Snp if (op.u.params.level < 0) { 2359259048Snp warnx("sched params \"level\" parameter missing"); 2360259048Snp errs++; 2361259048Snp } 2362259048Snp if (op.u.params.mode < 0) { 2363259048Snp warnx("sched params \"mode\" parameter missing"); 2364259048Snp errs++; 2365259048Snp } 2366259048Snp if (op.u.params.rateunit < 0) { 2367259048Snp warnx("sched params \"rate-unit\" parameter missing"); 2368259048Snp errs++; 2369259048Snp } 2370259048Snp if (op.u.params.ratemode < 0) { 2371259048Snp warnx("sched params \"rate-mode\" parameter missing"); 2372259048Snp errs++; 2373259048Snp } 2374259048Snp if (op.u.params.channel < 0) { 2375259048Snp warnx("sched params \"channel\" missing"); 2376259048Snp errs++; 2377259048Snp } 2378259048Snp if (op.u.params.cl < 0) { 2379259048Snp warnx("sched params \"class\" missing"); 2380259048Snp errs++; 2381259048Snp } 2382259048Snp if (op.u.params.maxrate < 0 && 2383259048Snp (op.u.params.level == SCHED_CLASS_LEVEL_CL_RL || 2384259048Snp op.u.params.level == SCHED_CLASS_LEVEL_CH_RL)) { 2385259048Snp warnx("sched params \"max-rate\" missing for " 2386259048Snp "rate-limit level"); 2387259048Snp errs++; 2388259048Snp } 2389259048Snp if (op.u.params.weight < 0 && 2390259048Snp op.u.params.level == SCHED_CLASS_LEVEL_CL_WRR) { 2391259048Snp warnx("sched params \"weight\" missing for " 2392259048Snp "weighted-round-robin level"); 2393259048Snp errs++; 2394259048Snp } 2395259048Snp if (op.u.params.pktsize < 0 && 2396259048Snp (op.u.params.level == SCHED_CLASS_LEVEL_CL_RL || 2397259048Snp op.u.params.level == SCHED_CLASS_LEVEL_CH_RL)) { 2398259048Snp warnx("sched params \"pkt-size\" missing for " 2399259048Snp "rate-limit level"); 2400259048Snp errs++; 2401259048Snp } 2402259048Snp if (op.u.params.mode == SCHED_CLASS_MODE_FLOW && 2403259048Snp op.u.params.ratemode != SCHED_CLASS_RATEMODE_ABS) { 2404259048Snp warnx("sched params mode flow needs rate-mode absolute"); 2405259048Snp errs++; 2406259048Snp } 2407259048Snp if (op.u.params.ratemode == SCHED_CLASS_RATEMODE_REL && 2408259048Snp !in_range(op.u.params.maxrate, 1, 100)) { 2409259048Snp warnx("sched params \"max-rate\" takes " 2410259048Snp "percentage value(1-100) for rate-mode relative"); 2411259048Snp errs++; 2412259048Snp } 2413259048Snp if (op.u.params.ratemode == SCHED_CLASS_RATEMODE_ABS && 2414259048Snp !in_range(op.u.params.maxrate, 1, 10000000)) { 2415259048Snp warnx("sched params \"max-rate\" takes " 2416259048Snp "value(1-10000000) for rate-mode absolute"); 2417259048Snp errs++; 2418259048Snp } 2419259048Snp if (op.u.params.maxrate > 0 && 2420259048Snp op.u.params.maxrate < op.u.params.minrate) { 2421259048Snp warnx("sched params \"max-rate\" is less than " 2422259048Snp "\"min-rate\""); 2423259048Snp errs++; 2424259048Snp } 2425259048Snp } 2426259048Snp 2427259048Snp if (errs > 0) { 2428259048Snp warnx("%d error%s in sched-class command", errs, 2429259048Snp errs == 1 ? "" : "s"); 2430253691Snp return (EINVAL); 2431253691Snp } 2432253691Snp 2433259048Snp return doit(CHELSIO_T4_SCHED_CLASS, &op); 2434259048Snp} 2435253691Snp 2436259048Snpstatic int 2437259048Snpsched_queue(int argc, const char *argv[]) 2438259048Snp{ 2439259048Snp struct t4_sched_queue op = {0}; 2440259048Snp char *p; 2441259048Snp long val; 2442253691Snp 2443259048Snp if (argc != 3) { 2444259048Snp /* need "<port> <queue> <class> */ 2445259048Snp warnx("incorrect number of arguments."); 2446259048Snp return (EINVAL); 2447259048Snp } 2448259048Snp 2449259048Snp p = str_to_number(argv[0], &val, NULL); 2450259048Snp if (*p || val > UCHAR_MAX) { 2451259048Snp warnx("invalid port id \"%s\"", argv[0]); 2452259048Snp return (EINVAL); 2453259048Snp } 2454259048Snp op.port = (uint8_t)val; 2455259048Snp 2456259048Snp if (!strcmp(argv[1], "all") || !strcmp(argv[1], "*")) 2457259048Snp op.queue = -1; 2458259048Snp else { 2459259048Snp p = str_to_number(argv[1], &val, NULL); 2460259048Snp if (*p || val < -1) { 2461259048Snp warnx("invalid queue \"%s\"", argv[1]); 2462259048Snp return (EINVAL); 2463259048Snp } 2464259048Snp op.queue = (int8_t)val; 2465259048Snp } 2466259048Snp 2467259048Snp if (!strcmp(argv[2], "unbind") || !strcmp(argv[2], "clear")) 2468259048Snp op.cl = -1; 2469259048Snp else { 2470259048Snp p = str_to_number(argv[2], &val, NULL); 2471259048Snp if (*p || val < -1) { 2472259048Snp warnx("invalid class \"%s\"", argv[2]); 2473259048Snp return (EINVAL); 2474259048Snp } 2475259048Snp op.cl = (int8_t)val; 2476259048Snp } 2477259048Snp 2478259048Snp return doit(CHELSIO_T4_SCHED_QUEUE, &op); 2479253691Snp} 2480253691Snp 2481253691Snpstatic int 2482222900Snprun_cmd(int argc, const char *argv[]) 2483222900Snp{ 2484222900Snp int rc = -1; 2485222900Snp const char *cmd = argv[0]; 2486222900Snp 2487222900Snp /* command */ 2488222900Snp argc--; 2489222900Snp argv++; 2490222900Snp 2491222900Snp if (!strcmp(cmd, "reg") || !strcmp(cmd, "reg32")) 2492222900Snp rc = register_io(argc, argv, 4); 2493222900Snp else if (!strcmp(cmd, "reg64")) 2494222900Snp rc = register_io(argc, argv, 8); 2495222900Snp else if (!strcmp(cmd, "regdump")) 2496222900Snp rc = dump_regs(argc, argv); 2497222900Snp else if (!strcmp(cmd, "filter")) 2498222900Snp rc = filter_cmd(argc, argv); 2499222974Snp else if (!strcmp(cmd, "context")) 2500222974Snp rc = get_sge_context(argc, argv); 2501228594Snp else if (!strcmp(cmd, "loadfw")) 2502228594Snp rc = loadfw(argc, argv); 2503228594Snp else if (!strcmp(cmd, "memdump")) 2504228594Snp rc = memdump(argc, argv); 2505228594Snp else if (!strcmp(cmd, "tcb")) 2506228594Snp rc = read_tcb(argc, argv); 2507241401Snp else if (!strcmp(cmd, "i2c")) 2508241401Snp rc = read_i2c(argc, argv); 2509241416Snp else if (!strcmp(cmd, "clearstats")) 2510241416Snp rc = clearstats(argc, argv); 2511253691Snp else if (!strcmp(cmd, "tracer")) 2512253691Snp rc = tracer_cmd(argc, argv); 2513258698Snp else if (!strcmp(cmd, "modinfo")) 2514258698Snp rc = modinfo(argc, argv); 2515259048Snp else if (!strcmp(cmd, "sched-class")) 2516259048Snp rc = sched_class(argc, argv); 2517259048Snp else if (!strcmp(cmd, "sched-queue")) 2518259048Snp rc = sched_queue(argc, argv); 2519222900Snp else { 2520222900Snp rc = EINVAL; 2521222900Snp warnx("invalid command \"%s\"", cmd); 2522222900Snp } 2523222900Snp 2524222900Snp return (rc); 2525222900Snp} 2526222900Snp 2527222900Snp#define MAX_ARGS 15 2528222900Snpstatic int 2529222900Snprun_cmd_loop(void) 2530222900Snp{ 2531222900Snp int i, rc = 0; 2532222900Snp char buffer[128], *buf; 2533222900Snp const char *args[MAX_ARGS + 1]; 2534222900Snp 2535222900Snp /* 2536222900Snp * Simple loop: displays a "> " prompt and processes any input as a 2537222900Snp * cxgbetool command. You're supposed to enter only the part after 2538222900Snp * "cxgbetool t4nexX". Use "quit" or "exit" to exit. 2539222900Snp */ 2540222900Snp for (;;) { 2541222900Snp fprintf(stdout, "> "); 2542222900Snp fflush(stdout); 2543222900Snp buf = fgets(buffer, sizeof(buffer), stdin); 2544222900Snp if (buf == NULL) { 2545222900Snp if (ferror(stdin)) { 2546222900Snp warn("stdin error"); 2547222900Snp rc = errno; /* errno from fgets */ 2548222900Snp } 2549222900Snp break; 2550222900Snp } 2551222900Snp 2552222900Snp i = 0; 2553222900Snp while ((args[i] = strsep(&buf, " \t\n")) != NULL) { 2554222900Snp if (args[i][0] != 0 && ++i == MAX_ARGS) 2555222900Snp break; 2556222900Snp } 2557222900Snp args[i] = 0; 2558222900Snp 2559222900Snp if (i == 0) 2560222900Snp continue; /* skip empty line */ 2561222900Snp 2562222900Snp if (!strcmp(args[0], "quit") || !strcmp(args[0], "exit")) 2563222900Snp break; 2564222900Snp 2565222900Snp rc = run_cmd(i, args); 2566222900Snp } 2567222900Snp 2568222900Snp /* rc normally comes from the last command (not including quit/exit) */ 2569222900Snp return (rc); 2570222900Snp} 2571222900Snp 2572222900Snpint 2573222900Snpmain(int argc, const char *argv[]) 2574222900Snp{ 2575222900Snp int rc = -1; 2576222900Snp 2577222900Snp progname = argv[0]; 2578222900Snp 2579222900Snp if (argc == 2) { 2580222900Snp if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { 2581222900Snp usage(stdout); 2582222900Snp exit(0); 2583222900Snp } 2584222900Snp } 2585222900Snp 2586222900Snp if (argc < 3) { 2587222900Snp usage(stderr); 2588222900Snp exit(EINVAL); 2589222900Snp } 2590222900Snp 2591222900Snp nexus = argv[1]; 2592222900Snp 2593222900Snp /* progname and nexus */ 2594222900Snp argc -= 2; 2595222900Snp argv += 2; 2596222900Snp 2597222900Snp if (argc == 1 && !strcmp(argv[0], "stdio")) 2598222900Snp rc = run_cmd_loop(); 2599222900Snp else 2600222900Snp rc = run_cmd(argc, argv); 2601222900Snp 2602222900Snp return (rc); 2603222900Snp} 2604