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: stable/11/usr.sbin/cxgbetool/cxgbetool.c 346806 2019-04-28 08:22:37Z np $"); 30222900Snp 31287297Srodrigc#include <sys/param.h> 32222900Snp#include <sys/ioctl.h> 33228594Snp#include <sys/mman.h> 34222900Snp#include <sys/socket.h> 35228594Snp#include <sys/stat.h> 36287297Srodrigc 37287297Srodrigc#include <arpa/inet.h> 38222900Snp#include <net/ethernet.h> 39287297Srodrigc#include <net/sff8472.h> 40222900Snp#include <netinet/in.h> 41222900Snp 42287297Srodrigc#include <ctype.h> 43287297Srodrigc#include <err.h> 44287297Srodrigc#include <errno.h> 45287297Srodrigc#include <fcntl.h> 46287297Srodrigc#include <limits.h> 47287297Srodrigc#include <stdint.h> 48346806Snp#define _WITH_GETLINE 49287297Srodrigc#include <stdio.h> 50287297Srodrigc#include <stdlib.h> 51287297Srodrigc#include <string.h> 52287297Srodrigc#include <unistd.h> 53346805Snp#include <pcap.h> 54287297Srodrigc 55222900Snp#include "t4_ioctl.h" 56339393Snp#include "tcb_common.h" 57222900Snp 58259048Snp#define in_range(val, lo, hi) ( val < 0 || (val <= hi && val >= lo)) 59222974Snp#define max(x, y) ((x) > (y) ? (x) : (y)) 60222974Snp 61222900Snpstatic const char *progname, *nexus; 62253870Snpstatic int chip_id; /* 4 for T4, 5 for T5 */ 63222900Snp 64222900Snpstruct reg_info { 65222900Snp const char *name; 66222900Snp uint32_t addr; 67222900Snp uint32_t len; 68222900Snp}; 69222900Snp 70222900Snpstruct mod_regs { 71222900Snp const char *name; 72222900Snp const struct reg_info *ri; 73222900Snp}; 74222900Snp 75222974Snpstruct field_desc { 76222974Snp const char *name; /* Field name */ 77222974Snp unsigned short start; /* Start bit position */ 78222974Snp unsigned short end; /* End bit position */ 79222974Snp unsigned char shift; /* # of low order bits omitted and implicitly 0 */ 80222974Snp unsigned char hex; /* Print field in hex instead of decimal */ 81222974Snp unsigned char islog2; /* Field contains the base-2 log of the value */ 82222974Snp}; 83222974Snp 84222900Snp#include "reg_defs_t4.c" 85296471Snp#include "reg_defs_t5.c" 86296471Snp#include "reg_defs_t6.c" 87222900Snp#include "reg_defs_t4vf.c" 88222900Snp 89222900Snpstatic void 90222900Snpusage(FILE *fp) 91222900Snp{ 92222900Snp fprintf(fp, "Usage: %s <nexus> [operation]\n", progname); 93222900Snp fprintf(fp, 94241416Snp "\tclearstats <port> clear port statistics\n" 95222974Snp "\tcontext <type> <id> show an SGE context\n" 96330307Snp "\tdumpstate <dump.bin> dump chip state\n" 97222900Snp "\tfilter <idx> [<param> <val>] ... set a filter\n" 98222900Snp "\tfilter <idx> delete|clear delete a filter\n" 99222900Snp "\tfilter list list all filters\n" 100222900Snp "\tfilter mode [<match>] ... get/set global filter mode\n" 101241401Snp "\ti2c <port> <devaddr> <addr> [<len>] read from i2c device\n" 102330310Snp "\tloadboot <bi.bin> [pf|offset <val>] install boot image\n" 103330310Snp "\tloadboot clear [pf|offset <val>] remove boot image\n" 104330310Snp "\tloadboot-cfg <bc.bin> install boot config\n" 105330310Snp "\tloadboot-cfg clear remove boot config\n" 106306823Snp "\tloadcfg <fw-config.txt> install configuration file\n" 107306823Snp "\tloadcfg clear remove configuration file\n" 108228594Snp "\tloadfw <fw-image.bin> install firmware\n" 109228594Snp "\tmemdump <addr> <len> dump a memory range\n" 110269106Snp "\tmodinfo <port> [raw] optics/cable information\n" 111346805Snp "\tpolicy <policy.txt> install offload policy\n" 112346805Snp "\tpolicy clear remove offload policy\n" 113222900Snp "\treg <address>[=<val>] read/write register\n" 114222900Snp "\treg64 <address>[=<val>] read/write 64 bit register\n" 115222900Snp "\tregdump [<module>] ... dump registers\n" 116259048Snp "\tsched-class params <param> <val> .. configure TX scheduler class\n" 117259048Snp "\tsched-queue <port> <queue> <class> bind NIC queues to TX Scheduling class\n" 118222900Snp "\tstdio interactive mode\n" 119228594Snp "\ttcb <tid> read TCB\n" 120259048Snp "\ttracer <idx> tx<n>|rx<n> set and enable a tracer\n" 121253691Snp "\ttracer <idx> disable|enable disable or enable a tracer\n" 122253691Snp "\ttracer list list all tracers\n" 123222900Snp ); 124222900Snp} 125222900Snp 126222900Snpstatic inline unsigned int 127222900Snpget_card_vers(unsigned int version) 128222900Snp{ 129222900Snp return (version & 0x3ff); 130222900Snp} 131222900Snp 132222900Snpstatic int 133222900Snpreal_doit(unsigned long cmd, void *data, const char *cmdstr) 134222900Snp{ 135222900Snp static int fd = -1; 136222900Snp int rc = 0; 137222900Snp 138222900Snp if (fd == -1) { 139222900Snp char buf[64]; 140222900Snp 141222900Snp snprintf(buf, sizeof(buf), "/dev/%s", nexus); 142222900Snp if ((fd = open(buf, O_RDWR)) < 0) { 143222900Snp warn("open(%s)", nexus); 144222900Snp rc = errno; 145222900Snp return (rc); 146222900Snp } 147253870Snp chip_id = nexus[1] - '0'; 148222900Snp } 149222900Snp 150222900Snp rc = ioctl(fd, cmd, data); 151222900Snp if (rc < 0) { 152222900Snp warn("%s", cmdstr); 153222900Snp rc = errno; 154222900Snp } 155222900Snp 156222900Snp return (rc); 157222900Snp} 158222900Snp#define doit(x, y) real_doit(x, y, #x) 159222900Snp 160222900Snpstatic char * 161222900Snpstr_to_number(const char *s, long *val, long long *vall) 162222900Snp{ 163222900Snp char *p; 164222900Snp 165222900Snp if (vall) 166222900Snp *vall = strtoll(s, &p, 0); 167222900Snp else if (val) 168222900Snp *val = strtol(s, &p, 0); 169222900Snp else 170222900Snp p = NULL; 171222900Snp 172222900Snp return (p); 173222900Snp} 174222900Snp 175222900Snpstatic int 176222900Snpread_reg(long addr, int size, long long *val) 177222900Snp{ 178222900Snp struct t4_reg reg; 179222900Snp int rc; 180222900Snp 181222900Snp reg.addr = (uint32_t) addr; 182222900Snp reg.size = (uint32_t) size; 183222900Snp reg.val = 0; 184222900Snp 185222900Snp rc = doit(CHELSIO_T4_GETREG, ®); 186222900Snp 187222900Snp *val = reg.val; 188222900Snp 189222900Snp return (rc); 190222900Snp} 191222900Snp 192222900Snpstatic int 193222900Snpwrite_reg(long addr, int size, long long val) 194222900Snp{ 195222900Snp struct t4_reg reg; 196222900Snp 197222900Snp reg.addr = (uint32_t) addr; 198222900Snp reg.size = (uint32_t) size; 199222900Snp reg.val = (uint64_t) val; 200222900Snp 201222900Snp return doit(CHELSIO_T4_SETREG, ®); 202222900Snp} 203222900Snp 204222900Snpstatic int 205222900Snpregister_io(int argc, const char *argv[], int size) 206222900Snp{ 207222900Snp char *p, *v; 208222900Snp long addr; 209222900Snp long long val; 210222900Snp int w = 0, rc; 211222900Snp 212222900Snp if (argc == 1) { 213222900Snp /* <reg> OR <reg>=<value> */ 214222900Snp 215222900Snp p = str_to_number(argv[0], &addr, NULL); 216222900Snp if (*p) { 217222900Snp if (*p != '=') { 218222900Snp warnx("invalid register \"%s\"", argv[0]); 219222900Snp return (EINVAL); 220222900Snp } 221222900Snp 222222900Snp w = 1; 223222900Snp v = p + 1; 224222900Snp p = str_to_number(v, NULL, &val); 225222900Snp 226222900Snp if (*p) { 227222900Snp warnx("invalid value \"%s\"", v); 228222900Snp return (EINVAL); 229222900Snp } 230222900Snp } 231222900Snp 232222900Snp } else if (argc == 2) { 233222900Snp /* <reg> <value> */ 234222900Snp 235222900Snp w = 1; 236222900Snp 237222900Snp p = str_to_number(argv[0], &addr, NULL); 238222900Snp if (*p) { 239222900Snp warnx("invalid register \"%s\"", argv[0]); 240222900Snp return (EINVAL); 241222900Snp } 242222900Snp 243222900Snp p = str_to_number(argv[1], NULL, &val); 244222900Snp if (*p) { 245222900Snp warnx("invalid value \"%s\"", argv[1]); 246222900Snp return (EINVAL); 247222900Snp } 248222900Snp } else { 249222900Snp warnx("reg: invalid number of arguments (%d)", argc); 250222900Snp return (EINVAL); 251222900Snp } 252222900Snp 253222900Snp if (w) 254222900Snp rc = write_reg(addr, size, val); 255222900Snp else { 256222900Snp rc = read_reg(addr, size, &val); 257222900Snp if (rc == 0) 258222900Snp printf("0x%llx [%llu]\n", val, val); 259222900Snp } 260222900Snp 261222900Snp return (rc); 262222900Snp} 263222900Snp 264222900Snpstatic inline uint32_t 265222900Snpxtract(uint32_t val, int shift, int len) 266222900Snp{ 267222900Snp return (val >> shift) & ((1 << len) - 1); 268222900Snp} 269222900Snp 270222900Snpstatic int 271222900Snpdump_block_regs(const struct reg_info *reg_array, const uint32_t *regs) 272222900Snp{ 273222900Snp uint32_t reg_val = 0; 274222900Snp 275222900Snp for ( ; reg_array->name; ++reg_array) 276222900Snp if (!reg_array->len) { 277222900Snp reg_val = regs[reg_array->addr / 4]; 278222900Snp printf("[%#7x] %-47s %#-10x %u\n", reg_array->addr, 279222900Snp reg_array->name, reg_val, reg_val); 280222900Snp } else { 281222900Snp uint32_t v = xtract(reg_val, reg_array->addr, 282222900Snp reg_array->len); 283222900Snp 284222900Snp printf(" %*u:%u %-47s %#-10x %u\n", 285222900Snp reg_array->addr < 10 ? 3 : 2, 286222900Snp reg_array->addr + reg_array->len - 1, 287222900Snp reg_array->addr, reg_array->name, v, v); 288222900Snp } 289222900Snp 290222900Snp return (1); 291222900Snp} 292222900Snp 293222900Snpstatic int 294222900Snpdump_regs_table(int argc, const char *argv[], const uint32_t *regs, 295222900Snp const struct mod_regs *modtab, int nmodules) 296222900Snp{ 297222900Snp int i, j, match; 298222900Snp 299222900Snp for (i = 0; i < argc; i++) { 300222900Snp for (j = 0; j < nmodules; j++) { 301222900Snp if (!strcmp(argv[i], modtab[j].name)) 302222900Snp break; 303222900Snp } 304222900Snp 305222900Snp if (j == nmodules) { 306222900Snp warnx("invalid register block \"%s\"", argv[i]); 307222900Snp fprintf(stderr, "\nAvailable blocks:"); 308222900Snp for ( ; nmodules; nmodules--, modtab++) 309222900Snp fprintf(stderr, " %s", modtab->name); 310222900Snp fprintf(stderr, "\n"); 311222900Snp return (EINVAL); 312222900Snp } 313222900Snp } 314222900Snp 315222900Snp for ( ; nmodules; nmodules--, modtab++) { 316222900Snp 317222900Snp match = argc == 0 ? 1 : 0; 318222900Snp for (i = 0; !match && i < argc; i++) { 319222900Snp if (!strcmp(argv[i], modtab->name)) 320222900Snp match = 1; 321222900Snp } 322222900Snp 323222900Snp if (match) 324222900Snp dump_block_regs(modtab->ri, regs); 325222900Snp } 326222900Snp 327222900Snp return (0); 328222900Snp} 329222900Snp 330222900Snp#define T4_MODREGS(name) { #name, t4_##name##_regs } 331222900Snpstatic int 332222900Snpdump_regs_t4(int argc, const char *argv[], const uint32_t *regs) 333222900Snp{ 334222900Snp static struct mod_regs t4_mod[] = { 335222900Snp T4_MODREGS(sge), 336222900Snp { "pci", t4_pcie_regs }, 337222900Snp T4_MODREGS(dbg), 338222900Snp T4_MODREGS(mc), 339222900Snp T4_MODREGS(ma), 340222900Snp { "edc0", t4_edc_0_regs }, 341222900Snp { "edc1", t4_edc_1_regs }, 342259048Snp T4_MODREGS(cim), 343222900Snp T4_MODREGS(tp), 344222900Snp T4_MODREGS(ulp_rx), 345222900Snp T4_MODREGS(ulp_tx), 346222900Snp { "pmrx", t4_pm_rx_regs }, 347222900Snp { "pmtx", t4_pm_tx_regs }, 348222900Snp T4_MODREGS(mps), 349222900Snp { "cplsw", t4_cpl_switch_regs }, 350222900Snp T4_MODREGS(smb), 351222900Snp { "i2c", t4_i2cm_regs }, 352222900Snp T4_MODREGS(mi), 353222900Snp T4_MODREGS(uart), 354259048Snp T4_MODREGS(pmu), 355222900Snp T4_MODREGS(sf), 356222900Snp T4_MODREGS(pl), 357222900Snp T4_MODREGS(le), 358222900Snp T4_MODREGS(ncsi), 359222900Snp T4_MODREGS(xgmac) 360222900Snp }; 361222900Snp 362287297Srodrigc return dump_regs_table(argc, argv, regs, t4_mod, nitems(t4_mod)); 363222900Snp} 364222900Snp#undef T4_MODREGS 365222900Snp 366248925Snp#define T5_MODREGS(name) { #name, t5_##name##_regs } 367222900Snpstatic int 368248925Snpdump_regs_t5(int argc, const char *argv[], const uint32_t *regs) 369248925Snp{ 370248925Snp static struct mod_regs t5_mod[] = { 371248925Snp T5_MODREGS(sge), 372248925Snp { "pci", t5_pcie_regs }, 373248925Snp T5_MODREGS(dbg), 374248925Snp { "mc0", t5_mc_0_regs }, 375248925Snp { "mc1", t5_mc_1_regs }, 376248925Snp T5_MODREGS(ma), 377248925Snp { "edc0", t5_edc_t50_regs }, 378248925Snp { "edc1", t5_edc_t51_regs }, 379248925Snp T5_MODREGS(cim), 380248925Snp T5_MODREGS(tp), 381248925Snp { "ulprx", t5_ulp_rx_regs }, 382248925Snp { "ulptx", t5_ulp_tx_regs }, 383248925Snp { "pmrx", t5_pm_rx_regs }, 384248925Snp { "pmtx", t5_pm_tx_regs }, 385248925Snp T5_MODREGS(mps), 386248925Snp { "cplsw", t5_cpl_switch_regs }, 387248925Snp T5_MODREGS(smb), 388248925Snp { "i2c", t5_i2cm_regs }, 389248925Snp T5_MODREGS(mi), 390248925Snp T5_MODREGS(uart), 391248925Snp T5_MODREGS(pmu), 392248925Snp T5_MODREGS(sf), 393248925Snp T5_MODREGS(pl), 394248925Snp T5_MODREGS(le), 395248925Snp T5_MODREGS(ncsi), 396248925Snp T5_MODREGS(mac), 397248925Snp { "hma", t5_hma_t5_regs } 398248925Snp }; 399248925Snp 400287297Srodrigc return dump_regs_table(argc, argv, regs, t5_mod, nitems(t5_mod)); 401248925Snp} 402248925Snp#undef T5_MODREGS 403248925Snp 404296471Snp#define T6_MODREGS(name) { #name, t6_##name##_regs } 405248925Snpstatic int 406296471Snpdump_regs_t6(int argc, const char *argv[], const uint32_t *regs) 407296471Snp{ 408296471Snp static struct mod_regs t6_mod[] = { 409296471Snp T6_MODREGS(sge), 410296471Snp { "pci", t6_pcie_regs }, 411296471Snp T6_MODREGS(dbg), 412296471Snp { "mc0", t6_mc_0_regs }, 413296471Snp T6_MODREGS(ma), 414296471Snp { "edc0", t6_edc_t60_regs }, 415296471Snp { "edc1", t6_edc_t61_regs }, 416296471Snp T6_MODREGS(cim), 417296471Snp T6_MODREGS(tp), 418296471Snp { "ulprx", t6_ulp_rx_regs }, 419296471Snp { "ulptx", t6_ulp_tx_regs }, 420296471Snp { "pmrx", t6_pm_rx_regs }, 421296471Snp { "pmtx", t6_pm_tx_regs }, 422296471Snp T6_MODREGS(mps), 423296471Snp { "cplsw", t6_cpl_switch_regs }, 424296471Snp T6_MODREGS(smb), 425296471Snp { "i2c", t6_i2cm_regs }, 426296471Snp T6_MODREGS(mi), 427296471Snp T6_MODREGS(uart), 428296471Snp T6_MODREGS(pmu), 429296471Snp T6_MODREGS(sf), 430296471Snp T6_MODREGS(pl), 431296471Snp T6_MODREGS(le), 432296471Snp T6_MODREGS(ncsi), 433296471Snp T6_MODREGS(mac), 434296471Snp { "hma", t6_hma_t6_regs } 435296471Snp }; 436296471Snp 437296471Snp return dump_regs_table(argc, argv, regs, t6_mod, nitems(t6_mod)); 438296471Snp} 439296471Snp#undef T6_MODREGS 440296471Snp 441296471Snpstatic int 442296471Snpdump_regs_t4vf(int argc, const char *argv[], const uint32_t *regs) 443296471Snp{ 444296471Snp static struct mod_regs t4vf_mod[] = { 445296471Snp { "sge", t4vf_sge_regs }, 446296471Snp { "mps", t4vf_mps_regs }, 447296471Snp { "pl", t4vf_pl_regs }, 448296471Snp { "mbdata", t4vf_mbdata_regs }, 449296471Snp { "cim", t4vf_cim_regs }, 450296471Snp }; 451296471Snp 452296471Snp return dump_regs_table(argc, argv, regs, t4vf_mod, nitems(t4vf_mod)); 453296471Snp} 454296471Snp 455296471Snpstatic int 456296471Snpdump_regs_t5vf(int argc, const char *argv[], const uint32_t *regs) 457296471Snp{ 458296471Snp static struct mod_regs t5vf_mod[] = { 459296471Snp { "sge", t5vf_sge_regs }, 460296471Snp { "mps", t4vf_mps_regs }, 461296471Snp { "pl", t5vf_pl_regs }, 462296471Snp { "mbdata", t4vf_mbdata_regs }, 463296471Snp { "cim", t4vf_cim_regs }, 464296471Snp }; 465296471Snp 466296471Snp return dump_regs_table(argc, argv, regs, t5vf_mod, nitems(t5vf_mod)); 467296471Snp} 468296471Snp 469296471Snpstatic int 470296471Snpdump_regs_t6vf(int argc, const char *argv[], const uint32_t *regs) 471296471Snp{ 472296471Snp static struct mod_regs t6vf_mod[] = { 473296471Snp { "sge", t5vf_sge_regs }, 474296471Snp { "mps", t4vf_mps_regs }, 475296471Snp { "pl", t6vf_pl_regs }, 476296471Snp { "mbdata", t4vf_mbdata_regs }, 477296471Snp { "cim", t4vf_cim_regs }, 478296471Snp }; 479296471Snp 480296471Snp return dump_regs_table(argc, argv, regs, t6vf_mod, nitems(t6vf_mod)); 481296471Snp} 482296471Snp 483296471Snpstatic int 484222900Snpdump_regs(int argc, const char *argv[]) 485222900Snp{ 486248925Snp int vers, revision, rc; 487222900Snp struct t4_regdump regs; 488248925Snp uint32_t len; 489222900Snp 490248925Snp len = max(T4_REGDUMP_SIZE, T5_REGDUMP_SIZE); 491248925Snp regs.data = calloc(1, len); 492222900Snp if (regs.data == NULL) { 493222900Snp warnc(ENOMEM, "regdump"); 494222900Snp return (ENOMEM); 495222900Snp } 496222900Snp 497248925Snp regs.len = len; 498222900Snp rc = doit(CHELSIO_T4_REGDUMP, ®s); 499222900Snp if (rc != 0) 500222900Snp return (rc); 501222900Snp 502222900Snp vers = get_card_vers(regs.version); 503222900Snp revision = (regs.version >> 10) & 0x3f; 504222900Snp 505222900Snp if (vers == 4) { 506222900Snp if (revision == 0x3f) 507222900Snp rc = dump_regs_t4vf(argc, argv, regs.data); 508222900Snp else 509222900Snp rc = dump_regs_t4(argc, argv, regs.data); 510296471Snp } else if (vers == 5) { 511296471Snp if (revision == 0x3f) 512296471Snp rc = dump_regs_t5vf(argc, argv, regs.data); 513296471Snp else 514296471Snp rc = dump_regs_t5(argc, argv, regs.data); 515296471Snp } else if (vers == 6) { 516296471Snp if (revision == 0x3f) 517296471Snp rc = dump_regs_t6vf(argc, argv, regs.data); 518296471Snp else 519296471Snp rc = dump_regs_t6(argc, argv, regs.data); 520296471Snp } else { 521248925Snp warnx("%s (type %d, rev %d) is not a known card.", 522222900Snp nexus, vers, revision); 523222900Snp return (ENOTSUP); 524222900Snp } 525222900Snp 526222900Snp free(regs.data); 527222900Snp return (rc); 528222900Snp} 529222900Snp 530222900Snpstatic void 531222900Snpdo_show_info_header(uint32_t mode) 532222900Snp{ 533222900Snp uint32_t i; 534222900Snp 535296236Snp printf("%4s %8s", "Idx", "Hits"); 536222900Snp for (i = T4_FILTER_FCoE; i <= T4_FILTER_IP_FRAGMENT; i <<= 1) { 537222900Snp switch (mode & i) { 538222900Snp case T4_FILTER_FCoE: 539296236Snp printf(" FCoE"); 540222900Snp break; 541222900Snp 542222900Snp case T4_FILTER_PORT: 543296236Snp printf(" Port"); 544222900Snp break; 545222900Snp 546228561Snp case T4_FILTER_VNIC: 547296481Snp if (mode & T4_FILTER_IC_VNIC) 548296481Snp printf(" VFvld:PF:VF"); 549296481Snp else 550296481Snp printf(" vld:oVLAN"); 551222900Snp break; 552222900Snp 553228561Snp case T4_FILTER_VLAN: 554296236Snp printf(" vld:VLAN"); 555222900Snp break; 556222900Snp 557222900Snp case T4_FILTER_IP_TOS: 558296236Snp printf(" TOS"); 559222900Snp break; 560222900Snp 561222900Snp case T4_FILTER_IP_PROTO: 562296236Snp printf(" Prot"); 563222900Snp break; 564222900Snp 565222900Snp case T4_FILTER_ETH_TYPE: 566296236Snp printf(" EthType"); 567222900Snp break; 568222900Snp 569222900Snp case T4_FILTER_MAC_IDX: 570296236Snp printf(" MACIdx"); 571222900Snp break; 572222900Snp 573222900Snp case T4_FILTER_MPS_HIT_TYPE: 574296236Snp printf(" MPS"); 575222900Snp break; 576222900Snp 577222900Snp case T4_FILTER_IP_FRAGMENT: 578296236Snp printf(" Frag"); 579222900Snp break; 580222900Snp 581222900Snp default: 582222900Snp /* compressed filter field not enabled */ 583222900Snp break; 584222900Snp } 585222900Snp } 586222900Snp printf(" %20s %20s %9s %9s %s\n", 587222900Snp "DIP", "SIP", "DPORT", "SPORT", "Action"); 588222900Snp} 589222900Snp 590222900Snp/* 591222900Snp * Parse an argument sub-vector as a { <parameter name> <value>[:<mask>] } 592222900Snp * ordered tuple. If the parameter name in the argument sub-vector does not 593222900Snp * match the passed in parameter name, then a zero is returned for the 594222900Snp * function and no parsing is performed. If there is a match, then the value 595222900Snp * and optional mask are parsed and returned in the provided return value 596222900Snp * pointers. If no optional mask is specified, then a default mask of all 1s 597222900Snp * will be returned. 598222900Snp * 599222900Snp * An error in parsing the value[:mask] will result in an error message and 600222900Snp * program termination. 601222900Snp */ 602222900Snpstatic int 603222900Snpparse_val_mask(const char *param, const char *args[], uint32_t *val, 604222900Snp uint32_t *mask) 605222900Snp{ 606222900Snp char *p; 607222900Snp 608222900Snp if (strcmp(param, args[0]) != 0) 609222900Snp return (EINVAL); 610222900Snp 611222900Snp *val = strtoul(args[1], &p, 0); 612222900Snp if (p > args[1]) { 613222900Snp if (p[0] == 0) { 614222900Snp *mask = ~0; 615222900Snp return (0); 616222900Snp } 617222900Snp 618222900Snp if (p[0] == ':' && p[1] != 0) { 619222900Snp *mask = strtoul(p+1, &p, 0); 620222900Snp if (p[0] == 0) 621222900Snp return (0); 622222900Snp } 623222900Snp } 624222900Snp 625222900Snp warnx("parameter \"%s\" has bad \"value[:mask]\" %s", 626222900Snp args[0], args[1]); 627222900Snp 628222900Snp return (EINVAL); 629222900Snp} 630222900Snp 631222900Snp/* 632222900Snp * Parse an argument sub-vector as a { <parameter name> <addr>[/<mask>] } 633222900Snp * ordered tuple. If the parameter name in the argument sub-vector does not 634222900Snp * match the passed in parameter name, then a zero is returned for the 635222900Snp * function and no parsing is performed. If there is a match, then the value 636222900Snp * and optional mask are parsed and returned in the provided return value 637222900Snp * pointers. If no optional mask is specified, then a default mask of all 1s 638222900Snp * will be returned. 639222900Snp * 640222900Snp * The value return parameter "afp" is used to specify the expected address 641222900Snp * family -- IPv4 or IPv6 -- of the address[/mask] and return its actual 642222900Snp * format. A passed in value of AF_UNSPEC indicates that either IPv4 or IPv6 643222900Snp * is acceptable; AF_INET means that only IPv4 addresses are acceptable; and 644222900Snp * AF_INET6 means that only IPv6 are acceptable. AF_INET is returned for IPv4 645222900Snp * and AF_INET6 for IPv6 addresses, respectively. IPv4 address/mask pairs are 646222900Snp * returned in the first four bytes of the address and mask return values with 647222900Snp * the address A.B.C.D returned with { A, B, C, D } returned in addresses { 0, 648222900Snp * 1, 2, 3}, respectively. 649222900Snp * 650222900Snp * An error in parsing the value[:mask] will result in an error message and 651222900Snp * program termination. 652222900Snp */ 653222900Snpstatic int 654222900Snpparse_ipaddr(const char *param, const char *args[], int *afp, uint8_t addr[], 655222900Snp uint8_t mask[]) 656222900Snp{ 657222900Snp const char *colon, *afn; 658222900Snp char *slash; 659222900Snp uint8_t *m; 660222900Snp int af, ret; 661222900Snp unsigned int masksize; 662222900Snp 663222900Snp /* 664222900Snp * Is this our parameter? 665222900Snp */ 666222900Snp if (strcmp(param, args[0]) != 0) 667222900Snp return (EINVAL); 668222900Snp 669222900Snp /* 670222900Snp * Fundamental IPv4 versus IPv6 selection. 671222900Snp */ 672222900Snp colon = strchr(args[1], ':'); 673222900Snp if (!colon) { 674222900Snp afn = "IPv4"; 675222900Snp af = AF_INET; 676222900Snp masksize = 32; 677222900Snp } else { 678222900Snp afn = "IPv6"; 679222900Snp af = AF_INET6; 680222900Snp masksize = 128; 681222900Snp } 682222900Snp if (*afp == AF_UNSPEC) 683222900Snp *afp = af; 684222900Snp else if (*afp != af) { 685222900Snp warnx("address %s is not of expected family %s", 686222900Snp args[1], *afp == AF_INET ? "IP" : "IPv6"); 687222900Snp return (EINVAL); 688222900Snp } 689222900Snp 690222900Snp /* 691222900Snp * Parse address (temporarily stripping off any "/mask" 692222900Snp * specification). 693222900Snp */ 694222900Snp slash = strchr(args[1], '/'); 695222900Snp if (slash) 696222900Snp *slash = 0; 697222900Snp ret = inet_pton(af, args[1], addr); 698222900Snp if (slash) 699222900Snp *slash = '/'; 700222900Snp if (ret <= 0) { 701222900Snp warnx("Cannot parse %s %s address %s", param, afn, args[1]); 702222900Snp return (EINVAL); 703222900Snp } 704222900Snp 705222900Snp /* 706222900Snp * Parse optional mask specification. 707222900Snp */ 708222900Snp if (slash) { 709222900Snp char *p; 710222900Snp unsigned int prefix = strtoul(slash + 1, &p, 10); 711222900Snp 712222900Snp if (p == slash + 1) { 713222900Snp warnx("missing address prefix for %s", param); 714222900Snp return (EINVAL); 715222900Snp } 716222900Snp if (*p) { 717222900Snp warnx("%s is not a valid address prefix", slash + 1); 718222900Snp return (EINVAL); 719222900Snp } 720222900Snp if (prefix > masksize) { 721222900Snp warnx("prefix %u is too long for an %s address", 722222900Snp prefix, afn); 723222900Snp return (EINVAL); 724222900Snp } 725222900Snp memset(mask, 0, masksize / 8); 726222900Snp masksize = prefix; 727222900Snp } 728222900Snp 729222900Snp /* 730222900Snp * Fill in mask. 731222900Snp */ 732222900Snp for (m = mask; masksize >= 8; m++, masksize -= 8) 733222900Snp *m = ~0; 734222900Snp if (masksize) 735222900Snp *m = ~0 << (8 - masksize); 736222900Snp 737222900Snp return (0); 738222900Snp} 739222900Snp 740222900Snp/* 741222900Snp * Parse an argument sub-vector as a { <parameter name> <value> } ordered 742222900Snp * tuple. If the parameter name in the argument sub-vector does not match the 743222900Snp * passed in parameter name, then a zero is returned for the function and no 744222900Snp * parsing is performed. If there is a match, then the value is parsed and 745222900Snp * returned in the provided return value pointer. 746222900Snp */ 747222900Snpstatic int 748222900Snpparse_val(const char *param, const char *args[], uint32_t *val) 749222900Snp{ 750222900Snp char *p; 751222900Snp 752222900Snp if (strcmp(param, args[0]) != 0) 753222900Snp return (EINVAL); 754222900Snp 755222900Snp *val = strtoul(args[1], &p, 0); 756222900Snp if (p > args[1] && p[0] == 0) 757222900Snp return (0); 758222900Snp 759222900Snp warnx("parameter \"%s\" has bad \"value\" %s", args[0], args[1]); 760222900Snp return (EINVAL); 761222900Snp} 762222900Snp 763222900Snpstatic void 764222900Snpfilters_show_ipaddr(int type, uint8_t *addr, uint8_t *addrm) 765222900Snp{ 766222900Snp int noctets, octet; 767222900Snp 768222900Snp printf(" "); 769222900Snp if (type == 0) { 770222900Snp noctets = 4; 771222900Snp printf("%3s", " "); 772222900Snp } else 773222900Snp noctets = 16; 774222900Snp 775222900Snp for (octet = 0; octet < noctets; octet++) 776222900Snp printf("%02x", addr[octet]); 777222900Snp printf("/"); 778222900Snp for (octet = 0; octet < noctets; octet++) 779222900Snp printf("%02x", addrm[octet]); 780222900Snp} 781222900Snp 782222900Snpstatic void 783222900Snpdo_show_one_filter_info(struct t4_filter *t, uint32_t mode) 784222900Snp{ 785222900Snp uint32_t i; 786222900Snp 787222900Snp printf("%4d", t->idx); 788222900Snp if (t->hits == UINT64_MAX) 789222900Snp printf(" %8s", "-"); 790222900Snp else 791222900Snp printf(" %8ju", t->hits); 792222900Snp 793222900Snp /* 794222900Snp * Compressed header portion of filter. 795222900Snp */ 796222900Snp for (i = T4_FILTER_FCoE; i <= T4_FILTER_IP_FRAGMENT; i <<= 1) { 797222900Snp switch (mode & i) { 798222900Snp case T4_FILTER_FCoE: 799222900Snp printf(" %1d/%1d", t->fs.val.fcoe, t->fs.mask.fcoe); 800222900Snp break; 801222900Snp 802222900Snp case T4_FILTER_PORT: 803222900Snp printf(" %1d/%1d", t->fs.val.iport, t->fs.mask.iport); 804222900Snp break; 805222900Snp 806228561Snp case T4_FILTER_VNIC: 807296481Snp if (mode & T4_FILTER_IC_VNIC) { 808296481Snp printf(" %1d:%1x:%02x/%1d:%1x:%02x", 809296481Snp t->fs.val.pfvf_vld, 810296481Snp (t->fs.val.vnic >> 13) & 0x7, 811296481Snp t->fs.val.vnic & 0x1fff, 812296481Snp t->fs.mask.pfvf_vld, 813296481Snp (t->fs.mask.vnic >> 13) & 0x7, 814296481Snp t->fs.mask.vnic & 0x1fff); 815296481Snp } else { 816296481Snp printf(" %1d:%04x/%1d:%04x", 817296481Snp t->fs.val.ovlan_vld, t->fs.val.vnic, 818296481Snp t->fs.mask.ovlan_vld, t->fs.mask.vnic); 819296481Snp } 820222900Snp break; 821222900Snp 822228561Snp case T4_FILTER_VLAN: 823222900Snp printf(" %1d:%04x/%1d:%04x", 824228561Snp t->fs.val.vlan_vld, t->fs.val.vlan, 825228561Snp t->fs.mask.vlan_vld, t->fs.mask.vlan); 826222900Snp break; 827222900Snp 828222900Snp case T4_FILTER_IP_TOS: 829222900Snp printf(" %02x/%02x", t->fs.val.tos, t->fs.mask.tos); 830222900Snp break; 831222900Snp 832222900Snp case T4_FILTER_IP_PROTO: 833222900Snp printf(" %02x/%02x", t->fs.val.proto, t->fs.mask.proto); 834222900Snp break; 835222900Snp 836222900Snp case T4_FILTER_ETH_TYPE: 837222900Snp printf(" %04x/%04x", t->fs.val.ethtype, 838222900Snp t->fs.mask.ethtype); 839222900Snp break; 840222900Snp 841222900Snp case T4_FILTER_MAC_IDX: 842222900Snp printf(" %03x/%03x", t->fs.val.macidx, 843222900Snp t->fs.mask.macidx); 844222900Snp break; 845222900Snp 846222900Snp case T4_FILTER_MPS_HIT_TYPE: 847222900Snp printf(" %1x/%1x", t->fs.val.matchtype, 848222900Snp t->fs.mask.matchtype); 849222900Snp break; 850222900Snp 851222900Snp case T4_FILTER_IP_FRAGMENT: 852222900Snp printf(" %1d/%1d", t->fs.val.frag, t->fs.mask.frag); 853222900Snp break; 854222900Snp 855222900Snp default: 856222900Snp /* compressed filter field not enabled */ 857222900Snp break; 858222900Snp } 859222900Snp } 860222900Snp 861222900Snp /* 862222900Snp * Fixed portion of filter. 863222900Snp */ 864222900Snp filters_show_ipaddr(t->fs.type, t->fs.val.dip, t->fs.mask.dip); 865222900Snp filters_show_ipaddr(t->fs.type, t->fs.val.sip, t->fs.mask.sip); 866222900Snp printf(" %04x/%04x %04x/%04x", 867222900Snp t->fs.val.dport, t->fs.mask.dport, 868222900Snp t->fs.val.sport, t->fs.mask.sport); 869222900Snp 870222900Snp /* 871222900Snp * Variable length filter action. 872222900Snp */ 873222900Snp if (t->fs.action == FILTER_DROP) 874222900Snp printf(" Drop"); 875222900Snp else if (t->fs.action == FILTER_SWITCH) { 876222900Snp printf(" Switch: port=%d", t->fs.eport); 877222900Snp if (t->fs.newdmac) 878222900Snp printf( 879222900Snp ", dmac=%02x:%02x:%02x:%02x:%02x:%02x " 880222900Snp ", l2tidx=%d", 881222900Snp t->fs.dmac[0], t->fs.dmac[1], 882222900Snp t->fs.dmac[2], t->fs.dmac[3], 883222900Snp t->fs.dmac[4], t->fs.dmac[5], 884222900Snp t->l2tidx); 885222900Snp if (t->fs.newsmac) 886222900Snp printf( 887222900Snp ", smac=%02x:%02x:%02x:%02x:%02x:%02x " 888222900Snp ", smtidx=%d", 889222900Snp t->fs.smac[0], t->fs.smac[1], 890222900Snp t->fs.smac[2], t->fs.smac[3], 891222900Snp t->fs.smac[4], t->fs.smac[5], 892222900Snp t->smtidx); 893222900Snp if (t->fs.newvlan == VLAN_REMOVE) 894222900Snp printf(", vlan=none"); 895222900Snp else if (t->fs.newvlan == VLAN_INSERT) 896222900Snp printf(", vlan=insert(%x)", t->fs.vlan); 897222900Snp else if (t->fs.newvlan == VLAN_REWRITE) 898222900Snp printf(", vlan=rewrite(%x)", t->fs.vlan); 899222900Snp } else { 900222900Snp printf(" Pass: Q="); 901222900Snp if (t->fs.dirsteer == 0) { 902222900Snp printf("RSS"); 903222900Snp if (t->fs.maskhash) 904222900Snp printf("(TCB=hash)"); 905222900Snp } else { 906222900Snp printf("%d", t->fs.iq); 907222900Snp if (t->fs.dirsteerhash == 0) 908222900Snp printf("(QID)"); 909222900Snp else 910222900Snp printf("(hash)"); 911222900Snp } 912222900Snp } 913222900Snp if (t->fs.prio) 914222900Snp printf(" Prio"); 915222900Snp if (t->fs.rpttid) 916222900Snp printf(" RptTID"); 917222900Snp printf("\n"); 918222900Snp} 919222900Snp 920222900Snpstatic int 921222900Snpshow_filters(void) 922222900Snp{ 923222900Snp uint32_t mode = 0, header = 0; 924222900Snp struct t4_filter t; 925222900Snp int rc; 926222900Snp 927222900Snp /* Get the global filter mode first */ 928222900Snp rc = doit(CHELSIO_T4_GET_FILTER_MODE, &mode); 929222900Snp if (rc != 0) 930222900Snp return (rc); 931222900Snp 932222900Snp t.idx = 0; 933222900Snp for (t.idx = 0; ; t.idx++) { 934222900Snp rc = doit(CHELSIO_T4_GET_FILTER, &t); 935222900Snp if (rc != 0 || t.idx == 0xffffffff) 936222900Snp break; 937222900Snp 938222900Snp if (!header) { 939222900Snp do_show_info_header(mode); 940222900Snp header = 1; 941222900Snp } 942222900Snp do_show_one_filter_info(&t, mode); 943222900Snp }; 944222900Snp 945222900Snp return (rc); 946222900Snp} 947222900Snp 948222900Snpstatic int 949222900Snpget_filter_mode(void) 950222900Snp{ 951222900Snp uint32_t mode = 0; 952222900Snp int rc; 953222900Snp 954222900Snp rc = doit(CHELSIO_T4_GET_FILTER_MODE, &mode); 955222900Snp if (rc != 0) 956222900Snp return (rc); 957222900Snp 958222900Snp if (mode & T4_FILTER_IPv4) 959222900Snp printf("ipv4 "); 960222900Snp 961222900Snp if (mode & T4_FILTER_IPv6) 962222900Snp printf("ipv6 "); 963222900Snp 964222900Snp if (mode & T4_FILTER_IP_SADDR) 965222900Snp printf("sip "); 966296236Snp 967222900Snp if (mode & T4_FILTER_IP_DADDR) 968222900Snp printf("dip "); 969222900Snp 970222900Snp if (mode & T4_FILTER_IP_SPORT) 971222900Snp printf("sport "); 972222900Snp 973222900Snp if (mode & T4_FILTER_IP_DPORT) 974222900Snp printf("dport "); 975222900Snp 976249368Snp if (mode & T4_FILTER_IP_FRAGMENT) 977249368Snp printf("frag "); 978249368Snp 979222900Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 980222900Snp printf("matchtype "); 981222900Snp 982222900Snp if (mode & T4_FILTER_MAC_IDX) 983222900Snp printf("macidx "); 984222900Snp 985222900Snp if (mode & T4_FILTER_ETH_TYPE) 986222900Snp printf("ethtype "); 987222900Snp 988222900Snp if (mode & T4_FILTER_IP_PROTO) 989222900Snp printf("proto "); 990222900Snp 991222900Snp if (mode & T4_FILTER_IP_TOS) 992222900Snp printf("tos "); 993222900Snp 994228561Snp if (mode & T4_FILTER_VLAN) 995228561Snp printf("vlan "); 996222900Snp 997296481Snp if (mode & T4_FILTER_VNIC) { 998296481Snp if (mode & T4_FILTER_IC_VNIC) 999296481Snp printf("vnic_id "); 1000296481Snp else 1001296481Snp printf("ovlan "); 1002296481Snp } 1003222900Snp 1004222900Snp if (mode & T4_FILTER_PORT) 1005222900Snp printf("iport "); 1006222900Snp 1007222900Snp if (mode & T4_FILTER_FCoE) 1008222900Snp printf("fcoe "); 1009222900Snp 1010222900Snp printf("\n"); 1011222900Snp 1012222900Snp return (0); 1013222900Snp} 1014222900Snp 1015222900Snpstatic int 1016222900Snpset_filter_mode(int argc, const char *argv[]) 1017222900Snp{ 1018222900Snp uint32_t mode = 0; 1019296481Snp int vnic = 0, ovlan = 0; 1020222900Snp 1021222900Snp for (; argc; argc--, argv++) { 1022249368Snp if (!strcmp(argv[0], "frag")) 1023249368Snp mode |= T4_FILTER_IP_FRAGMENT; 1024249368Snp 1025222900Snp if (!strcmp(argv[0], "matchtype")) 1026222900Snp mode |= T4_FILTER_MPS_HIT_TYPE; 1027222900Snp 1028222900Snp if (!strcmp(argv[0], "macidx")) 1029222900Snp mode |= T4_FILTER_MAC_IDX; 1030222900Snp 1031222900Snp if (!strcmp(argv[0], "ethtype")) 1032222900Snp mode |= T4_FILTER_ETH_TYPE; 1033222900Snp 1034222900Snp if (!strcmp(argv[0], "proto")) 1035222900Snp mode |= T4_FILTER_IP_PROTO; 1036222900Snp 1037222900Snp if (!strcmp(argv[0], "tos")) 1038222900Snp mode |= T4_FILTER_IP_TOS; 1039222900Snp 1040228561Snp if (!strcmp(argv[0], "vlan")) 1041228561Snp mode |= T4_FILTER_VLAN; 1042222900Snp 1043296481Snp if (!strcmp(argv[0], "ovlan")) { 1044228561Snp mode |= T4_FILTER_VNIC; 1045296481Snp ovlan++; 1046296481Snp } 1047222900Snp 1048296481Snp if (!strcmp(argv[0], "vnic_id")) { 1049296481Snp mode |= T4_FILTER_VNIC; 1050296481Snp mode |= T4_FILTER_IC_VNIC; 1051296481Snp vnic++; 1052296481Snp } 1053296481Snp 1054222900Snp if (!strcmp(argv[0], "iport")) 1055222900Snp mode |= T4_FILTER_PORT; 1056222900Snp 1057222900Snp if (!strcmp(argv[0], "fcoe")) 1058222900Snp mode |= T4_FILTER_FCoE; 1059222900Snp } 1060222900Snp 1061296481Snp if (vnic > 0 && ovlan > 0) { 1062296481Snp warnx("\"vnic_id\" and \"ovlan\" are mutually exclusive."); 1063296481Snp return (EINVAL); 1064296481Snp } 1065296481Snp 1066222900Snp return doit(CHELSIO_T4_SET_FILTER_MODE, &mode); 1067222900Snp} 1068222900Snp 1069222900Snpstatic int 1070222900Snpdel_filter(uint32_t idx) 1071222900Snp{ 1072222900Snp struct t4_filter t; 1073222900Snp 1074222900Snp t.idx = idx; 1075222900Snp 1076222900Snp return doit(CHELSIO_T4_DEL_FILTER, &t); 1077222900Snp} 1078222900Snp 1079222900Snpstatic int 1080222900Snpset_filter(uint32_t idx, int argc, const char *argv[]) 1081222900Snp{ 1082222900Snp int af = AF_UNSPEC, start_arg = 0; 1083222900Snp struct t4_filter t; 1084222900Snp 1085222900Snp if (argc < 2) { 1086222900Snp warnc(EINVAL, "%s", __func__); 1087222900Snp return (EINVAL); 1088222900Snp }; 1089222900Snp bzero(&t, sizeof (t)); 1090222900Snp t.idx = idx; 1091252470Snp t.fs.hitcnts = 1; 1092222900Snp 1093222900Snp for (start_arg = 0; start_arg + 2 <= argc; start_arg += 2) { 1094222900Snp const char **args = &argv[start_arg]; 1095222900Snp uint32_t val, mask; 1096222900Snp 1097222900Snp if (!strcmp(argv[start_arg], "type")) { 1098222900Snp int newaf; 1099222900Snp if (!strcasecmp(argv[start_arg + 1], "ipv4")) 1100222900Snp newaf = AF_INET; 1101222900Snp else if (!strcasecmp(argv[start_arg + 1], "ipv6")) 1102222900Snp newaf = AF_INET6; 1103222900Snp else { 1104222900Snp warnx("invalid type \"%s\"; " 1105222900Snp "must be one of \"ipv4\" or \"ipv6\"", 1106222900Snp argv[start_arg + 1]); 1107222900Snp return (EINVAL); 1108222900Snp } 1109222900Snp 1110222900Snp if (af != AF_UNSPEC && af != newaf) { 1111222900Snp warnx("conflicting IPv4/IPv6 specifications."); 1112222900Snp return (EINVAL); 1113222900Snp } 1114222900Snp af = newaf; 1115222900Snp } else if (!parse_val_mask("fcoe", args, &val, &mask)) { 1116222900Snp t.fs.val.fcoe = val; 1117222900Snp t.fs.mask.fcoe = mask; 1118222900Snp } else if (!parse_val_mask("iport", args, &val, &mask)) { 1119222900Snp t.fs.val.iport = val; 1120222900Snp t.fs.mask.iport = mask; 1121222900Snp } else if (!parse_val_mask("ovlan", args, &val, &mask)) { 1122228561Snp t.fs.val.vnic = val; 1123228561Snp t.fs.mask.vnic = mask; 1124296481Snp t.fs.val.ovlan_vld = 1; 1125296481Snp t.fs.mask.ovlan_vld = 1; 1126245520Snp } else if (!parse_val_mask("ivlan", args, &val, &mask)) { 1127228561Snp t.fs.val.vlan = val; 1128228561Snp t.fs.mask.vlan = mask; 1129228561Snp t.fs.val.vlan_vld = 1; 1130228561Snp t.fs.mask.vlan_vld = 1; 1131296481Snp } else if (!parse_val_mask("pf", args, &val, &mask)) { 1132296481Snp t.fs.val.vnic &= 0x1fff; 1133296481Snp t.fs.val.vnic |= (val & 0x7) << 13; 1134296481Snp t.fs.mask.vnic &= 0x1fff; 1135296481Snp t.fs.mask.vnic |= (mask & 0x7) << 13; 1136296481Snp t.fs.val.pfvf_vld = 1; 1137296481Snp t.fs.mask.pfvf_vld = 1; 1138296481Snp } else if (!parse_val_mask("vf", args, &val, &mask)) { 1139296481Snp t.fs.val.vnic &= 0xe000; 1140296481Snp t.fs.val.vnic |= val & 0x1fff; 1141296481Snp t.fs.mask.vnic &= 0xe000; 1142296481Snp t.fs.mask.vnic |= mask & 0x1fff; 1143296481Snp t.fs.val.pfvf_vld = 1; 1144296481Snp t.fs.mask.pfvf_vld = 1; 1145222900Snp } else if (!parse_val_mask("tos", args, &val, &mask)) { 1146222900Snp t.fs.val.tos = val; 1147222900Snp t.fs.mask.tos = mask; 1148222900Snp } else if (!parse_val_mask("proto", args, &val, &mask)) { 1149222900Snp t.fs.val.proto = val; 1150222900Snp t.fs.mask.proto = mask; 1151222900Snp } else if (!parse_val_mask("ethtype", args, &val, &mask)) { 1152222900Snp t.fs.val.ethtype = val; 1153222900Snp t.fs.mask.ethtype = mask; 1154222900Snp } else if (!parse_val_mask("macidx", args, &val, &mask)) { 1155222900Snp t.fs.val.macidx = val; 1156222900Snp t.fs.mask.macidx = mask; 1157222900Snp } else if (!parse_val_mask("matchtype", args, &val, &mask)) { 1158222900Snp t.fs.val.matchtype = val; 1159222900Snp t.fs.mask.matchtype = mask; 1160222900Snp } else if (!parse_val_mask("frag", args, &val, &mask)) { 1161222900Snp t.fs.val.frag = val; 1162222900Snp t.fs.mask.frag = mask; 1163222900Snp } else if (!parse_val_mask("dport", args, &val, &mask)) { 1164222900Snp t.fs.val.dport = val; 1165222900Snp t.fs.mask.dport = mask; 1166222900Snp } else if (!parse_val_mask("sport", args, &val, &mask)) { 1167222900Snp t.fs.val.sport = val; 1168222900Snp t.fs.mask.sport = mask; 1169222900Snp } else if (!parse_ipaddr("dip", args, &af, t.fs.val.dip, 1170222900Snp t.fs.mask.dip)) { 1171222900Snp /* nada */; 1172222900Snp } else if (!parse_ipaddr("sip", args, &af, t.fs.val.sip, 1173222900Snp t.fs.mask.sip)) { 1174222900Snp /* nada */; 1175222900Snp } else if (!strcmp(argv[start_arg], "action")) { 1176222900Snp if (!strcmp(argv[start_arg + 1], "pass")) 1177222900Snp t.fs.action = FILTER_PASS; 1178222900Snp else if (!strcmp(argv[start_arg + 1], "drop")) 1179222900Snp t.fs.action = FILTER_DROP; 1180222900Snp else if (!strcmp(argv[start_arg + 1], "switch")) 1181222900Snp t.fs.action = FILTER_SWITCH; 1182222900Snp else { 1183222900Snp warnx("invalid action \"%s\"; must be one of" 1184222900Snp " \"pass\", \"drop\" or \"switch\"", 1185222900Snp argv[start_arg + 1]); 1186222900Snp return (EINVAL); 1187222900Snp } 1188222900Snp } else if (!parse_val("hitcnts", args, &val)) { 1189222900Snp t.fs.hitcnts = val; 1190222900Snp } else if (!parse_val("prio", args, &val)) { 1191222900Snp t.fs.prio = val; 1192222900Snp } else if (!parse_val("rpttid", args, &val)) { 1193222900Snp t.fs.rpttid = 1; 1194222900Snp } else if (!parse_val("queue", args, &val)) { 1195222900Snp t.fs.dirsteer = 1; 1196222900Snp t.fs.iq = val; 1197222900Snp } else if (!parse_val("tcbhash", args, &val)) { 1198222900Snp t.fs.maskhash = 1; 1199222900Snp t.fs.dirsteerhash = 1; 1200222900Snp } else if (!parse_val("eport", args, &val)) { 1201222900Snp t.fs.eport = val; 1202222900Snp } else if (!strcmp(argv[start_arg], "dmac")) { 1203222900Snp struct ether_addr *daddr; 1204222900Snp 1205222900Snp daddr = ether_aton(argv[start_arg + 1]); 1206222900Snp if (daddr == NULL) { 1207222900Snp warnx("invalid dmac address \"%s\"", 1208222900Snp argv[start_arg + 1]); 1209222900Snp return (EINVAL); 1210222900Snp } 1211222900Snp memcpy(t.fs.dmac, daddr, ETHER_ADDR_LEN); 1212222900Snp t.fs.newdmac = 1; 1213222900Snp } else if (!strcmp(argv[start_arg], "smac")) { 1214222900Snp struct ether_addr *saddr; 1215222900Snp 1216222900Snp saddr = ether_aton(argv[start_arg + 1]); 1217222900Snp if (saddr == NULL) { 1218222900Snp warnx("invalid smac address \"%s\"", 1219222900Snp argv[start_arg + 1]); 1220222900Snp return (EINVAL); 1221222900Snp } 1222222900Snp memcpy(t.fs.smac, saddr, ETHER_ADDR_LEN); 1223222900Snp t.fs.newsmac = 1; 1224222900Snp } else if (!strcmp(argv[start_arg], "vlan")) { 1225222900Snp char *p; 1226222900Snp if (!strcmp(argv[start_arg + 1], "none")) { 1227222900Snp t.fs.newvlan = VLAN_REMOVE; 1228222900Snp } else if (argv[start_arg + 1][0] == '=') { 1229222900Snp t.fs.newvlan = VLAN_REWRITE; 1230222900Snp } else if (argv[start_arg + 1][0] == '+') { 1231222900Snp t.fs.newvlan = VLAN_INSERT; 1232245520Snp } else if (isdigit(argv[start_arg + 1][0]) && 1233245520Snp !parse_val_mask("vlan", args, &val, &mask)) { 1234245520Snp t.fs.val.vlan = val; 1235245520Snp t.fs.mask.vlan = mask; 1236245520Snp t.fs.val.vlan_vld = 1; 1237245520Snp t.fs.mask.vlan_vld = 1; 1238222900Snp } else { 1239222900Snp warnx("unknown vlan parameter \"%s\"; must" 1240245520Snp " be one of \"none\", \"=<vlan>\", " 1241245520Snp " \"+<vlan>\", or \"<vlan>\"", 1242245520Snp argv[start_arg + 1]); 1243222900Snp return (EINVAL); 1244222900Snp } 1245222900Snp if (t.fs.newvlan == VLAN_REWRITE || 1246222900Snp t.fs.newvlan == VLAN_INSERT) { 1247222900Snp t.fs.vlan = strtoul(argv[start_arg + 1] + 1, 1248222900Snp &p, 0); 1249222900Snp if (p == argv[start_arg + 1] + 1 || p[0] != 0) { 1250222900Snp warnx("invalid vlan \"%s\"", 1251222900Snp argv[start_arg + 1]); 1252222900Snp return (EINVAL); 1253222900Snp } 1254222900Snp } 1255222900Snp } else { 1256222900Snp warnx("invalid parameter \"%s\"", argv[start_arg]); 1257222900Snp return (EINVAL); 1258222900Snp } 1259222900Snp } 1260222900Snp if (start_arg != argc) { 1261222900Snp warnx("no value for \"%s\"", argv[start_arg]); 1262222900Snp return (EINVAL); 1263222900Snp } 1264222900Snp 1265222900Snp /* 1266222900Snp * Check basic sanity of option combinations. 1267222900Snp */ 1268222900Snp if (t.fs.action != FILTER_SWITCH && 1269222900Snp (t.fs.eport || t.fs.newdmac || t.fs.newsmac || t.fs.newvlan)) { 1270222900Snp warnx("prio, port dmac, smac and vlan only make sense with" 1271222900Snp " \"action switch\""); 1272222900Snp return (EINVAL); 1273222900Snp } 1274222900Snp if (t.fs.action != FILTER_PASS && 1275222900Snp (t.fs.rpttid || t.fs.dirsteer || t.fs.maskhash)) { 1276222900Snp warnx("rpttid, queue and tcbhash don't make sense with" 1277222900Snp " action \"drop\" or \"switch\""); 1278222900Snp return (EINVAL); 1279222900Snp } 1280296481Snp if (t.fs.val.ovlan_vld && t.fs.val.pfvf_vld) { 1281296481Snp warnx("ovlan and vnic_id (pf/vf) are mutually exclusive"); 1282296481Snp return (EINVAL); 1283296481Snp } 1284222900Snp 1285222900Snp t.fs.type = (af == AF_INET6 ? 1 : 0); /* default IPv4 */ 1286222900Snp return doit(CHELSIO_T4_SET_FILTER, &t); 1287222900Snp} 1288222900Snp 1289222900Snpstatic int 1290222900Snpfilter_cmd(int argc, const char *argv[]) 1291222900Snp{ 1292222900Snp long long val; 1293222900Snp uint32_t idx; 1294222900Snp char *s; 1295222900Snp 1296222900Snp if (argc == 0) { 1297222900Snp warnx("filter: no arguments."); 1298222900Snp return (EINVAL); 1299222900Snp }; 1300222900Snp 1301222900Snp /* list */ 1302222900Snp if (strcmp(argv[0], "list") == 0) { 1303222900Snp if (argc != 1) 1304222900Snp warnx("trailing arguments after \"list\" ignored."); 1305222900Snp 1306222900Snp return show_filters(); 1307222900Snp } 1308222900Snp 1309222900Snp /* mode */ 1310222900Snp if (argc == 1 && strcmp(argv[0], "mode") == 0) 1311222900Snp return get_filter_mode(); 1312222900Snp 1313222900Snp /* mode <mode> */ 1314222900Snp if (strcmp(argv[0], "mode") == 0) 1315222900Snp return set_filter_mode(argc - 1, argv + 1); 1316222900Snp 1317222900Snp /* <idx> ... */ 1318222900Snp s = str_to_number(argv[0], NULL, &val); 1319222900Snp if (*s || val > 0xffffffffU) { 1320222900Snp warnx("\"%s\" is neither an index nor a filter subcommand.", 1321222900Snp argv[0]); 1322222900Snp return (EINVAL); 1323222900Snp } 1324222900Snp idx = (uint32_t) val; 1325222900Snp 1326222900Snp /* <idx> delete|clear */ 1327222900Snp if (argc == 2 && 1328222900Snp (strcmp(argv[1], "delete") == 0 || strcmp(argv[1], "clear") == 0)) { 1329222900Snp return del_filter(idx); 1330222900Snp } 1331222900Snp 1332222900Snp /* <idx> [<param> <val>] ... */ 1333222900Snp return set_filter(idx, argc - 1, argv + 1); 1334222900Snp} 1335222900Snp 1336222974Snp/* 1337222974Snp * Shows the fields of a multi-word structure. The structure is considered to 1338222974Snp * consist of @nwords 32-bit words (i.e, it's an (@nwords * 32)-bit structure) 1339222974Snp * whose fields are described by @fd. The 32-bit words are given in @words 1340222974Snp * starting with the least significant 32-bit word. 1341222974Snp */ 1342222974Snpstatic void 1343222974Snpshow_struct(const uint32_t *words, int nwords, const struct field_desc *fd) 1344222974Snp{ 1345222974Snp unsigned int w = 0; 1346222974Snp const struct field_desc *p; 1347222974Snp 1348222974Snp for (p = fd; p->name; p++) 1349222974Snp w = max(w, strlen(p->name)); 1350222974Snp 1351222974Snp while (fd->name) { 1352222974Snp unsigned long long data; 1353222974Snp int first_word = fd->start / 32; 1354222974Snp int shift = fd->start % 32; 1355222974Snp int width = fd->end - fd->start + 1; 1356222974Snp unsigned long long mask = (1ULL << width) - 1; 1357222974Snp 1358222974Snp data = (words[first_word] >> shift) | 1359222974Snp ((uint64_t)words[first_word + 1] << (32 - shift)); 1360222974Snp if (shift) 1361222974Snp data |= ((uint64_t)words[first_word + 2] << (64 - shift)); 1362222974Snp data &= mask; 1363222974Snp if (fd->islog2) 1364222974Snp data = 1 << data; 1365222974Snp printf("%-*s ", w, fd->name); 1366222974Snp printf(fd->hex ? "%#llx\n" : "%llu\n", data << fd->shift); 1367222974Snp fd++; 1368222974Snp } 1369222974Snp} 1370222974Snp 1371222974Snp#define FIELD(name, start, end) { name, start, end, 0, 0, 0 } 1372222974Snp#define FIELD1(name, start) FIELD(name, start, start) 1373222974Snp 1374222974Snpstatic void 1375306137Snpshow_t5t6_ctxt(const struct t4_sge_context *p, int vers) 1376222974Snp{ 1377284984Snp static struct field_desc egress_t5[] = { 1378284984Snp FIELD("DCA_ST:", 181, 191), 1379222974Snp FIELD1("StatusPgNS:", 180), 1380222974Snp FIELD1("StatusPgRO:", 179), 1381222974Snp FIELD1("FetchNS:", 178), 1382222974Snp FIELD1("FetchRO:", 177), 1383222974Snp FIELD1("Valid:", 176), 1384222974Snp FIELD("PCIeDataChannel:", 174, 175), 1385284984Snp FIELD1("StatusPgTPHintEn:", 173), 1386284984Snp FIELD("StatusPgTPHint:", 171, 172), 1387284984Snp FIELD1("FetchTPHintEn:", 170), 1388284984Snp FIELD("FetchTPHint:", 168, 169), 1389284984Snp FIELD1("FCThreshOverride:", 167), 1390284984Snp { "WRLength:", 162, 166, 9, 0, 1 }, 1391284984Snp FIELD1("WRLengthKnown:", 161), 1392284984Snp FIELD1("ReschedulePending:", 160), 1393284984Snp FIELD1("OnChipQueue:", 159), 1394284984Snp FIELD1("FetchSizeMode:", 158), 1395284984Snp { "FetchBurstMin:", 156, 157, 4, 0, 1 }, 1396284984Snp FIELD1("FLMPacking:", 155), 1397284984Snp FIELD("FetchBurstMax:", 153, 154), 1398284984Snp FIELD("uPToken:", 133, 152), 1399284984Snp FIELD1("uPTokenEn:", 132), 1400284984Snp FIELD1("UserModeIO:", 131), 1401284984Snp FIELD("uPFLCredits:", 123, 130), 1402284984Snp FIELD1("uPFLCreditEn:", 122), 1403284984Snp FIELD("FID:", 111, 121), 1404284984Snp FIELD("HostFCMode:", 109, 110), 1405284984Snp FIELD1("HostFCOwner:", 108), 1406284984Snp { "CIDXFlushThresh:", 105, 107, 0, 0, 1 }, 1407284984Snp FIELD("CIDX:", 89, 104), 1408284984Snp FIELD("PIDX:", 73, 88), 1409284984Snp { "BaseAddress:", 18, 72, 9, 1 }, 1410284984Snp FIELD("QueueSize:", 2, 17), 1411284984Snp FIELD1("QueueType:", 1), 1412284984Snp FIELD1("CachePriority:", 0), 1413284984Snp { NULL } 1414284984Snp }; 1415306137Snp static struct field_desc egress_t6[] = { 1416306137Snp FIELD("DCA_ST:", 181, 191), 1417306137Snp FIELD1("StatusPgNS:", 180), 1418306137Snp FIELD1("StatusPgRO:", 179), 1419306137Snp FIELD1("FetchNS:", 178), 1420306137Snp FIELD1("FetchRO:", 177), 1421306137Snp FIELD1("Valid:", 176), 1422306137Snp FIELD1("ReschedulePending_1:", 175), 1423306137Snp FIELD1("PCIeDataChannel:", 174), 1424306137Snp FIELD1("StatusPgTPHintEn:", 173), 1425306137Snp FIELD("StatusPgTPHint:", 171, 172), 1426306137Snp FIELD1("FetchTPHintEn:", 170), 1427306137Snp FIELD("FetchTPHint:", 168, 169), 1428306137Snp FIELD1("FCThreshOverride:", 167), 1429306137Snp { "WRLength:", 162, 166, 9, 0, 1 }, 1430306137Snp FIELD1("WRLengthKnown:", 161), 1431306137Snp FIELD1("ReschedulePending:", 160), 1432306137Snp FIELD("TimerIx:", 157, 159), 1433306137Snp FIELD1("FetchBurstMin:", 156), 1434306137Snp FIELD1("FLMPacking:", 155), 1435306137Snp FIELD("FetchBurstMax:", 153, 154), 1436306137Snp FIELD("uPToken:", 133, 152), 1437306137Snp FIELD1("uPTokenEn:", 132), 1438306137Snp FIELD1("UserModeIO:", 131), 1439306137Snp FIELD("uPFLCredits:", 123, 130), 1440306137Snp FIELD1("uPFLCreditEn:", 122), 1441306137Snp FIELD("FID:", 111, 121), 1442306137Snp FIELD("HostFCMode:", 109, 110), 1443306137Snp FIELD1("HostFCOwner:", 108), 1444306137Snp { "CIDXFlushThresh:", 105, 107, 0, 0, 1 }, 1445306137Snp FIELD("CIDX:", 89, 104), 1446306137Snp FIELD("PIDX:", 73, 88), 1447306137Snp { "BaseAddress:", 18, 72, 9, 1 }, 1448306137Snp FIELD("QueueSize:", 2, 17), 1449306137Snp FIELD1("QueueType:", 1), 1450306137Snp FIELD1("FetchSizeMode:", 0), 1451306137Snp { NULL } 1452306137Snp }; 1453284984Snp static struct field_desc fl_t5[] = { 1454284984Snp FIELD("DCA_ST:", 181, 191), 1455284984Snp FIELD1("StatusPgNS:", 180), 1456284984Snp FIELD1("StatusPgRO:", 179), 1457284984Snp FIELD1("FetchNS:", 178), 1458284984Snp FIELD1("FetchRO:", 177), 1459284984Snp FIELD1("Valid:", 176), 1460284984Snp FIELD("PCIeDataChannel:", 174, 175), 1461284984Snp FIELD1("StatusPgTPHintEn:", 173), 1462284984Snp FIELD("StatusPgTPHint:", 171, 172), 1463284984Snp FIELD1("FetchTPHintEn:", 170), 1464284984Snp FIELD("FetchTPHint:", 168, 169), 1465284984Snp FIELD1("FCThreshOverride:", 167), 1466284984Snp FIELD1("ReschedulePending:", 160), 1467284984Snp FIELD1("OnChipQueue:", 159), 1468284984Snp FIELD1("FetchSizeMode:", 158), 1469284984Snp { "FetchBurstMin:", 156, 157, 4, 0, 1 }, 1470284984Snp FIELD1("FLMPacking:", 155), 1471284984Snp FIELD("FetchBurstMax:", 153, 154), 1472284984Snp FIELD1("FLMcongMode:", 152), 1473284984Snp FIELD("MaxuPFLCredits:", 144, 151), 1474284984Snp FIELD("FLMcontextID:", 133, 143), 1475284984Snp FIELD1("uPTokenEn:", 132), 1476284984Snp FIELD1("UserModeIO:", 131), 1477284984Snp FIELD("uPFLCredits:", 123, 130), 1478284984Snp FIELD1("uPFLCreditEn:", 122), 1479284984Snp FIELD("FID:", 111, 121), 1480284984Snp FIELD("HostFCMode:", 109, 110), 1481284984Snp FIELD1("HostFCOwner:", 108), 1482284984Snp { "CIDXFlushThresh:", 105, 107, 0, 0, 1 }, 1483284984Snp FIELD("CIDX:", 89, 104), 1484284984Snp FIELD("PIDX:", 73, 88), 1485284984Snp { "BaseAddress:", 18, 72, 9, 1 }, 1486284984Snp FIELD("QueueSize:", 2, 17), 1487284984Snp FIELD1("QueueType:", 1), 1488284984Snp FIELD1("CachePriority:", 0), 1489284984Snp { NULL } 1490284984Snp }; 1491284984Snp static struct field_desc ingress_t5[] = { 1492284984Snp FIELD("DCA_ST:", 143, 153), 1493284984Snp FIELD1("ISCSICoalescing:", 142), 1494284984Snp FIELD1("Queue_Valid:", 141), 1495284984Snp FIELD1("TimerPending:", 140), 1496284984Snp FIELD1("DropRSS:", 139), 1497284984Snp FIELD("PCIeChannel:", 137, 138), 1498284984Snp FIELD1("SEInterruptArmed:", 136), 1499284984Snp FIELD1("CongestionMgtEnable:", 135), 1500284984Snp FIELD1("NoSnoop:", 134), 1501284984Snp FIELD1("RelaxedOrdering:", 133), 1502284984Snp FIELD1("GTSmode:", 132), 1503284984Snp FIELD1("TPHintEn:", 131), 1504284984Snp FIELD("TPHint:", 129, 130), 1505284984Snp FIELD1("UpdateScheduling:", 128), 1506284984Snp FIELD("UpdateDelivery:", 126, 127), 1507284984Snp FIELD1("InterruptSent:", 125), 1508284984Snp FIELD("InterruptIDX:", 114, 124), 1509284984Snp FIELD1("InterruptDestination:", 113), 1510284984Snp FIELD1("InterruptArmed:", 112), 1511284984Snp FIELD("RxIntCounter:", 106, 111), 1512284984Snp FIELD("RxIntCounterThreshold:", 104, 105), 1513284984Snp FIELD1("Generation:", 103), 1514284984Snp { "BaseAddress:", 48, 102, 9, 1 }, 1515284984Snp FIELD("PIDX:", 32, 47), 1516284984Snp FIELD("CIDX:", 16, 31), 1517284984Snp { "QueueSize:", 4, 15, 4, 0 }, 1518284984Snp { "QueueEntrySize:", 2, 3, 4, 0, 1 }, 1519284984Snp FIELD1("QueueEntryOverride:", 1), 1520284984Snp FIELD1("CachePriority:", 0), 1521284984Snp { NULL } 1522284984Snp }; 1523306137Snp static struct field_desc ingress_t6[] = { 1524306137Snp FIELD1("SP_NS:", 158), 1525306137Snp FIELD1("SP_RO:", 157), 1526306137Snp FIELD1("SP_TPHintEn:", 156), 1527306137Snp FIELD("SP_TPHint:", 154, 155), 1528306137Snp FIELD("DCA_ST:", 143, 153), 1529306137Snp FIELD1("ISCSICoalescing:", 142), 1530306137Snp FIELD1("Queue_Valid:", 141), 1531306137Snp FIELD1("TimerPending:", 140), 1532306137Snp FIELD1("DropRSS:", 139), 1533306137Snp FIELD("PCIeChannel:", 137, 138), 1534306137Snp FIELD1("SEInterruptArmed:", 136), 1535306137Snp FIELD1("CongestionMgtEnable:", 135), 1536306137Snp FIELD1("NoSnoop:", 134), 1537306137Snp FIELD1("RelaxedOrdering:", 133), 1538306137Snp FIELD1("GTSmode:", 132), 1539306137Snp FIELD1("TPHintEn:", 131), 1540306137Snp FIELD("TPHint:", 129, 130), 1541306137Snp FIELD1("UpdateScheduling:", 128), 1542306137Snp FIELD("UpdateDelivery:", 126, 127), 1543306137Snp FIELD1("InterruptSent:", 125), 1544306137Snp FIELD("InterruptIDX:", 114, 124), 1545306137Snp FIELD1("InterruptDestination:", 113), 1546306137Snp FIELD1("InterruptArmed:", 112), 1547306137Snp FIELD("RxIntCounter:", 106, 111), 1548306137Snp FIELD("RxIntCounterThreshold:", 104, 105), 1549306137Snp FIELD1("Generation:", 103), 1550306137Snp { "BaseAddress:", 48, 102, 9, 1 }, 1551306137Snp FIELD("PIDX:", 32, 47), 1552306137Snp FIELD("CIDX:", 16, 31), 1553306137Snp { "QueueSize:", 4, 15, 4, 0 }, 1554306137Snp { "QueueEntrySize:", 2, 3, 4, 0, 1 }, 1555306137Snp FIELD1("QueueEntryOverride:", 1), 1556306137Snp FIELD1("CachePriority:", 0), 1557306137Snp { NULL } 1558306137Snp }; 1559284984Snp static struct field_desc flm_t5[] = { 1560284984Snp FIELD1("Valid:", 89), 1561284984Snp FIELD("SplitLenMode:", 87, 88), 1562284984Snp FIELD1("TPHintEn:", 86), 1563284984Snp FIELD("TPHint:", 84, 85), 1564284984Snp FIELD1("NoSnoop:", 83), 1565284984Snp FIELD1("RelaxedOrdering:", 82), 1566284984Snp FIELD("DCA_ST:", 71, 81), 1567284984Snp FIELD("EQid:", 54, 70), 1568284984Snp FIELD("SplitEn:", 52, 53), 1569284984Snp FIELD1("PadEn:", 51), 1570284984Snp FIELD1("PackEn:", 50), 1571284984Snp FIELD1("Cache_Lock :", 49), 1572284984Snp FIELD1("CongDrop:", 48), 1573284984Snp FIELD("PackOffset:", 16, 47), 1574284984Snp FIELD("CIDX:", 8, 15), 1575284984Snp FIELD("PIDX:", 0, 7), 1576284984Snp { NULL } 1577284984Snp }; 1578306137Snp static struct field_desc flm_t6[] = { 1579306137Snp FIELD1("Valid:", 89), 1580306137Snp FIELD("SplitLenMode:", 87, 88), 1581306137Snp FIELD1("TPHintEn:", 86), 1582306137Snp FIELD("TPHint:", 84, 85), 1583306137Snp FIELD1("NoSnoop:", 83), 1584306137Snp FIELD1("RelaxedOrdering:", 82), 1585306137Snp FIELD("DCA_ST:", 71, 81), 1586306137Snp FIELD("EQid:", 54, 70), 1587306137Snp FIELD("SplitEn:", 52, 53), 1588306137Snp FIELD1("PadEn:", 51), 1589306137Snp FIELD1("PackEn:", 50), 1590306137Snp FIELD1("Cache_Lock :", 49), 1591306137Snp FIELD1("CongDrop:", 48), 1592306138Snp FIELD1("Inflight:", 47), 1593306137Snp FIELD1("CongEn:", 46), 1594306137Snp FIELD1("CongMode:", 45), 1595306137Snp FIELD("PackOffset:", 20, 39), 1596306137Snp FIELD("CIDX:", 8, 15), 1597306137Snp FIELD("PIDX:", 0, 7), 1598306137Snp { NULL } 1599306137Snp }; 1600284984Snp static struct field_desc conm_t5[] = { 1601284984Snp FIELD1("CngMPSEnable:", 21), 1602284984Snp FIELD("CngTPMode:", 19, 20), 1603284984Snp FIELD1("CngDBPHdr:", 18), 1604284984Snp FIELD1("CngDBPData:", 17), 1605284984Snp FIELD1("CngIMSG:", 16), 1606284984Snp { "CngChMap:", 0, 15, 0, 1, 0 }, 1607284984Snp { NULL } 1608284984Snp }; 1609284984Snp 1610306137Snp if (p->mem_id == SGE_CONTEXT_EGRESS) { 1611306137Snp if (p->data[0] & 2) 1612306137Snp show_struct(p->data, 6, fl_t5); 1613306137Snp else if (vers == 5) 1614306137Snp show_struct(p->data, 6, egress_t5); 1615306137Snp else 1616306137Snp show_struct(p->data, 6, egress_t6); 1617306137Snp } else if (p->mem_id == SGE_CONTEXT_FLM) 1618306137Snp show_struct(p->data, 3, vers == 5 ? flm_t5 : flm_t6); 1619284984Snp else if (p->mem_id == SGE_CONTEXT_INGRESS) 1620306137Snp show_struct(p->data, 5, vers == 5 ? ingress_t5 : ingress_t6); 1621284984Snp else if (p->mem_id == SGE_CONTEXT_CNM) 1622284984Snp show_struct(p->data, 1, conm_t5); 1623284984Snp} 1624284984Snp 1625284984Snpstatic void 1626284984Snpshow_t4_ctxt(const struct t4_sge_context *p) 1627284984Snp{ 1628284984Snp static struct field_desc egress_t4[] = { 1629284984Snp FIELD1("StatusPgNS:", 180), 1630284984Snp FIELD1("StatusPgRO:", 179), 1631284984Snp FIELD1("FetchNS:", 178), 1632284984Snp FIELD1("FetchRO:", 177), 1633284984Snp FIELD1("Valid:", 176), 1634284984Snp FIELD("PCIeDataChannel:", 174, 175), 1635222974Snp FIELD1("DCAEgrQEn:", 173), 1636222974Snp FIELD("DCACPUID:", 168, 172), 1637222974Snp FIELD1("FCThreshOverride:", 167), 1638222974Snp FIELD("WRLength:", 162, 166), 1639222974Snp FIELD1("WRLengthKnown:", 161), 1640222974Snp FIELD1("ReschedulePending:", 160), 1641222974Snp FIELD1("OnChipQueue:", 159), 1642222974Snp FIELD1("FetchSizeMode", 158), 1643222974Snp { "FetchBurstMin:", 156, 157, 4, 0, 1 }, 1644222974Snp { "FetchBurstMax:", 153, 154, 6, 0, 1 }, 1645222974Snp FIELD("uPToken:", 133, 152), 1646222974Snp FIELD1("uPTokenEn:", 132), 1647222974Snp FIELD1("UserModeIO:", 131), 1648222974Snp FIELD("uPFLCredits:", 123, 130), 1649222974Snp FIELD1("uPFLCreditEn:", 122), 1650222974Snp FIELD("FID:", 111, 121), 1651222974Snp FIELD("HostFCMode:", 109, 110), 1652222974Snp FIELD1("HostFCOwner:", 108), 1653222974Snp { "CIDXFlushThresh:", 105, 107, 0, 0, 1 }, 1654222974Snp FIELD("CIDX:", 89, 104), 1655222974Snp FIELD("PIDX:", 73, 88), 1656222974Snp { "BaseAddress:", 18, 72, 9, 1 }, 1657222974Snp FIELD("QueueSize:", 2, 17), 1658222974Snp FIELD1("QueueType:", 1), 1659222974Snp FIELD1("CachePriority:", 0), 1660222974Snp { NULL } 1661222974Snp }; 1662284984Snp static struct field_desc fl_t4[] = { 1663222974Snp FIELD1("StatusPgNS:", 180), 1664222974Snp FIELD1("StatusPgRO:", 179), 1665222974Snp FIELD1("FetchNS:", 178), 1666222974Snp FIELD1("FetchRO:", 177), 1667222974Snp FIELD1("Valid:", 176), 1668222974Snp FIELD("PCIeDataChannel:", 174, 175), 1669222974Snp FIELD1("DCAEgrQEn:", 173), 1670222974Snp FIELD("DCACPUID:", 168, 172), 1671222974Snp FIELD1("FCThreshOverride:", 167), 1672222974Snp FIELD1("ReschedulePending:", 160), 1673222974Snp FIELD1("OnChipQueue:", 159), 1674222974Snp FIELD1("FetchSizeMode", 158), 1675222974Snp { "FetchBurstMin:", 156, 157, 4, 0, 1 }, 1676222974Snp { "FetchBurstMax:", 153, 154, 6, 0, 1 }, 1677222974Snp FIELD1("FLMcongMode:", 152), 1678222974Snp FIELD("MaxuPFLCredits:", 144, 151), 1679222974Snp FIELD("FLMcontextID:", 133, 143), 1680222974Snp FIELD1("uPTokenEn:", 132), 1681222974Snp FIELD1("UserModeIO:", 131), 1682222974Snp FIELD("uPFLCredits:", 123, 130), 1683222974Snp FIELD1("uPFLCreditEn:", 122), 1684222974Snp FIELD("FID:", 111, 121), 1685222974Snp FIELD("HostFCMode:", 109, 110), 1686222974Snp FIELD1("HostFCOwner:", 108), 1687222974Snp { "CIDXFlushThresh:", 105, 107, 0, 0, 1 }, 1688222974Snp FIELD("CIDX:", 89, 104), 1689222974Snp FIELD("PIDX:", 73, 88), 1690222974Snp { "BaseAddress:", 18, 72, 9, 1 }, 1691222974Snp FIELD("QueueSize:", 2, 17), 1692222974Snp FIELD1("QueueType:", 1), 1693222974Snp FIELD1("CachePriority:", 0), 1694222974Snp { NULL } 1695222974Snp }; 1696284984Snp static struct field_desc ingress_t4[] = { 1697222974Snp FIELD1("NoSnoop:", 145), 1698222974Snp FIELD1("RelaxedOrdering:", 144), 1699222974Snp FIELD1("GTSmode:", 143), 1700222974Snp FIELD1("ISCSICoalescing:", 142), 1701222974Snp FIELD1("Valid:", 141), 1702222974Snp FIELD1("TimerPending:", 140), 1703222974Snp FIELD1("DropRSS:", 139), 1704222974Snp FIELD("PCIeChannel:", 137, 138), 1705222974Snp FIELD1("SEInterruptArmed:", 136), 1706222974Snp FIELD1("CongestionMgtEnable:", 135), 1707222974Snp FIELD1("DCAIngQEnable:", 134), 1708222974Snp FIELD("DCACPUID:", 129, 133), 1709222974Snp FIELD1("UpdateScheduling:", 128), 1710222974Snp FIELD("UpdateDelivery:", 126, 127), 1711222974Snp FIELD1("InterruptSent:", 125), 1712222974Snp FIELD("InterruptIDX:", 114, 124), 1713222974Snp FIELD1("InterruptDestination:", 113), 1714222974Snp FIELD1("InterruptArmed:", 112), 1715222974Snp FIELD("RxIntCounter:", 106, 111), 1716222974Snp FIELD("RxIntCounterThreshold:", 104, 105), 1717222974Snp FIELD1("Generation:", 103), 1718222974Snp { "BaseAddress:", 48, 102, 9, 1 }, 1719222974Snp FIELD("PIDX:", 32, 47), 1720222974Snp FIELD("CIDX:", 16, 31), 1721222974Snp { "QueueSize:", 4, 15, 4, 0 }, 1722222974Snp { "QueueEntrySize:", 2, 3, 4, 0, 1 }, 1723222974Snp FIELD1("QueueEntryOverride:", 1), 1724222974Snp FIELD1("CachePriority:", 0), 1725222974Snp { NULL } 1726222974Snp }; 1727284984Snp static struct field_desc flm_t4[] = { 1728222974Snp FIELD1("NoSnoop:", 79), 1729222974Snp FIELD1("RelaxedOrdering:", 78), 1730222974Snp FIELD1("Valid:", 77), 1731222974Snp FIELD("DCACPUID:", 72, 76), 1732222974Snp FIELD1("DCAFLEn:", 71), 1733222974Snp FIELD("EQid:", 54, 70), 1734222974Snp FIELD("SplitEn:", 52, 53), 1735222974Snp FIELD1("PadEn:", 51), 1736222974Snp FIELD1("PackEn:", 50), 1737222974Snp FIELD1("DBpriority:", 48), 1738222974Snp FIELD("PackOffset:", 16, 47), 1739222974Snp FIELD("CIDX:", 8, 15), 1740222974Snp FIELD("PIDX:", 0, 7), 1741222974Snp { NULL } 1742222974Snp }; 1743284984Snp static struct field_desc conm_t4[] = { 1744222974Snp FIELD1("CngDBPHdr:", 6), 1745222974Snp FIELD1("CngDBPData:", 5), 1746222974Snp FIELD1("CngIMSG:", 4), 1747261534Snp { "CngChMap:", 0, 3, 0, 1, 0}, 1748222974Snp { NULL } 1749222974Snp }; 1750222974Snp 1751222974Snp if (p->mem_id == SGE_CONTEXT_EGRESS) 1752284984Snp show_struct(p->data, 6, (p->data[0] & 2) ? fl_t4 : egress_t4); 1753222974Snp else if (p->mem_id == SGE_CONTEXT_FLM) 1754284984Snp show_struct(p->data, 3, flm_t4); 1755222974Snp else if (p->mem_id == SGE_CONTEXT_INGRESS) 1756284984Snp show_struct(p->data, 5, ingress_t4); 1757222974Snp else if (p->mem_id == SGE_CONTEXT_CNM) 1758284984Snp show_struct(p->data, 1, conm_t4); 1759222974Snp} 1760222974Snp 1761222974Snp#undef FIELD 1762222974Snp#undef FIELD1 1763222974Snp 1764222900Snpstatic int 1765222974Snpget_sge_context(int argc, const char *argv[]) 1766222974Snp{ 1767222974Snp int rc; 1768222974Snp char *p; 1769222974Snp long cid; 1770222974Snp struct t4_sge_context cntxt = {0}; 1771222974Snp 1772222974Snp if (argc != 2) { 1773222974Snp warnx("sge_context: incorrect number of arguments."); 1774222974Snp return (EINVAL); 1775222974Snp } 1776222974Snp 1777222974Snp if (!strcmp(argv[0], "egress")) 1778222974Snp cntxt.mem_id = SGE_CONTEXT_EGRESS; 1779222974Snp else if (!strcmp(argv[0], "ingress")) 1780222974Snp cntxt.mem_id = SGE_CONTEXT_INGRESS; 1781222974Snp else if (!strcmp(argv[0], "fl")) 1782222974Snp cntxt.mem_id = SGE_CONTEXT_FLM; 1783222974Snp else if (!strcmp(argv[0], "cong")) 1784222974Snp cntxt.mem_id = SGE_CONTEXT_CNM; 1785222974Snp else { 1786222974Snp warnx("unknown context type \"%s\"; known types are egress, " 1787222974Snp "ingress, fl, and cong.", argv[0]); 1788222974Snp return (EINVAL); 1789222974Snp } 1790222974Snp 1791222974Snp p = str_to_number(argv[1], &cid, NULL); 1792222974Snp if (*p) { 1793222974Snp warnx("invalid context id \"%s\"", argv[1]); 1794222974Snp return (EINVAL); 1795222974Snp } 1796222974Snp cntxt.cid = cid; 1797222974Snp 1798222974Snp rc = doit(CHELSIO_T4_GET_SGE_CONTEXT, &cntxt); 1799222974Snp if (rc != 0) 1800222974Snp return (rc); 1801222974Snp 1802284984Snp if (chip_id == 4) 1803284984Snp show_t4_ctxt(&cntxt); 1804284984Snp else 1805306137Snp show_t5t6_ctxt(&cntxt, chip_id); 1806284984Snp 1807222974Snp return (0); 1808222974Snp} 1809222974Snp 1810222974Snpstatic int 1811228594Snploadfw(int argc, const char *argv[]) 1812228594Snp{ 1813228594Snp int rc, fd; 1814228594Snp struct t4_data data = {0}; 1815228594Snp const char *fname = argv[0]; 1816228594Snp struct stat st = {0}; 1817228594Snp 1818228594Snp if (argc != 1) { 1819228594Snp warnx("loadfw: incorrect number of arguments."); 1820228594Snp return (EINVAL); 1821228594Snp } 1822228594Snp 1823228594Snp fd = open(fname, O_RDONLY); 1824228594Snp if (fd < 0) { 1825228594Snp warn("open(%s)", fname); 1826228594Snp return (errno); 1827228594Snp } 1828228594Snp 1829228594Snp if (fstat(fd, &st) < 0) { 1830228594Snp warn("fstat"); 1831228594Snp close(fd); 1832228594Snp return (errno); 1833228594Snp } 1834228594Snp 1835228594Snp data.len = st.st_size; 1836273360Snp data.data = mmap(0, data.len, PROT_READ, MAP_PRIVATE, fd, 0); 1837228594Snp if (data.data == MAP_FAILED) { 1838228594Snp warn("mmap"); 1839228594Snp close(fd); 1840228594Snp return (errno); 1841228594Snp } 1842228594Snp 1843228594Snp rc = doit(CHELSIO_T4_LOAD_FW, &data); 1844228594Snp munmap(data.data, data.len); 1845228594Snp close(fd); 1846228594Snp return (rc); 1847228594Snp} 1848228594Snp 1849228594Snpstatic int 1850306823Snploadcfg(int argc, const char *argv[]) 1851306823Snp{ 1852306823Snp int rc, fd; 1853306823Snp struct t4_data data = {0}; 1854306823Snp const char *fname = argv[0]; 1855306823Snp struct stat st = {0}; 1856306823Snp 1857306823Snp if (argc != 1) { 1858306823Snp warnx("loadcfg: incorrect number of arguments."); 1859306823Snp return (EINVAL); 1860306823Snp } 1861306823Snp 1862306823Snp if (strcmp(fname, "clear") == 0) 1863306823Snp return (doit(CHELSIO_T4_LOAD_CFG, &data)); 1864306823Snp 1865306823Snp fd = open(fname, O_RDONLY); 1866306823Snp if (fd < 0) { 1867306823Snp warn("open(%s)", fname); 1868306823Snp return (errno); 1869306823Snp } 1870306823Snp 1871306823Snp if (fstat(fd, &st) < 0) { 1872306823Snp warn("fstat"); 1873306823Snp close(fd); 1874306823Snp return (errno); 1875306823Snp } 1876306823Snp 1877306823Snp data.len = st.st_size; 1878306823Snp data.len &= ~3; /* Clip off to make it a multiple of 4 */ 1879306823Snp data.data = mmap(0, data.len, PROT_READ, MAP_PRIVATE, fd, 0); 1880306823Snp if (data.data == MAP_FAILED) { 1881306823Snp warn("mmap"); 1882306823Snp close(fd); 1883306823Snp return (errno); 1884306823Snp } 1885306823Snp 1886306823Snp rc = doit(CHELSIO_T4_LOAD_CFG, &data); 1887306823Snp munmap(data.data, data.len); 1888306823Snp close(fd); 1889306823Snp return (rc); 1890306823Snp} 1891306823Snp 1892306823Snpstatic int 1893330307Snpdumpstate(int argc, const char *argv[]) 1894330307Snp{ 1895330307Snp int rc, fd; 1896330307Snp struct t4_cudbg_dump dump = {0}; 1897330307Snp const char *fname = argv[0]; 1898330307Snp 1899330307Snp if (argc != 1) { 1900330307Snp warnx("dumpstate: incorrect number of arguments."); 1901330307Snp return (EINVAL); 1902330307Snp } 1903330307Snp 1904330307Snp dump.wr_flash = 0; 1905330307Snp memset(&dump.bitmap, 0xff, sizeof(dump.bitmap)); 1906330307Snp dump.len = 8 * 1024 * 1024; 1907330307Snp dump.data = malloc(dump.len); 1908330307Snp if (dump.data == NULL) { 1909330307Snp return (ENOMEM); 1910330307Snp } 1911330307Snp 1912330307Snp rc = doit(CHELSIO_T4_CUDBG_DUMP, &dump); 1913330307Snp if (rc != 0) 1914330307Snp goto done; 1915330307Snp 1916330307Snp fd = open(fname, O_CREAT | O_TRUNC | O_EXCL | O_WRONLY, 1917330307Snp S_IRUSR | S_IRGRP | S_IROTH); 1918330307Snp if (fd < 0) { 1919330307Snp warn("open(%s)", fname); 1920330307Snp rc = errno; 1921330307Snp goto done; 1922330307Snp } 1923330307Snp write(fd, dump.data, dump.len); 1924330307Snp close(fd); 1925330307Snpdone: 1926330307Snp free(dump.data); 1927330307Snp return (rc); 1928330307Snp} 1929330307Snp 1930330307Snpstatic int 1931228594Snpread_mem(uint32_t addr, uint32_t len, void (*output)(uint32_t *, uint32_t)) 1932228594Snp{ 1933228594Snp int rc; 1934228594Snp struct t4_mem_range mr; 1935228594Snp 1936228594Snp mr.addr = addr; 1937228594Snp mr.len = len; 1938228594Snp mr.data = malloc(mr.len); 1939228594Snp 1940228594Snp if (mr.data == 0) { 1941228594Snp warn("read_mem: malloc"); 1942228594Snp return (errno); 1943228594Snp } 1944228594Snp 1945228594Snp rc = doit(CHELSIO_T4_GET_MEM, &mr); 1946228594Snp if (rc != 0) 1947228594Snp goto done; 1948228594Snp 1949228594Snp if (output) 1950228594Snp (*output)(mr.data, mr.len); 1951228594Snpdone: 1952228594Snp free(mr.data); 1953228594Snp return (rc); 1954228594Snp} 1955228594Snp 1956330310Snpstatic int 1957330310Snploadboot(int argc, const char *argv[]) 1958330310Snp{ 1959330310Snp int rc, fd; 1960330310Snp long l; 1961330310Snp char *p; 1962330310Snp struct t4_bootrom br = {0}; 1963330310Snp const char *fname = argv[0]; 1964330310Snp struct stat st = {0}; 1965330310Snp 1966330310Snp if (argc == 1) { 1967330310Snp br.pf_offset = 0; 1968330310Snp br.pfidx_addr = 0; 1969330310Snp } else if (argc == 3) { 1970330310Snp if (!strcmp(argv[1], "pf")) 1971330310Snp br.pf_offset = 0; 1972330310Snp else if (!strcmp(argv[1], "offset")) 1973330310Snp br.pf_offset = 1; 1974330310Snp else 1975330310Snp return (EINVAL); 1976330310Snp 1977330310Snp p = str_to_number(argv[2], &l, NULL); 1978330310Snp if (*p) 1979330310Snp return (EINVAL); 1980330310Snp br.pfidx_addr = l; 1981330310Snp } else { 1982330310Snp warnx("loadboot: incorrect number of arguments."); 1983330310Snp return (EINVAL); 1984330310Snp } 1985330310Snp 1986330310Snp if (strcmp(fname, "clear") == 0) 1987330310Snp return (doit(CHELSIO_T4_LOAD_BOOT, &br)); 1988330310Snp 1989330310Snp fd = open(fname, O_RDONLY); 1990330310Snp if (fd < 0) { 1991330310Snp warn("open(%s)", fname); 1992330310Snp return (errno); 1993330310Snp } 1994330310Snp 1995330310Snp if (fstat(fd, &st) < 0) { 1996330310Snp warn("fstat"); 1997330310Snp close(fd); 1998330310Snp return (errno); 1999330310Snp } 2000330310Snp 2001330310Snp br.len = st.st_size; 2002330310Snp br.data = mmap(0, br.len, PROT_READ, MAP_PRIVATE, fd, 0); 2003330310Snp if (br.data == MAP_FAILED) { 2004330310Snp warn("mmap"); 2005330310Snp close(fd); 2006330310Snp return (errno); 2007330310Snp } 2008330310Snp 2009330310Snp rc = doit(CHELSIO_T4_LOAD_BOOT, &br); 2010330310Snp munmap(br.data, br.len); 2011330310Snp close(fd); 2012330310Snp return (rc); 2013330310Snp} 2014330310Snp 2015330310Snpstatic int 2016330310Snploadbootcfg(int argc, const char *argv[]) 2017330310Snp{ 2018330310Snp int rc, fd; 2019330310Snp struct t4_data bc = {0}; 2020330310Snp const char *fname = argv[0]; 2021330310Snp struct stat st = {0}; 2022330310Snp 2023330310Snp if (argc != 1) { 2024330310Snp warnx("loadbootcfg: incorrect number of arguments."); 2025330310Snp return (EINVAL); 2026330310Snp } 2027330310Snp 2028330310Snp if (strcmp(fname, "clear") == 0) 2029330310Snp return (doit(CHELSIO_T4_LOAD_BOOTCFG, &bc)); 2030330310Snp 2031330310Snp fd = open(fname, O_RDONLY); 2032330310Snp if (fd < 0) { 2033330310Snp warn("open(%s)", fname); 2034330310Snp return (errno); 2035330310Snp } 2036330310Snp 2037330310Snp if (fstat(fd, &st) < 0) { 2038330310Snp warn("fstat"); 2039330310Snp close(fd); 2040330310Snp return (errno); 2041330310Snp } 2042330310Snp 2043330310Snp bc.len = st.st_size; 2044330310Snp bc.data = mmap(0, bc.len, PROT_READ, MAP_PRIVATE, fd, 0); 2045330310Snp if (bc.data == MAP_FAILED) { 2046330310Snp warn("mmap"); 2047330310Snp close(fd); 2048330310Snp return (errno); 2049330310Snp } 2050330310Snp 2051330310Snp rc = doit(CHELSIO_T4_LOAD_BOOTCFG, &bc); 2052330310Snp munmap(bc.data, bc.len); 2053330310Snp close(fd); 2054330310Snp return (rc); 2055330310Snp} 2056330310Snp 2057228594Snp/* 2058228594Snp * Display memory as list of 'n' 4-byte values per line. 2059228594Snp */ 2060228594Snpstatic void 2061228594Snpshow_mem(uint32_t *buf, uint32_t len) 2062228594Snp{ 2063228594Snp const char *s; 2064228594Snp int i, n = 8; 2065228594Snp 2066228594Snp while (len) { 2067228594Snp for (i = 0; len && i < n; i++, buf++, len -= 4) { 2068228594Snp s = i ? " " : ""; 2069228594Snp printf("%s%08x", s, htonl(*buf)); 2070228594Snp } 2071228594Snp printf("\n"); 2072228594Snp } 2073228594Snp} 2074228594Snp 2075228594Snpstatic int 2076228594Snpmemdump(int argc, const char *argv[]) 2077228594Snp{ 2078228594Snp char *p; 2079228594Snp long l; 2080228594Snp uint32_t addr, len; 2081228594Snp 2082228594Snp if (argc != 2) { 2083228594Snp warnx("incorrect number of arguments."); 2084228594Snp return (EINVAL); 2085228594Snp } 2086228594Snp 2087228594Snp p = str_to_number(argv[0], &l, NULL); 2088228594Snp if (*p) { 2089228594Snp warnx("invalid address \"%s\"", argv[0]); 2090228594Snp return (EINVAL); 2091228594Snp } 2092228594Snp addr = l; 2093228594Snp 2094228594Snp p = str_to_number(argv[1], &l, NULL); 2095228594Snp if (*p) { 2096228594Snp warnx("memdump: invalid length \"%s\"", argv[1]); 2097228594Snp return (EINVAL); 2098228594Snp } 2099228594Snp len = l; 2100228594Snp 2101228594Snp return (read_mem(addr, len, show_mem)); 2102228594Snp} 2103228594Snp 2104228594Snp/* 2105228594Snp * Display TCB as list of 'n' 4-byte values per line. 2106228594Snp */ 2107228594Snpstatic void 2108228594Snpshow_tcb(uint32_t *buf, uint32_t len) 2109228594Snp{ 2110339393Snp unsigned char *tcb = (unsigned char *)buf; 2111228594Snp const char *s; 2112228594Snp int i, n = 8; 2113228594Snp 2114228594Snp while (len) { 2115228594Snp for (i = 0; len && i < n; i++, buf++, len -= 4) { 2116228594Snp s = i ? " " : ""; 2117228594Snp printf("%s%08x", s, htonl(*buf)); 2118228594Snp } 2119228594Snp printf("\n"); 2120228594Snp } 2121339393Snp set_tcb_info(TIDTYPE_TCB, chip_id); 2122339393Snp set_print_style(PRNTSTYL_COMP); 2123339393Snp swizzle_tcb(tcb); 2124339393Snp parse_n_display_xcb(tcb); 2125228594Snp} 2126228594Snp 2127228594Snp#define A_TP_CMM_TCB_BASE 0x7d10 2128228594Snp#define TCB_SIZE 128 2129228594Snpstatic int 2130228594Snpread_tcb(int argc, const char *argv[]) 2131228594Snp{ 2132228594Snp char *p; 2133228594Snp long l; 2134228594Snp long long val; 2135228594Snp unsigned int tid; 2136228594Snp uint32_t addr; 2137228594Snp int rc; 2138228594Snp 2139228594Snp if (argc != 1) { 2140228594Snp warnx("incorrect number of arguments."); 2141228594Snp return (EINVAL); 2142228594Snp } 2143228594Snp 2144228594Snp p = str_to_number(argv[0], &l, NULL); 2145228594Snp if (*p) { 2146228594Snp warnx("invalid tid \"%s\"", argv[0]); 2147228594Snp return (EINVAL); 2148228594Snp } 2149228594Snp tid = l; 2150228594Snp 2151228594Snp rc = read_reg(A_TP_CMM_TCB_BASE, 4, &val); 2152228594Snp if (rc != 0) 2153228594Snp return (rc); 2154228594Snp 2155228594Snp addr = val + tid * TCB_SIZE; 2156228594Snp 2157228594Snp return (read_mem(addr, TCB_SIZE, show_tcb)); 2158228594Snp} 2159228594Snp 2160228594Snpstatic int 2161241401Snpread_i2c(int argc, const char *argv[]) 2162241401Snp{ 2163241401Snp char *p; 2164241401Snp long l; 2165241401Snp struct t4_i2c_data i2cd; 2166241401Snp int rc, i; 2167241401Snp 2168241401Snp if (argc < 3 || argc > 4) { 2169241401Snp warnx("incorrect number of arguments."); 2170241401Snp return (EINVAL); 2171241401Snp } 2172241401Snp 2173241401Snp p = str_to_number(argv[0], &l, NULL); 2174241401Snp if (*p || l > UCHAR_MAX) { 2175241401Snp warnx("invalid port id \"%s\"", argv[0]); 2176241401Snp return (EINVAL); 2177241401Snp } 2178241401Snp i2cd.port_id = l; 2179241401Snp 2180241401Snp p = str_to_number(argv[1], &l, NULL); 2181241401Snp if (*p || l > UCHAR_MAX) { 2182241401Snp warnx("invalid i2c device address \"%s\"", argv[1]); 2183241401Snp return (EINVAL); 2184241401Snp } 2185241401Snp i2cd.dev_addr = l; 2186241401Snp 2187241401Snp p = str_to_number(argv[2], &l, NULL); 2188241401Snp if (*p || l > UCHAR_MAX) { 2189241401Snp warnx("invalid byte offset \"%s\"", argv[2]); 2190241401Snp return (EINVAL); 2191241401Snp } 2192241401Snp i2cd.offset = l; 2193241401Snp 2194241401Snp if (argc == 4) { 2195241401Snp p = str_to_number(argv[3], &l, NULL); 2196241401Snp if (*p || l > sizeof(i2cd.data)) { 2197241401Snp warnx("invalid number of bytes \"%s\"", argv[3]); 2198241401Snp return (EINVAL); 2199241401Snp } 2200241401Snp i2cd.len = l; 2201241401Snp } else 2202241401Snp i2cd.len = 1; 2203241401Snp 2204241401Snp rc = doit(CHELSIO_T4_GET_I2C, &i2cd); 2205241401Snp if (rc != 0) 2206241401Snp return (rc); 2207241401Snp 2208241401Snp for (i = 0; i < i2cd.len; i++) 2209241401Snp printf("0x%x [%u]\n", i2cd.data[i], i2cd.data[i]); 2210241401Snp 2211241401Snp return (0); 2212241401Snp} 2213241401Snp 2214241401Snpstatic int 2215241416Snpclearstats(int argc, const char *argv[]) 2216241416Snp{ 2217241416Snp char *p; 2218241416Snp long l; 2219241416Snp uint32_t port; 2220241416Snp 2221241416Snp if (argc != 1) { 2222241416Snp warnx("incorrect number of arguments."); 2223241416Snp return (EINVAL); 2224241416Snp } 2225241416Snp 2226241416Snp p = str_to_number(argv[0], &l, NULL); 2227241416Snp if (*p) { 2228241416Snp warnx("invalid port id \"%s\"", argv[0]); 2229241416Snp return (EINVAL); 2230241416Snp } 2231241416Snp port = l; 2232241416Snp 2233241416Snp return doit(CHELSIO_T4_CLEAR_STATS, &port); 2234241416Snp} 2235241416Snp 2236241416Snpstatic int 2237253691Snpshow_tracers(void) 2238253691Snp{ 2239253691Snp struct t4_tracer t; 2240253691Snp char *s; 2241253691Snp int rc, port_idx, i; 2242253691Snp long long val; 2243253691Snp 2244253691Snp /* Magic values: MPS_TRC_CFG = 0x9800. MPS_TRC_CFG[1:1] = TrcEn */ 2245253691Snp rc = read_reg(0x9800, 4, &val); 2246253691Snp if (rc != 0) 2247253691Snp return (rc); 2248253691Snp printf("tracing is %s\n", val & 2 ? "ENABLED" : "DISABLED"); 2249253691Snp 2250253691Snp t.idx = 0; 2251253691Snp for (t.idx = 0; ; t.idx++) { 2252253691Snp rc = doit(CHELSIO_T4_GET_TRACER, &t); 2253253691Snp if (rc != 0 || t.idx == 0xff) 2254253691Snp break; 2255253691Snp 2256253691Snp if (t.tp.port < 4) { 2257253691Snp s = "Rx"; 2258253691Snp port_idx = t.tp.port; 2259253691Snp } else if (t.tp.port < 8) { 2260253691Snp s = "Tx"; 2261253691Snp port_idx = t.tp.port - 4; 2262253691Snp } else if (t.tp.port < 12) { 2263253691Snp s = "loopback"; 2264253691Snp port_idx = t.tp.port - 8; 2265253691Snp } else if (t.tp.port < 16) { 2266253691Snp s = "MPS Rx"; 2267253691Snp port_idx = t.tp.port - 12; 2268253691Snp } else if (t.tp.port < 20) { 2269253691Snp s = "MPS Tx"; 2270253691Snp port_idx = t.tp.port - 16; 2271253691Snp } else { 2272253691Snp s = "unknown"; 2273253691Snp port_idx = t.tp.port; 2274253691Snp } 2275253691Snp 2276253691Snp printf("\ntracer %u (currently %s) captures ", t.idx, 2277253691Snp t.enabled ? "ENABLED" : "DISABLED"); 2278253691Snp if (t.tp.port < 8) 2279253691Snp printf("port %u %s, ", port_idx, s); 2280253691Snp else 2281253691Snp printf("%s %u, ", s, port_idx); 2282253691Snp printf("snap length: %u, min length: %u\n", t.tp.snap_len, 2283253691Snp t.tp.min_len); 2284253691Snp printf("packets captured %smatch filter\n", 2285253691Snp t.tp.invert ? "do not " : ""); 2286253691Snp if (t.tp.skip_ofst) { 2287253691Snp printf("filter pattern: "); 2288253691Snp for (i = 0; i < t.tp.skip_ofst * 2; i += 2) 2289253691Snp printf("%08x%08x", t.tp.data[i], 2290253691Snp t.tp.data[i + 1]); 2291253691Snp printf("/"); 2292253691Snp for (i = 0; i < t.tp.skip_ofst * 2; i += 2) 2293253691Snp printf("%08x%08x", t.tp.mask[i], 2294253691Snp t.tp.mask[i + 1]); 2295253691Snp printf("@0\n"); 2296253691Snp } 2297253691Snp printf("filter pattern: "); 2298253691Snp for (i = t.tp.skip_ofst * 2; i < T4_TRACE_LEN / 4; i += 2) 2299253691Snp printf("%08x%08x", t.tp.data[i], t.tp.data[i + 1]); 2300253691Snp printf("/"); 2301253691Snp for (i = t.tp.skip_ofst * 2; i < T4_TRACE_LEN / 4; i += 2) 2302253691Snp printf("%08x%08x", t.tp.mask[i], t.tp.mask[i + 1]); 2303253691Snp printf("@%u\n", (t.tp.skip_ofst + t.tp.skip_len) * 8); 2304253691Snp } 2305253691Snp 2306253691Snp return (rc); 2307253691Snp} 2308253691Snp 2309253691Snpstatic int 2310253691Snptracer_onoff(uint8_t idx, int enabled) 2311253691Snp{ 2312253691Snp struct t4_tracer t; 2313253691Snp 2314253691Snp t.idx = idx; 2315253691Snp t.enabled = enabled; 2316253691Snp t.valid = 0; 2317253691Snp 2318253691Snp return doit(CHELSIO_T4_SET_TRACER, &t); 2319253691Snp} 2320253691Snp 2321253691Snpstatic void 2322253691Snpcreate_tracing_ifnet() 2323253691Snp{ 2324253691Snp char *cmd[] = { 2325253691Snp "/sbin/ifconfig", __DECONST(char *, nexus), "create", NULL 2326253691Snp }; 2327253691Snp char *env[] = {NULL}; 2328253691Snp 2329253691Snp if (vfork() == 0) { 2330253691Snp close(STDERR_FILENO); 2331253691Snp execve(cmd[0], cmd, env); 2332253691Snp _exit(0); 2333253691Snp } 2334253691Snp} 2335253691Snp 2336253691Snp/* 2337253691Snp * XXX: Allow user to specify snaplen, minlen, and pattern (including inverted 2338253691Snp * matching). Right now this is a quick-n-dirty implementation that traces the 2339253691Snp * first 128B of all tx or rx on a port 2340253691Snp */ 2341253691Snpstatic int 2342253691Snpset_tracer(uint8_t idx, int argc, const char *argv[]) 2343253691Snp{ 2344253691Snp struct t4_tracer t; 2345253691Snp int len, port; 2346253691Snp 2347253691Snp bzero(&t, sizeof (t)); 2348253691Snp t.idx = idx; 2349253691Snp t.enabled = 1; 2350253691Snp t.valid = 1; 2351253691Snp 2352253691Snp if (argc != 1) { 2353253691Snp warnx("must specify tx<n> or rx<n>."); 2354253691Snp return (EINVAL); 2355253691Snp } 2356253691Snp 2357253691Snp len = strlen(argv[0]); 2358253691Snp if (len != 3) { 2359253691Snp warnx("argument must be 3 characters (tx<n> or rx<n>)"); 2360253691Snp return (EINVAL); 2361253691Snp } 2362253691Snp 2363253691Snp if (strncmp(argv[0], "tx", 2) == 0) { 2364253691Snp port = argv[0][2] - '0'; 2365253691Snp if (port < 0 || port > 3) { 2366253691Snp warnx("'%c' in %s is invalid", argv[0][2], argv[0]); 2367253691Snp return (EINVAL); 2368253691Snp } 2369253691Snp port += 4; 2370253691Snp } else if (strncmp(argv[0], "rx", 2) == 0) { 2371253691Snp port = argv[0][2] - '0'; 2372253691Snp if (port < 0 || port > 3) { 2373253691Snp warnx("'%c' in %s is invalid", argv[0][2], argv[0]); 2374253691Snp return (EINVAL); 2375253691Snp } 2376253691Snp } else { 2377253691Snp warnx("argument '%s' isn't tx<n> or rx<n>", argv[0]); 2378253691Snp return (EINVAL); 2379253691Snp } 2380253691Snp 2381253691Snp t.tp.snap_len = 128; 2382253691Snp t.tp.min_len = 0; 2383253691Snp t.tp.skip_ofst = 0; 2384253691Snp t.tp.skip_len = 0; 2385253691Snp t.tp.invert = 0; 2386253691Snp t.tp.port = port; 2387253691Snp 2388253691Snp create_tracing_ifnet(); 2389253691Snp return doit(CHELSIO_T4_SET_TRACER, &t); 2390253691Snp} 2391253691Snp 2392253691Snpstatic int 2393259048Snptracer_cmd(int argc, const char *argv[]) 2394259048Snp{ 2395259048Snp long long val; 2396259048Snp uint8_t idx; 2397259048Snp char *s; 2398259048Snp 2399259048Snp if (argc == 0) { 2400259048Snp warnx("tracer: no arguments."); 2401259048Snp return (EINVAL); 2402259048Snp }; 2403259048Snp 2404259048Snp /* list */ 2405259048Snp if (strcmp(argv[0], "list") == 0) { 2406259048Snp if (argc != 1) 2407259048Snp warnx("trailing arguments after \"list\" ignored."); 2408259048Snp 2409259048Snp return show_tracers(); 2410259048Snp } 2411259048Snp 2412259048Snp /* <idx> ... */ 2413259048Snp s = str_to_number(argv[0], NULL, &val); 2414259048Snp if (*s || val > 0xff) { 2415259048Snp warnx("\"%s\" is neither an index nor a tracer subcommand.", 2416259048Snp argv[0]); 2417259048Snp return (EINVAL); 2418259048Snp } 2419259048Snp idx = (int8_t)val; 2420259048Snp 2421259048Snp /* <idx> disable */ 2422259048Snp if (argc == 2 && strcmp(argv[1], "disable") == 0) 2423259048Snp return tracer_onoff(idx, 0); 2424259048Snp 2425259048Snp /* <idx> enable */ 2426259048Snp if (argc == 2 && strcmp(argv[1], "enable") == 0) 2427259048Snp return tracer_onoff(idx, 1); 2428259048Snp 2429259048Snp /* <idx> ... */ 2430259048Snp return set_tracer(idx, argc - 1, argv + 1); 2431259048Snp} 2432259048Snp 2433259048Snpstatic int 2434269106Snpmodinfo_raw(int port_id) 2435269106Snp{ 2436269106Snp uint8_t offset; 2437269106Snp struct t4_i2c_data i2cd; 2438269106Snp int rc; 2439269106Snp 2440269106Snp for (offset = 0; offset < 96; offset += sizeof(i2cd.data)) { 2441269106Snp bzero(&i2cd, sizeof(i2cd)); 2442269106Snp i2cd.port_id = port_id; 2443269106Snp i2cd.dev_addr = 0xa0; 2444269106Snp i2cd.offset = offset; 2445269106Snp i2cd.len = sizeof(i2cd.data); 2446269106Snp rc = doit(CHELSIO_T4_GET_I2C, &i2cd); 2447269106Snp if (rc != 0) 2448269106Snp return (rc); 2449269106Snp printf("%02x: %02x %02x %02x %02x %02x %02x %02x %02x", 2450269106Snp offset, i2cd.data[0], i2cd.data[1], i2cd.data[2], 2451269106Snp i2cd.data[3], i2cd.data[4], i2cd.data[5], i2cd.data[6], 2452269106Snp i2cd.data[7]); 2453269106Snp 2454269106Snp printf(" %c%c%c%c %c%c%c%c\n", 2455269106Snp isprint(i2cd.data[0]) ? i2cd.data[0] : '.', 2456269106Snp isprint(i2cd.data[1]) ? i2cd.data[1] : '.', 2457269106Snp isprint(i2cd.data[2]) ? i2cd.data[2] : '.', 2458269106Snp isprint(i2cd.data[3]) ? i2cd.data[3] : '.', 2459269106Snp isprint(i2cd.data[4]) ? i2cd.data[4] : '.', 2460269106Snp isprint(i2cd.data[5]) ? i2cd.data[5] : '.', 2461269106Snp isprint(i2cd.data[6]) ? i2cd.data[6] : '.', 2462269106Snp isprint(i2cd.data[7]) ? i2cd.data[7] : '.'); 2463269106Snp } 2464269106Snp 2465269106Snp return (0); 2466269106Snp} 2467269106Snp 2468269106Snpstatic int 2469258698Snpmodinfo(int argc, const char *argv[]) 2470258698Snp{ 2471258698Snp long port; 2472258698Snp char string[16], *p; 2473258698Snp struct t4_i2c_data i2cd; 2474258698Snp int rc, i; 2475258698Snp uint16_t temp, vcc, tx_bias, tx_power, rx_power; 2476258698Snp 2477269106Snp if (argc < 1) { 2478258698Snp warnx("must supply a port"); 2479258698Snp return (EINVAL); 2480258698Snp } 2481258698Snp 2482269106Snp if (argc > 2) { 2483269106Snp warnx("too many arguments"); 2484269106Snp return (EINVAL); 2485269106Snp } 2486269106Snp 2487258698Snp p = str_to_number(argv[0], &port, NULL); 2488258698Snp if (*p || port > UCHAR_MAX) { 2489258698Snp warnx("invalid port id \"%s\"", argv[0]); 2490258698Snp return (EINVAL); 2491258698Snp } 2492258698Snp 2493269106Snp if (argc == 2) { 2494269106Snp if (!strcmp(argv[1], "raw")) 2495269106Snp return (modinfo_raw(port)); 2496269106Snp else { 2497269106Snp warnx("second argument can only be \"raw\""); 2498269106Snp return (EINVAL); 2499269106Snp } 2500269106Snp } 2501269106Snp 2502258698Snp bzero(&i2cd, sizeof(i2cd)); 2503258698Snp i2cd.len = 1; 2504258698Snp i2cd.port_id = port; 2505258698Snp i2cd.dev_addr = SFF_8472_BASE; 2506258698Snp 2507258698Snp i2cd.offset = SFF_8472_ID; 2508258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2509258698Snp goto fail; 2510258698Snp 2511258698Snp if (i2cd.data[0] > SFF_8472_ID_LAST) 2512258698Snp printf("Unknown ID\n"); 2513258698Snp else 2514258698Snp printf("ID: %s\n", sff_8472_id[i2cd.data[0]]); 2515258698Snp 2516258698Snp bzero(&string, sizeof(string)); 2517258698Snp for (i = SFF_8472_VENDOR_START; i < SFF_8472_VENDOR_END; i++) { 2518258698Snp i2cd.offset = i; 2519258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2520258698Snp goto fail; 2521258698Snp string[i - SFF_8472_VENDOR_START] = i2cd.data[0]; 2522258698Snp } 2523258698Snp printf("Vendor %s\n", string); 2524258698Snp 2525258698Snp bzero(&string, sizeof(string)); 2526258698Snp for (i = SFF_8472_SN_START; i < SFF_8472_SN_END; i++) { 2527258698Snp i2cd.offset = i; 2528258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2529258698Snp goto fail; 2530258698Snp string[i - SFF_8472_SN_START] = i2cd.data[0]; 2531258698Snp } 2532258698Snp printf("SN %s\n", string); 2533258698Snp 2534258698Snp bzero(&string, sizeof(string)); 2535258698Snp for (i = SFF_8472_PN_START; i < SFF_8472_PN_END; i++) { 2536258698Snp i2cd.offset = i; 2537258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2538258698Snp goto fail; 2539258698Snp string[i - SFF_8472_PN_START] = i2cd.data[0]; 2540258698Snp } 2541258698Snp printf("PN %s\n", string); 2542258698Snp 2543258698Snp bzero(&string, sizeof(string)); 2544258698Snp for (i = SFF_8472_REV_START; i < SFF_8472_REV_END; i++) { 2545258698Snp i2cd.offset = i; 2546258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2547258698Snp goto fail; 2548258698Snp string[i - SFF_8472_REV_START] = i2cd.data[0]; 2549258698Snp } 2550258698Snp printf("Rev %s\n", string); 2551258698Snp 2552258698Snp i2cd.offset = SFF_8472_DIAG_TYPE; 2553258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2554258698Snp goto fail; 2555258698Snp 2556258698Snp if ((char )i2cd.data[0] & (SFF_8472_DIAG_IMPL | 2557258698Snp SFF_8472_DIAG_INTERNAL)) { 2558258698Snp 2559258698Snp /* Switch to reading from the Diagnostic address. */ 2560258698Snp i2cd.dev_addr = SFF_8472_DIAG; 2561258698Snp i2cd.len = 1; 2562258698Snp 2563258698Snp i2cd.offset = SFF_8472_TEMP; 2564258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2565258698Snp goto fail; 2566258698Snp temp = i2cd.data[0] << 8; 2567258698Snp printf("Temp: "); 2568258698Snp if ((temp & SFF_8472_TEMP_SIGN) == SFF_8472_TEMP_SIGN) 2569258698Snp printf("-"); 2570258698Snp else 2571258698Snp printf("+"); 2572258698Snp printf("%dC\n", (temp & SFF_8472_TEMP_MSK) >> 2573258698Snp SFF_8472_TEMP_SHIFT); 2574258698Snp 2575258698Snp i2cd.offset = SFF_8472_VCC; 2576258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2577258698Snp goto fail; 2578258698Snp vcc = i2cd.data[0] << 8; 2579258698Snp printf("Vcc %fV\n", vcc / SFF_8472_VCC_FACTOR); 2580258698Snp 2581258698Snp i2cd.offset = SFF_8472_TX_BIAS; 2582258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2583258698Snp goto fail; 2584258698Snp tx_bias = i2cd.data[0] << 8; 2585258698Snp printf("TX Bias %fuA\n", tx_bias / SFF_8472_BIAS_FACTOR); 2586258698Snp 2587258698Snp i2cd.offset = SFF_8472_TX_POWER; 2588258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2589258698Snp goto fail; 2590258698Snp tx_power = i2cd.data[0] << 8; 2591258698Snp printf("TX Power %fmW\n", tx_power / SFF_8472_POWER_FACTOR); 2592258698Snp 2593258698Snp i2cd.offset = SFF_8472_RX_POWER; 2594258698Snp if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0) 2595258698Snp goto fail; 2596258698Snp rx_power = i2cd.data[0] << 8; 2597258698Snp printf("RX Power %fmW\n", rx_power / SFF_8472_POWER_FACTOR); 2598258698Snp 2599258698Snp } else 2600258698Snp printf("Diagnostics not supported.\n"); 2601258698Snp 2602258698Snp return(0); 2603258698Snp 2604258698Snpfail: 2605258698Snp if (rc == EPERM) 2606258698Snp warnx("No module/cable in port %ld", port); 2607258698Snp return (rc); 2608258698Snp 2609258698Snp} 2610258698Snp 2611259048Snp/* XXX: pass in a low/high and do range checks as well */ 2612258698Snpstatic int 2613259048Snpget_sched_param(const char *param, const char *args[], long *val) 2614253691Snp{ 2615259048Snp char *p; 2616253691Snp 2617259048Snp if (strcmp(param, args[0]) != 0) 2618259048Snp return (EINVAL); 2619259048Snp 2620259048Snp p = str_to_number(args[1], val, NULL); 2621259048Snp if (*p) { 2622259048Snp warnx("parameter \"%s\" has bad value \"%s\"", args[0], 2623259048Snp args[1]); 2624259048Snp return (EINVAL); 2625259048Snp } 2626259048Snp 2627259048Snp return (0); 2628259048Snp} 2629259048Snp 2630259048Snpstatic int 2631259048Snpsched_class(int argc, const char *argv[]) 2632259048Snp{ 2633259048Snp struct t4_sched_params op; 2634259048Snp int errs, i; 2635259048Snp 2636259048Snp memset(&op, 0xff, sizeof(op)); 2637259048Snp op.subcmd = -1; 2638259048Snp op.type = -1; 2639253691Snp if (argc == 0) { 2640259048Snp warnx("missing scheduling sub-command"); 2641253691Snp return (EINVAL); 2642259048Snp } 2643259048Snp if (!strcmp(argv[0], "config")) { 2644259048Snp op.subcmd = SCHED_CLASS_SUBCMD_CONFIG; 2645259048Snp op.u.config.minmax = -1; 2646259048Snp } else if (!strcmp(argv[0], "params")) { 2647259048Snp op.subcmd = SCHED_CLASS_SUBCMD_PARAMS; 2648259048Snp op.u.params.level = op.u.params.mode = op.u.params.rateunit = 2649259048Snp op.u.params.ratemode = op.u.params.channel = 2650259048Snp op.u.params.cl = op.u.params.minrate = op.u.params.maxrate = 2651259048Snp op.u.params.weight = op.u.params.pktsize = -1; 2652259048Snp } else { 2653259048Snp warnx("invalid scheduling sub-command \"%s\"", argv[0]); 2654259048Snp return (EINVAL); 2655259048Snp } 2656253691Snp 2657259048Snp /* Decode remaining arguments ... */ 2658259048Snp errs = 0; 2659259048Snp for (i = 1; i < argc; i += 2) { 2660259048Snp const char **args = &argv[i]; 2661259048Snp long l; 2662253691Snp 2663259048Snp if (i + 1 == argc) { 2664259048Snp warnx("missing argument for \"%s\"", args[0]); 2665259048Snp errs++; 2666259048Snp break; 2667259048Snp } 2668259048Snp 2669259048Snp if (!strcmp(args[0], "type")) { 2670259048Snp if (!strcmp(args[1], "packet")) 2671259048Snp op.type = SCHED_CLASS_TYPE_PACKET; 2672259048Snp else { 2673259048Snp warnx("invalid type parameter \"%s\"", args[1]); 2674259048Snp errs++; 2675259048Snp } 2676259048Snp 2677259048Snp continue; 2678259048Snp } 2679259048Snp 2680259048Snp if (op.subcmd == SCHED_CLASS_SUBCMD_CONFIG) { 2681259048Snp if(!get_sched_param("minmax", args, &l)) 2682259048Snp op.u.config.minmax = (int8_t)l; 2683259048Snp else { 2684259048Snp warnx("unknown scheduler config parameter " 2685259048Snp "\"%s\"", args[0]); 2686259048Snp errs++; 2687259048Snp } 2688259048Snp 2689259048Snp continue; 2690259048Snp } 2691259048Snp 2692259048Snp /* Rest applies only to SUBCMD_PARAMS */ 2693259048Snp if (op.subcmd != SCHED_CLASS_SUBCMD_PARAMS) 2694259048Snp continue; 2695259048Snp 2696259048Snp if (!strcmp(args[0], "level")) { 2697259048Snp if (!strcmp(args[1], "cl-rl")) 2698259048Snp op.u.params.level = SCHED_CLASS_LEVEL_CL_RL; 2699259048Snp else if (!strcmp(args[1], "cl-wrr")) 2700259048Snp op.u.params.level = SCHED_CLASS_LEVEL_CL_WRR; 2701259048Snp else if (!strcmp(args[1], "ch-rl")) 2702259048Snp op.u.params.level = SCHED_CLASS_LEVEL_CH_RL; 2703259048Snp else { 2704259048Snp warnx("invalid level parameter \"%s\"", 2705259048Snp args[1]); 2706259048Snp errs++; 2707259048Snp } 2708259048Snp } else if (!strcmp(args[0], "mode")) { 2709259048Snp if (!strcmp(args[1], "class")) 2710259048Snp op.u.params.mode = SCHED_CLASS_MODE_CLASS; 2711259048Snp else if (!strcmp(args[1], "flow")) 2712259048Snp op.u.params.mode = SCHED_CLASS_MODE_FLOW; 2713259048Snp else { 2714259048Snp warnx("invalid mode parameter \"%s\"", args[1]); 2715259048Snp errs++; 2716259048Snp } 2717259048Snp } else if (!strcmp(args[0], "rate-unit")) { 2718259048Snp if (!strcmp(args[1], "bits")) 2719259048Snp op.u.params.rateunit = SCHED_CLASS_RATEUNIT_BITS; 2720259048Snp else if (!strcmp(args[1], "pkts")) 2721259048Snp op.u.params.rateunit = SCHED_CLASS_RATEUNIT_PKTS; 2722259048Snp else { 2723259048Snp warnx("invalid rate-unit parameter \"%s\"", 2724259048Snp args[1]); 2725259048Snp errs++; 2726259048Snp } 2727259048Snp } else if (!strcmp(args[0], "rate-mode")) { 2728259048Snp if (!strcmp(args[1], "relative")) 2729259048Snp op.u.params.ratemode = SCHED_CLASS_RATEMODE_REL; 2730259048Snp else if (!strcmp(args[1], "absolute")) 2731259048Snp op.u.params.ratemode = SCHED_CLASS_RATEMODE_ABS; 2732259048Snp else { 2733259048Snp warnx("invalid rate-mode parameter \"%s\"", 2734259048Snp args[1]); 2735259048Snp errs++; 2736259048Snp } 2737259048Snp } else if (!get_sched_param("channel", args, &l)) 2738259048Snp op.u.params.channel = (int8_t)l; 2739259048Snp else if (!get_sched_param("class", args, &l)) 2740259048Snp op.u.params.cl = (int8_t)l; 2741259048Snp else if (!get_sched_param("min-rate", args, &l)) 2742259048Snp op.u.params.minrate = (int32_t)l; 2743259048Snp else if (!get_sched_param("max-rate", args, &l)) 2744259048Snp op.u.params.maxrate = (int32_t)l; 2745259048Snp else if (!get_sched_param("weight", args, &l)) 2746259048Snp op.u.params.weight = (int16_t)l; 2747259048Snp else if (!get_sched_param("pkt-size", args, &l)) 2748259048Snp op.u.params.pktsize = (int16_t)l; 2749259048Snp else { 2750259048Snp warnx("unknown scheduler parameter \"%s\"", args[0]); 2751259048Snp errs++; 2752259048Snp } 2753253691Snp } 2754253691Snp 2755259048Snp /* 2756259048Snp * Catch some logical fallacies in terms of argument combinations here 2757259048Snp * so we can offer more than just the EINVAL return from the driver. 2758259048Snp * The driver will be able to catch a lot more issues since it knows 2759259048Snp * the specifics of the device hardware capabilities like how many 2760259048Snp * channels, classes, etc. the device supports. 2761259048Snp */ 2762259048Snp if (op.type < 0) { 2763259048Snp warnx("sched \"type\" parameter missing"); 2764259048Snp errs++; 2765259048Snp } 2766259048Snp if (op.subcmd == SCHED_CLASS_SUBCMD_CONFIG) { 2767259048Snp if (op.u.config.minmax < 0) { 2768259048Snp warnx("sched config \"minmax\" parameter missing"); 2769259048Snp errs++; 2770259048Snp } 2771259048Snp } 2772259048Snp if (op.subcmd == SCHED_CLASS_SUBCMD_PARAMS) { 2773259048Snp if (op.u.params.level < 0) { 2774259048Snp warnx("sched params \"level\" parameter missing"); 2775259048Snp errs++; 2776259048Snp } 2777259048Snp if (op.u.params.mode < 0) { 2778259048Snp warnx("sched params \"mode\" parameter missing"); 2779259048Snp errs++; 2780259048Snp } 2781259048Snp if (op.u.params.rateunit < 0) { 2782259048Snp warnx("sched params \"rate-unit\" parameter missing"); 2783259048Snp errs++; 2784259048Snp } 2785259048Snp if (op.u.params.ratemode < 0) { 2786259048Snp warnx("sched params \"rate-mode\" parameter missing"); 2787259048Snp errs++; 2788259048Snp } 2789259048Snp if (op.u.params.channel < 0) { 2790259048Snp warnx("sched params \"channel\" missing"); 2791259048Snp errs++; 2792259048Snp } 2793259048Snp if (op.u.params.cl < 0) { 2794259048Snp warnx("sched params \"class\" missing"); 2795259048Snp errs++; 2796259048Snp } 2797259048Snp if (op.u.params.maxrate < 0 && 2798259048Snp (op.u.params.level == SCHED_CLASS_LEVEL_CL_RL || 2799259048Snp op.u.params.level == SCHED_CLASS_LEVEL_CH_RL)) { 2800259048Snp warnx("sched params \"max-rate\" missing for " 2801259048Snp "rate-limit level"); 2802259048Snp errs++; 2803259048Snp } 2804259048Snp if (op.u.params.weight < 0 && 2805259048Snp op.u.params.level == SCHED_CLASS_LEVEL_CL_WRR) { 2806259048Snp warnx("sched params \"weight\" missing for " 2807259048Snp "weighted-round-robin level"); 2808259048Snp errs++; 2809259048Snp } 2810259048Snp if (op.u.params.pktsize < 0 && 2811259048Snp (op.u.params.level == SCHED_CLASS_LEVEL_CL_RL || 2812259048Snp op.u.params.level == SCHED_CLASS_LEVEL_CH_RL)) { 2813259048Snp warnx("sched params \"pkt-size\" missing for " 2814259048Snp "rate-limit level"); 2815259048Snp errs++; 2816259048Snp } 2817259048Snp if (op.u.params.mode == SCHED_CLASS_MODE_FLOW && 2818259048Snp op.u.params.ratemode != SCHED_CLASS_RATEMODE_ABS) { 2819259048Snp warnx("sched params mode flow needs rate-mode absolute"); 2820259048Snp errs++; 2821259048Snp } 2822259048Snp if (op.u.params.ratemode == SCHED_CLASS_RATEMODE_REL && 2823259048Snp !in_range(op.u.params.maxrate, 1, 100)) { 2824259048Snp warnx("sched params \"max-rate\" takes " 2825259048Snp "percentage value(1-100) for rate-mode relative"); 2826259048Snp errs++; 2827259048Snp } 2828259048Snp if (op.u.params.ratemode == SCHED_CLASS_RATEMODE_ABS && 2829301516Snp !in_range(op.u.params.maxrate, 1, 100000000)) { 2830259048Snp warnx("sched params \"max-rate\" takes " 2831301516Snp "value(1-100000000) for rate-mode absolute"); 2832259048Snp errs++; 2833259048Snp } 2834259048Snp if (op.u.params.maxrate > 0 && 2835259048Snp op.u.params.maxrate < op.u.params.minrate) { 2836259048Snp warnx("sched params \"max-rate\" is less than " 2837259048Snp "\"min-rate\""); 2838259048Snp errs++; 2839259048Snp } 2840259048Snp } 2841259048Snp 2842259048Snp if (errs > 0) { 2843259048Snp warnx("%d error%s in sched-class command", errs, 2844259048Snp errs == 1 ? "" : "s"); 2845253691Snp return (EINVAL); 2846253691Snp } 2847253691Snp 2848259048Snp return doit(CHELSIO_T4_SCHED_CLASS, &op); 2849259048Snp} 2850253691Snp 2851259048Snpstatic int 2852259048Snpsched_queue(int argc, const char *argv[]) 2853259048Snp{ 2854259048Snp struct t4_sched_queue op = {0}; 2855259048Snp char *p; 2856259048Snp long val; 2857253691Snp 2858259048Snp if (argc != 3) { 2859259048Snp /* need "<port> <queue> <class> */ 2860259048Snp warnx("incorrect number of arguments."); 2861259048Snp return (EINVAL); 2862259048Snp } 2863259048Snp 2864259048Snp p = str_to_number(argv[0], &val, NULL); 2865259048Snp if (*p || val > UCHAR_MAX) { 2866259048Snp warnx("invalid port id \"%s\"", argv[0]); 2867259048Snp return (EINVAL); 2868259048Snp } 2869259048Snp op.port = (uint8_t)val; 2870259048Snp 2871259048Snp if (!strcmp(argv[1], "all") || !strcmp(argv[1], "*")) 2872259048Snp op.queue = -1; 2873259048Snp else { 2874259048Snp p = str_to_number(argv[1], &val, NULL); 2875259048Snp if (*p || val < -1) { 2876259048Snp warnx("invalid queue \"%s\"", argv[1]); 2877259048Snp return (EINVAL); 2878259048Snp } 2879259048Snp op.queue = (int8_t)val; 2880259048Snp } 2881259048Snp 2882259048Snp if (!strcmp(argv[2], "unbind") || !strcmp(argv[2], "clear")) 2883259048Snp op.cl = -1; 2884259048Snp else { 2885259048Snp p = str_to_number(argv[2], &val, NULL); 2886259048Snp if (*p || val < -1) { 2887259048Snp warnx("invalid class \"%s\"", argv[2]); 2888259048Snp return (EINVAL); 2889259048Snp } 2890259048Snp op.cl = (int8_t)val; 2891259048Snp } 2892259048Snp 2893259048Snp return doit(CHELSIO_T4_SCHED_QUEUE, &op); 2894253691Snp} 2895253691Snp 2896253691Snpstatic int 2897346805Snpparse_offload_settings_word(const char *s, char **pnext, const char *ws, 2898346805Snp int *pneg, struct offload_settings *os) 2899346805Snp{ 2900346805Snp 2901346805Snp while (*s == '!') { 2902346805Snp (*pneg)++; 2903346805Snp s++; 2904346805Snp } 2905346805Snp 2906346805Snp if (!strcmp(s, "not")) { 2907346805Snp (*pneg)++; 2908346805Snp return (0); 2909346805Snp } 2910346805Snp 2911346805Snp if (!strcmp(s, "offload")) { 2912346805Snp os->offload = (*pneg + 1) & 1; 2913346805Snp *pneg = 0; 2914346805Snp } else if (!strcmp(s , "coalesce")) { 2915346805Snp os->rx_coalesce = (*pneg + 1) & 1; 2916346805Snp *pneg = 0; 2917346805Snp } else if (!strcmp(s, "timestamp") || !strcmp(s, "tstamp")) { 2918346805Snp os->tstamp = (*pneg + 1) & 1; 2919346805Snp *pneg = 0; 2920346805Snp } else if (!strcmp(s, "sack")) { 2921346805Snp os->sack = (*pneg + 1) & 1; 2922346805Snp *pneg = 0; 2923346805Snp } else if (!strcmp(s, "nagle")) { 2924346805Snp os->nagle = (*pneg + 1) & 1; 2925346805Snp *pneg = 0; 2926346805Snp } else if (!strcmp(s, "ecn")) { 2927346805Snp os->ecn = (*pneg + 1) & 1; 2928346805Snp *pneg = 0; 2929346805Snp } else if (!strcmp(s, "ddp")) { 2930346805Snp os->ddp = (*pneg + 1) & 1; 2931346805Snp *pneg = 0; 2932346805Snp } else if (!strcmp(s, "tls")) { 2933346805Snp os->tls = (*pneg + 1) & 1; 2934346805Snp *pneg = 0; 2935346805Snp } else { 2936346805Snp char *param, *p; 2937346805Snp long val; 2938346805Snp 2939346805Snp /* Settings with additional parameter handled here. */ 2940346805Snp 2941346805Snp if (*pneg) { 2942346805Snp warnx("\"%s\" is not a valid keyword, or it does not " 2943346805Snp "support negation.", s); 2944346805Snp return (EINVAL); 2945346805Snp } 2946346805Snp 2947346805Snp while ((param = strsep(pnext, ws)) != NULL) { 2948346805Snp if (*param != '\0') 2949346805Snp break; 2950346805Snp } 2951346805Snp if (param == NULL) { 2952346805Snp warnx("\"%s\" is not a valid keyword, or it requires a " 2953346805Snp "parameter that has not been provided.", s); 2954346805Snp return (EINVAL); 2955346805Snp } 2956346805Snp 2957346805Snp if (!strcmp(s, "cong")) { 2958346805Snp if (!strcmp(param, "reno")) 2959346805Snp os->cong_algo = 0; 2960346805Snp else if (!strcmp(param, "tahoe")) 2961346805Snp os->cong_algo = 1; 2962346805Snp else if (!strcmp(param, "newreno")) 2963346805Snp os->cong_algo = 2; 2964346805Snp else if (!strcmp(param, "highspeed")) 2965346805Snp os->cong_algo = 3; 2966346805Snp else { 2967346805Snp warnx("unknown congestion algorithm \"%s\".", s); 2968346805Snp return (EINVAL); 2969346805Snp } 2970346805Snp } else if (!strcmp(s, "class")) { 2971346805Snp val = -1; 2972346805Snp p = str_to_number(param, &val, NULL); 2973346805Snp /* (nsched_cls - 1) is spelled 15 here. */ 2974346805Snp if (*p || val < 0 || val > 15) { 2975346805Snp warnx("invalid scheduling class \"%s\". " 2976346805Snp "\"class\" needs an integer value where " 2977346805Snp "0 <= value <= 15", param); 2978346805Snp return (EINVAL); 2979346805Snp } 2980346805Snp os->sched_class = val; 2981346805Snp } else if (!strcmp(s, "bind") || !strcmp(s, "txq") || 2982346805Snp !strcmp(s, "rxq")) { 2983346805Snp val = -1; 2984346805Snp if (strcmp(param, "random")) { 2985346805Snp p = str_to_number(param, &val, NULL); 2986346805Snp if (*p || val < 0 || val > 0xffff) { 2987346805Snp warnx("invalid queue specification " 2988346805Snp "\"%s\". \"%s\" needs an integer" 2989346805Snp " value, or \"random\".", 2990346805Snp param, s); 2991346805Snp return (EINVAL); 2992346805Snp } 2993346805Snp } 2994346805Snp if (!strcmp(s, "bind")) { 2995346805Snp os->txq = val; 2996346805Snp os->rxq = val; 2997346805Snp } else if (!strcmp(s, "txq")) { 2998346805Snp os->txq = val; 2999346805Snp } else if (!strcmp(s, "rxq")) { 3000346805Snp os->rxq = val; 3001346805Snp } else { 3002346805Snp return (EDOOFUS); 3003346805Snp } 3004346805Snp } else if (!strcmp(s, "mss")) { 3005346805Snp val = -1; 3006346805Snp p = str_to_number(param, &val, NULL); 3007346805Snp if (*p || val <= 0) { 3008346805Snp warnx("invalid MSS specification \"%s\". " 3009346805Snp "\"mss\" needs a positive integer value", 3010346805Snp param); 3011346805Snp return (EINVAL); 3012346805Snp } 3013346805Snp os->mss = val; 3014346805Snp } else { 3015346805Snp warnx("unknown settings keyword: \"%s\"", s); 3016346805Snp return (EINVAL); 3017346805Snp } 3018346805Snp } 3019346805Snp 3020346805Snp return (0); 3021346805Snp} 3022346805Snp 3023346805Snpstatic int 3024346805Snpparse_offload_settings(const char *settings_ro, struct offload_settings *os) 3025346805Snp{ 3026346805Snp const char *ws = " \f\n\r\v\t"; 3027346805Snp char *settings, *s, *next; 3028346805Snp int rc, nsettings, neg; 3029346805Snp static const struct offload_settings default_settings = { 3030346805Snp .offload = 0, /* No settings imply !offload */ 3031346805Snp .rx_coalesce = -1, 3032346805Snp .cong_algo = -1, 3033346805Snp .sched_class = -1, 3034346805Snp .tstamp = -1, 3035346805Snp .sack = -1, 3036346805Snp .nagle = -1, 3037346805Snp .ecn = -1, 3038346805Snp .ddp = -1, 3039346805Snp .tls = -1, 3040346805Snp .txq = -1, 3041346805Snp .rxq = -1, 3042346805Snp .mss = -1, 3043346805Snp }; 3044346805Snp 3045346805Snp *os = default_settings; 3046346805Snp 3047346805Snp next = settings = strdup(settings_ro); 3048346805Snp if (settings == NULL) { 3049346805Snp warn (NULL); 3050346805Snp return (errno); 3051346805Snp } 3052346805Snp 3053346805Snp nsettings = 0; 3054346805Snp rc = 0; 3055346805Snp neg = 0; 3056346805Snp while ((s = strsep(&next, ws)) != NULL) { 3057346805Snp if (*s == '\0') 3058346805Snp continue; 3059346805Snp nsettings++; 3060346805Snp rc = parse_offload_settings_word(s, &next, ws, &neg, os); 3061346805Snp if (rc != 0) 3062346805Snp goto done; 3063346805Snp } 3064346805Snp if (nsettings == 0) { 3065346805Snp warnx("no settings provided"); 3066346805Snp rc = EINVAL; 3067346805Snp goto done; 3068346805Snp } 3069346805Snp if (neg > 0) { 3070346805Snp warnx("%d stray negation(s) at end of offload settings", neg); 3071346805Snp rc = EINVAL; 3072346805Snp goto done; 3073346805Snp } 3074346805Snpdone: 3075346805Snp free(settings); 3076346805Snp return (rc); 3077346805Snp} 3078346805Snp 3079346805Snpstatic int 3080346805Snpisempty_line(char *line, size_t llen) 3081346805Snp{ 3082346805Snp 3083346805Snp /* skip leading whitespace */ 3084346805Snp while (isspace(*line)) { 3085346805Snp line++; 3086346805Snp llen--; 3087346805Snp } 3088346805Snp if (llen == 0 || *line == '#' || *line == '\n') 3089346805Snp return (1); 3090346805Snp 3091346805Snp return (0); 3092346805Snp} 3093346805Snp 3094346805Snpstatic int 3095346805Snpspecial_offload_rule(char *str) 3096346805Snp{ 3097346805Snp 3098346805Snp /* skip leading whitespaces */ 3099346805Snp while (isspace(*str)) 3100346805Snp str++; 3101346805Snp 3102346805Snp /* check for special strings: "-", "all", "any" */ 3103346805Snp if (*str == '-') { 3104346805Snp str++; 3105346805Snp } else if (!strncmp(str, "all", 3) || !strncmp(str, "any", 3)) { 3106346805Snp str += 3; 3107346805Snp } else { 3108346805Snp return (0); 3109346805Snp } 3110346805Snp 3111346805Snp /* skip trailing whitespaces */ 3112346805Snp while (isspace(*str)) 3113346805Snp str++; 3114346805Snp 3115346805Snp return (*str == '\0'); 3116346805Snp} 3117346805Snp 3118346805Snp/* 3119346805Snp * A rule has 3 parts: an open-type, a match expression, and offload settings. 3120346805Snp * 3121346805Snp * [<open-type>] <expr> => <settings> 3122346805Snp */ 3123346805Snpstatic int 3124346805Snpparse_offload_policy_line(size_t lno, char *line, size_t llen, pcap_t *pd, 3125346805Snp struct offload_rule *r) 3126346805Snp{ 3127346805Snp char *expr, *settings, *s; 3128346805Snp 3129346805Snp bzero(r, sizeof(*r)); 3130346805Snp 3131346805Snp /* Skip leading whitespace. */ 3132346805Snp while (isspace(*line)) 3133346805Snp line++; 3134346805Snp /* Trim trailing whitespace */ 3135346805Snp s = &line[llen - 1]; 3136346805Snp while (isspace(*s)) { 3137346805Snp *s-- = '\0'; 3138346805Snp llen--; 3139346805Snp } 3140346805Snp 3141346805Snp /* 3142346805Snp * First part of the rule: '[X]' where X = A/D/L/P 3143346805Snp */ 3144346805Snp if (*line++ != '[') { 3145346805Snp warnx("missing \"[\" on line %zd", lno); 3146346805Snp return (EINVAL); 3147346805Snp } 3148346805Snp switch (*line) { 3149346805Snp case 'A': 3150346805Snp case 'D': 3151346805Snp case 'L': 3152346805Snp case 'P': 3153346805Snp r->open_type = *line; 3154346805Snp break; 3155346805Snp default: 3156346805Snp warnx("invalid socket-type \"%c\" on line %zd.", *line, lno); 3157346805Snp return (EINVAL); 3158346805Snp } 3159346805Snp line++; 3160346805Snp if (*line++ != ']') { 3161346805Snp warnx("missing \"]\" after \"[%c\" on line %zd", 3162346805Snp r->open_type, lno); 3163346805Snp return (EINVAL); 3164346805Snp } 3165346805Snp 3166346805Snp /* Skip whitespace. */ 3167346805Snp while (isspace(*line)) 3168346805Snp line++; 3169346805Snp 3170346805Snp /* 3171346805Snp * Rest of the rule: <expr> => <settings> 3172346805Snp */ 3173346805Snp expr = line; 3174346805Snp s = strstr(line, "=>"); 3175346805Snp if (s == NULL) 3176346805Snp return (EINVAL); 3177346805Snp settings = s + 2; 3178346805Snp while (isspace(*settings)) 3179346805Snp settings++; 3180346805Snp *s = '\0'; 3181346805Snp 3182346805Snp /* 3183346805Snp * <expr> is either a special name (all, any) or a pcap-filter(7). 3184346805Snp * In case of a special name the bpf_prog stays all-zero. 3185346805Snp */ 3186346805Snp if (!special_offload_rule(expr)) { 3187346805Snp if (pcap_compile(pd, &r->bpf_prog, expr, 1, 3188346805Snp PCAP_NETMASK_UNKNOWN) < 0) { 3189346805Snp warnx("failed to compile \"%s\" on line %zd: %s", expr, 3190346805Snp lno, pcap_geterr(pd)); 3191346805Snp return (EINVAL); 3192346805Snp } 3193346805Snp } 3194346805Snp 3195346805Snp /* settings to apply on a match. */ 3196346805Snp if (parse_offload_settings(settings, &r->settings) != 0) { 3197346805Snp warnx("failed to parse offload settings \"%s\" on line %zd", 3198346805Snp settings, lno); 3199346805Snp pcap_freecode(&r->bpf_prog); 3200346805Snp return (EINVAL); 3201346805Snp } 3202346805Snp 3203346805Snp return (0); 3204346805Snp 3205346805Snp} 3206346805Snp 3207346805Snp/* 3208346805Snp * Note that op itself is not dynamically allocated. 3209346805Snp */ 3210346805Snpstatic void 3211346805Snpfree_offload_policy(struct t4_offload_policy *op) 3212346805Snp{ 3213346805Snp int i; 3214346805Snp 3215346805Snp for (i = 0; i < op->nrules; i++) { 3216346805Snp /* 3217346805Snp * pcap_freecode can cope with empty bpf_prog, which is the case 3218346805Snp * for an rule that matches on 'any/all/-'. 3219346805Snp */ 3220346805Snp pcap_freecode(&op->rule[i].bpf_prog); 3221346805Snp } 3222346805Snp free(op->rule); 3223346805Snp op->nrules = 0; 3224346805Snp op->rule = NULL; 3225346805Snp} 3226346805Snp 3227346805Snp#define REALLOC_STRIDE 32 3228346805Snp 3229346805Snp/* 3230346805Snp * Fills up op->nrules and op->rule. 3231346805Snp */ 3232346805Snpstatic int 3233346805Snpparse_offload_policy(const char *fname, struct t4_offload_policy *op) 3234346805Snp{ 3235346805Snp FILE *fp; 3236346805Snp char *line; 3237346805Snp int lno, maxrules, rc; 3238346805Snp size_t lcap, llen; 3239346805Snp struct offload_rule *r; 3240346805Snp pcap_t *pd; 3241346805Snp 3242346805Snp fp = fopen(fname, "r"); 3243346805Snp if (fp == NULL) { 3244346805Snp warn("Unable to open file \"%s\"", fname); 3245346805Snp return (errno); 3246346805Snp } 3247346805Snp pd = pcap_open_dead(DLT_EN10MB, 128); 3248346805Snp if (pd == NULL) { 3249346805Snp warnx("Failed to open pcap device"); 3250346805Snp fclose(fp); 3251346805Snp return (EIO); 3252346805Snp } 3253346805Snp 3254346805Snp rc = 0; 3255346805Snp lno = 0; 3256346805Snp lcap = 0; 3257346805Snp maxrules = 0; 3258346805Snp op->nrules = 0; 3259346805Snp op->rule = NULL; 3260346805Snp line = NULL; 3261346805Snp 3262346805Snp while ((llen = getline(&line, &lcap, fp)) != -1) { 3263346805Snp lno++; 3264346805Snp 3265346805Snp /* Skip empty lines. */ 3266346805Snp if (isempty_line(line, llen)) 3267346805Snp continue; 3268346805Snp 3269346805Snp if (op->nrules == maxrules) { 3270346805Snp maxrules += REALLOC_STRIDE; 3271346805Snp r = realloc(op->rule, 3272346805Snp maxrules * sizeof(struct offload_rule)); 3273346805Snp if (r == NULL) { 3274346805Snp warnx("failed to allocate memory for %d rules", 3275346805Snp maxrules); 3276346805Snp rc = ENOMEM; 3277346805Snp goto done; 3278346805Snp } 3279346805Snp op->rule = r; 3280346805Snp } 3281346805Snp 3282346805Snp r = &op->rule[op->nrules]; 3283346805Snp rc = parse_offload_policy_line(lno, line, llen, pd, r); 3284346805Snp if (rc != 0) { 3285346805Snp warnx("Error parsing line %d of \"%s\"", lno, fname); 3286346805Snp goto done; 3287346805Snp } 3288346805Snp 3289346805Snp op->nrules++; 3290346805Snp } 3291346805Snp free(line); 3292346805Snp 3293346805Snp if (!feof(fp)) { 3294346805Snp warn("Error while reading from file \"%s\" at line %d", 3295346805Snp fname, lno); 3296346805Snp rc = errno; 3297346805Snp goto done; 3298346805Snp } 3299346805Snp 3300346805Snp if (op->nrules == 0) { 3301346805Snp warnx("No valid rules found in \"%s\"", fname); 3302346805Snp rc = EINVAL; 3303346805Snp } 3304346805Snpdone: 3305346805Snp pcap_close(pd); 3306346805Snp fclose(fp); 3307346805Snp if (rc != 0) { 3308346805Snp free_offload_policy(op); 3309346805Snp } 3310346805Snp 3311346805Snp return (rc); 3312346805Snp} 3313346805Snp 3314346805Snpstatic int 3315346805Snpload_offload_policy(int argc, const char *argv[]) 3316346805Snp{ 3317346805Snp int rc = 0; 3318346805Snp const char *fname = argv[0]; 3319346805Snp struct t4_offload_policy op = {0}; 3320346805Snp 3321346805Snp if (argc != 1) { 3322346805Snp warnx("incorrect number of arguments."); 3323346805Snp return (EINVAL); 3324346805Snp } 3325346805Snp 3326346805Snp if (!strcmp(fname, "clear") || !strcmp(fname, "none")) { 3327346805Snp /* op.nrules is 0 and that means clear policy */ 3328346805Snp return (doit(CHELSIO_T4_SET_OFLD_POLICY, &op)); 3329346805Snp } 3330346805Snp 3331346805Snp rc = parse_offload_policy(fname, &op); 3332346805Snp if (rc != 0) { 3333346805Snp /* Error message displayed already */ 3334346805Snp return (EINVAL); 3335346805Snp } 3336346805Snp 3337346805Snp rc = doit(CHELSIO_T4_SET_OFLD_POLICY, &op); 3338346805Snp free_offload_policy(&op); 3339346805Snp 3340346805Snp return (rc); 3341346805Snp} 3342346805Snp 3343346805Snpstatic int 3344222900Snprun_cmd(int argc, const char *argv[]) 3345222900Snp{ 3346222900Snp int rc = -1; 3347222900Snp const char *cmd = argv[0]; 3348222900Snp 3349222900Snp /* command */ 3350222900Snp argc--; 3351222900Snp argv++; 3352222900Snp 3353222900Snp if (!strcmp(cmd, "reg") || !strcmp(cmd, "reg32")) 3354222900Snp rc = register_io(argc, argv, 4); 3355222900Snp else if (!strcmp(cmd, "reg64")) 3356222900Snp rc = register_io(argc, argv, 8); 3357222900Snp else if (!strcmp(cmd, "regdump")) 3358222900Snp rc = dump_regs(argc, argv); 3359222900Snp else if (!strcmp(cmd, "filter")) 3360222900Snp rc = filter_cmd(argc, argv); 3361222974Snp else if (!strcmp(cmd, "context")) 3362222974Snp rc = get_sge_context(argc, argv); 3363228594Snp else if (!strcmp(cmd, "loadfw")) 3364228594Snp rc = loadfw(argc, argv); 3365228594Snp else if (!strcmp(cmd, "memdump")) 3366228594Snp rc = memdump(argc, argv); 3367228594Snp else if (!strcmp(cmd, "tcb")) 3368228594Snp rc = read_tcb(argc, argv); 3369241401Snp else if (!strcmp(cmd, "i2c")) 3370241401Snp rc = read_i2c(argc, argv); 3371241416Snp else if (!strcmp(cmd, "clearstats")) 3372241416Snp rc = clearstats(argc, argv); 3373253691Snp else if (!strcmp(cmd, "tracer")) 3374253691Snp rc = tracer_cmd(argc, argv); 3375258698Snp else if (!strcmp(cmd, "modinfo")) 3376258698Snp rc = modinfo(argc, argv); 3377259048Snp else if (!strcmp(cmd, "sched-class")) 3378259048Snp rc = sched_class(argc, argv); 3379259048Snp else if (!strcmp(cmd, "sched-queue")) 3380259048Snp rc = sched_queue(argc, argv); 3381306823Snp else if (!strcmp(cmd, "loadcfg")) 3382306823Snp rc = loadcfg(argc, argv); 3383330310Snp else if (!strcmp(cmd, "loadboot")) 3384330310Snp rc = loadboot(argc, argv); 3385330310Snp else if (!strcmp(cmd, "loadboot-cfg")) 3386330310Snp rc = loadbootcfg(argc, argv); 3387330307Snp else if (!strcmp(cmd, "dumpstate")) 3388330307Snp rc = dumpstate(argc, argv); 3389346805Snp else if (!strcmp(cmd, "policy")) 3390346805Snp rc = load_offload_policy(argc, argv); 3391222900Snp else { 3392222900Snp rc = EINVAL; 3393222900Snp warnx("invalid command \"%s\"", cmd); 3394222900Snp } 3395222900Snp 3396222900Snp return (rc); 3397222900Snp} 3398222900Snp 3399222900Snp#define MAX_ARGS 15 3400222900Snpstatic int 3401222900Snprun_cmd_loop(void) 3402222900Snp{ 3403222900Snp int i, rc = 0; 3404222900Snp char buffer[128], *buf; 3405222900Snp const char *args[MAX_ARGS + 1]; 3406222900Snp 3407222900Snp /* 3408222900Snp * Simple loop: displays a "> " prompt and processes any input as a 3409222900Snp * cxgbetool command. You're supposed to enter only the part after 3410222900Snp * "cxgbetool t4nexX". Use "quit" or "exit" to exit. 3411222900Snp */ 3412222900Snp for (;;) { 3413222900Snp fprintf(stdout, "> "); 3414222900Snp fflush(stdout); 3415222900Snp buf = fgets(buffer, sizeof(buffer), stdin); 3416222900Snp if (buf == NULL) { 3417222900Snp if (ferror(stdin)) { 3418222900Snp warn("stdin error"); 3419222900Snp rc = errno; /* errno from fgets */ 3420222900Snp } 3421222900Snp break; 3422222900Snp } 3423222900Snp 3424222900Snp i = 0; 3425222900Snp while ((args[i] = strsep(&buf, " \t\n")) != NULL) { 3426222900Snp if (args[i][0] != 0 && ++i == MAX_ARGS) 3427222900Snp break; 3428222900Snp } 3429222900Snp args[i] = 0; 3430222900Snp 3431222900Snp if (i == 0) 3432222900Snp continue; /* skip empty line */ 3433222900Snp 3434222900Snp if (!strcmp(args[0], "quit") || !strcmp(args[0], "exit")) 3435222900Snp break; 3436222900Snp 3437222900Snp rc = run_cmd(i, args); 3438222900Snp } 3439222900Snp 3440222900Snp /* rc normally comes from the last command (not including quit/exit) */ 3441222900Snp return (rc); 3442222900Snp} 3443222900Snp 3444222900Snpint 3445222900Snpmain(int argc, const char *argv[]) 3446222900Snp{ 3447222900Snp int rc = -1; 3448222900Snp 3449222900Snp progname = argv[0]; 3450222900Snp 3451222900Snp if (argc == 2) { 3452222900Snp if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { 3453222900Snp usage(stdout); 3454222900Snp exit(0); 3455222900Snp } 3456222900Snp } 3457222900Snp 3458222900Snp if (argc < 3) { 3459222900Snp usage(stderr); 3460222900Snp exit(EINVAL); 3461222900Snp } 3462222900Snp 3463222900Snp nexus = argv[1]; 3464222900Snp 3465222900Snp /* progname and nexus */ 3466222900Snp argc -= 2; 3467222900Snp argv += 2; 3468222900Snp 3469222900Snp if (argc == 1 && !strcmp(argv[0], "stdio")) 3470222900Snp rc = run_cmd_loop(); 3471222900Snp else 3472222900Snp rc = run_cmd(argc, argv); 3473222900Snp 3474222900Snp return (rc); 3475222900Snp} 3476