cxgbetool.c revision 222900
1222900Snp/*- 2222900Snp * Copyright (c) 2011 Chelsio Communications, Inc. 3222900Snp * All rights reserved. 4222900Snp * Written by: Navdeep Parhar <np@FreeBSD.org> 5222900Snp * 6222900Snp * Redistribution and use in source and binary forms, with or without 7222900Snp * modification, are permitted provided that the following conditions 8222900Snp * are met: 9222900Snp * 1. Redistributions of source code must retain the above copyright 10222900Snp * notice, this list of conditions and the following disclaimer. 11222900Snp * 2. Redistributions in binary form must reproduce the above copyright 12222900Snp * notice, this list of conditions and the following disclaimer in the 13222900Snp * documentation and/or other materials provided with the distribution. 14222900Snp * 15222900Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16222900Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17222900Snp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18222900Snp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19222900Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20222900Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21222900Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22222900Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23222900Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24222900Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25222900Snp * SUCH DAMAGE. 26222900Snp */ 27222900Snp 28222900Snp#include <sys/cdefs.h> 29222900Snp__FBSDID("$FreeBSD: head/tools/tools/cxgbetool/cxgbetool.c 222900 2011-06-09 20:21:45Z np $"); 30222900Snp 31222900Snp#include <stdint.h> 32222900Snp#include <stdlib.h> 33222900Snp#include <errno.h> 34222900Snp#include <err.h> 35222900Snp#include <fcntl.h> 36222900Snp#include <string.h> 37222900Snp#include <stdio.h> 38222900Snp#include <sys/ioctl.h> 39222900Snp#include <sys/types.h> 40222900Snp#include <sys/socket.h> 41222900Snp#include <net/ethernet.h> 42222900Snp#include <netinet/in.h> 43222900Snp#include <arpa/inet.h> 44222900Snp 45222900Snp#include "t4_ioctl.h" 46222900Snp 47222900Snp#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 48222900Snp 49222900Snpstatic const char *progname, *nexus; 50222900Snp 51222900Snpstruct reg_info { 52222900Snp const char *name; 53222900Snp uint32_t addr; 54222900Snp uint32_t len; 55222900Snp}; 56222900Snp 57222900Snpstruct mod_regs { 58222900Snp const char *name; 59222900Snp const struct reg_info *ri; 60222900Snp}; 61222900Snp 62222900Snp#include "reg_defs_t4.c" 63222900Snp#include "reg_defs_t4vf.c" 64222900Snp 65222900Snpstatic void 66222900Snpusage(FILE *fp) 67222900Snp{ 68222900Snp fprintf(fp, "Usage: %s <nexus> [operation]\n", progname); 69222900Snp fprintf(fp, 70222900Snp "\tfilter <idx> [<param> <val>] ... set a filter\n" 71222900Snp "\tfilter <idx> delete|clear delete a filter\n" 72222900Snp "\tfilter list list all filters\n" 73222900Snp "\tfilter mode [<match>] ... get/set global filter mode\n" 74222900Snp "\treg <address>[=<val>] read/write register\n" 75222900Snp "\treg64 <address>[=<val>] read/write 64 bit register\n" 76222900Snp "\tregdump [<module>] ... dump registers\n" 77222900Snp "\tstdio interactive mode\n" 78222900Snp ); 79222900Snp} 80222900Snp 81222900Snpstatic inline unsigned int 82222900Snpget_card_vers(unsigned int version) 83222900Snp{ 84222900Snp return (version & 0x3ff); 85222900Snp} 86222900Snp 87222900Snpstatic int 88222900Snpreal_doit(unsigned long cmd, void *data, const char *cmdstr) 89222900Snp{ 90222900Snp static int fd = -1; 91222900Snp int rc = 0; 92222900Snp 93222900Snp if (fd == -1) { 94222900Snp char buf[64]; 95222900Snp 96222900Snp snprintf(buf, sizeof(buf), "/dev/%s", nexus); 97222900Snp if ((fd = open(buf, O_RDWR)) < 0) { 98222900Snp warn("open(%s)", nexus); 99222900Snp rc = errno; 100222900Snp return (rc); 101222900Snp } 102222900Snp } 103222900Snp 104222900Snp rc = ioctl(fd, cmd, data); 105222900Snp if (rc < 0) { 106222900Snp warn("%s", cmdstr); 107222900Snp rc = errno; 108222900Snp } 109222900Snp 110222900Snp return (rc); 111222900Snp} 112222900Snp#define doit(x, y) real_doit(x, y, #x) 113222900Snp 114222900Snpstatic char * 115222900Snpstr_to_number(const char *s, long *val, long long *vall) 116222900Snp{ 117222900Snp char *p; 118222900Snp 119222900Snp if (vall) 120222900Snp *vall = strtoll(s, &p, 0); 121222900Snp else if (val) 122222900Snp *val = strtol(s, &p, 0); 123222900Snp else 124222900Snp p = NULL; 125222900Snp 126222900Snp return (p); 127222900Snp} 128222900Snp 129222900Snpstatic int 130222900Snpread_reg(long addr, int size, long long *val) 131222900Snp{ 132222900Snp struct t4_reg reg; 133222900Snp int rc; 134222900Snp 135222900Snp reg.addr = (uint32_t) addr; 136222900Snp reg.size = (uint32_t) size; 137222900Snp reg.val = 0; 138222900Snp 139222900Snp rc = doit(CHELSIO_T4_GETREG, ®); 140222900Snp 141222900Snp *val = reg.val; 142222900Snp 143222900Snp return (rc); 144222900Snp} 145222900Snp 146222900Snpstatic int 147222900Snpwrite_reg(long addr, int size, long long val) 148222900Snp{ 149222900Snp struct t4_reg reg; 150222900Snp 151222900Snp reg.addr = (uint32_t) addr; 152222900Snp reg.size = (uint32_t) size; 153222900Snp reg.val = (uint64_t) val; 154222900Snp 155222900Snp return doit(CHELSIO_T4_SETREG, ®); 156222900Snp} 157222900Snp 158222900Snpstatic int 159222900Snpregister_io(int argc, const char *argv[], int size) 160222900Snp{ 161222900Snp char *p, *v; 162222900Snp long addr; 163222900Snp long long val; 164222900Snp int w = 0, rc; 165222900Snp 166222900Snp if (argc == 1) { 167222900Snp /* <reg> OR <reg>=<value> */ 168222900Snp 169222900Snp p = str_to_number(argv[0], &addr, NULL); 170222900Snp if (*p) { 171222900Snp if (*p != '=') { 172222900Snp warnx("invalid register \"%s\"", argv[0]); 173222900Snp return (EINVAL); 174222900Snp } 175222900Snp 176222900Snp w = 1; 177222900Snp v = p + 1; 178222900Snp p = str_to_number(v, NULL, &val); 179222900Snp 180222900Snp if (*p) { 181222900Snp warnx("invalid value \"%s\"", v); 182222900Snp return (EINVAL); 183222900Snp } 184222900Snp } 185222900Snp 186222900Snp } else if (argc == 2) { 187222900Snp /* <reg> <value> */ 188222900Snp 189222900Snp w = 1; 190222900Snp 191222900Snp p = str_to_number(argv[0], &addr, NULL); 192222900Snp if (*p) { 193222900Snp warnx("invalid register \"%s\"", argv[0]); 194222900Snp return (EINVAL); 195222900Snp } 196222900Snp 197222900Snp p = str_to_number(argv[1], NULL, &val); 198222900Snp if (*p) { 199222900Snp warnx("invalid value \"%s\"", argv[1]); 200222900Snp return (EINVAL); 201222900Snp } 202222900Snp } else { 203222900Snp warnx("reg: invalid number of arguments (%d)", argc); 204222900Snp return (EINVAL); 205222900Snp } 206222900Snp 207222900Snp if (w) 208222900Snp rc = write_reg(addr, size, val); 209222900Snp else { 210222900Snp rc = read_reg(addr, size, &val); 211222900Snp if (rc == 0) 212222900Snp printf("0x%llx [%llu]\n", val, val); 213222900Snp } 214222900Snp 215222900Snp return (rc); 216222900Snp} 217222900Snp 218222900Snpstatic inline uint32_t 219222900Snpxtract(uint32_t val, int shift, int len) 220222900Snp{ 221222900Snp return (val >> shift) & ((1 << len) - 1); 222222900Snp} 223222900Snp 224222900Snpstatic int 225222900Snpdump_block_regs(const struct reg_info *reg_array, const uint32_t *regs) 226222900Snp{ 227222900Snp uint32_t reg_val = 0; 228222900Snp 229222900Snp for ( ; reg_array->name; ++reg_array) 230222900Snp if (!reg_array->len) { 231222900Snp reg_val = regs[reg_array->addr / 4]; 232222900Snp printf("[%#7x] %-47s %#-10x %u\n", reg_array->addr, 233222900Snp reg_array->name, reg_val, reg_val); 234222900Snp } else { 235222900Snp uint32_t v = xtract(reg_val, reg_array->addr, 236222900Snp reg_array->len); 237222900Snp 238222900Snp printf(" %*u:%u %-47s %#-10x %u\n", 239222900Snp reg_array->addr < 10 ? 3 : 2, 240222900Snp reg_array->addr + reg_array->len - 1, 241222900Snp reg_array->addr, reg_array->name, v, v); 242222900Snp } 243222900Snp 244222900Snp return (1); 245222900Snp} 246222900Snp 247222900Snpstatic int 248222900Snpdump_regs_table(int argc, const char *argv[], const uint32_t *regs, 249222900Snp const struct mod_regs *modtab, int nmodules) 250222900Snp{ 251222900Snp int i, j, match; 252222900Snp 253222900Snp for (i = 0; i < argc; i++) { 254222900Snp for (j = 0; j < nmodules; j++) { 255222900Snp if (!strcmp(argv[i], modtab[j].name)) 256222900Snp break; 257222900Snp } 258222900Snp 259222900Snp if (j == nmodules) { 260222900Snp warnx("invalid register block \"%s\"", argv[i]); 261222900Snp fprintf(stderr, "\nAvailable blocks:"); 262222900Snp for ( ; nmodules; nmodules--, modtab++) 263222900Snp fprintf(stderr, " %s", modtab->name); 264222900Snp fprintf(stderr, "\n"); 265222900Snp return (EINVAL); 266222900Snp } 267222900Snp } 268222900Snp 269222900Snp for ( ; nmodules; nmodules--, modtab++) { 270222900Snp 271222900Snp match = argc == 0 ? 1 : 0; 272222900Snp for (i = 0; !match && i < argc; i++) { 273222900Snp if (!strcmp(argv[i], modtab->name)) 274222900Snp match = 1; 275222900Snp } 276222900Snp 277222900Snp if (match) 278222900Snp dump_block_regs(modtab->ri, regs); 279222900Snp } 280222900Snp 281222900Snp return (0); 282222900Snp} 283222900Snp 284222900Snp#define T4_MODREGS(name) { #name, t4_##name##_regs } 285222900Snpstatic int 286222900Snpdump_regs_t4(int argc, const char *argv[], const uint32_t *regs) 287222900Snp{ 288222900Snp static struct mod_regs t4_mod[] = { 289222900Snp T4_MODREGS(sge), 290222900Snp { "pci", t4_pcie_regs }, 291222900Snp T4_MODREGS(dbg), 292222900Snp T4_MODREGS(mc), 293222900Snp T4_MODREGS(ma), 294222900Snp { "edc0", t4_edc_0_regs }, 295222900Snp { "edc1", t4_edc_1_regs }, 296222900Snp T4_MODREGS(cim), 297222900Snp T4_MODREGS(tp), 298222900Snp T4_MODREGS(ulp_rx), 299222900Snp T4_MODREGS(ulp_tx), 300222900Snp { "pmrx", t4_pm_rx_regs }, 301222900Snp { "pmtx", t4_pm_tx_regs }, 302222900Snp T4_MODREGS(mps), 303222900Snp { "cplsw", t4_cpl_switch_regs }, 304222900Snp T4_MODREGS(smb), 305222900Snp { "i2c", t4_i2cm_regs }, 306222900Snp T4_MODREGS(mi), 307222900Snp T4_MODREGS(uart), 308222900Snp T4_MODREGS(pmu), 309222900Snp T4_MODREGS(sf), 310222900Snp T4_MODREGS(pl), 311222900Snp T4_MODREGS(le), 312222900Snp T4_MODREGS(ncsi), 313222900Snp T4_MODREGS(xgmac) 314222900Snp }; 315222900Snp 316222900Snp return dump_regs_table(argc, argv, regs, t4_mod, ARRAY_SIZE(t4_mod)); 317222900Snp} 318222900Snp#undef T4_MODREGS 319222900Snp 320222900Snpstatic int 321222900Snpdump_regs_t4vf(int argc, const char *argv[], const uint32_t *regs) 322222900Snp{ 323222900Snp static struct mod_regs t4vf_mod[] = { 324222900Snp { "sge", t4vf_sge_regs }, 325222900Snp { "mps", t4vf_mps_regs }, 326222900Snp { "pl", t4vf_pl_regs }, 327222900Snp { "mbdata", t4vf_mbdata_regs }, 328222900Snp { "cim", t4vf_cim_regs }, 329222900Snp }; 330222900Snp 331222900Snp return dump_regs_table(argc, argv, regs, t4vf_mod, 332222900Snp ARRAY_SIZE(t4vf_mod)); 333222900Snp} 334222900Snp 335222900Snpstatic int 336222900Snpdump_regs(int argc, const char *argv[]) 337222900Snp{ 338222900Snp int vers, revision, is_pcie, rc; 339222900Snp struct t4_regdump regs; 340222900Snp 341222900Snp regs.data = calloc(1, T4_REGDUMP_SIZE); 342222900Snp if (regs.data == NULL) { 343222900Snp warnc(ENOMEM, "regdump"); 344222900Snp return (ENOMEM); 345222900Snp } 346222900Snp 347222900Snp regs.len = T4_REGDUMP_SIZE; 348222900Snp rc = doit(CHELSIO_T4_REGDUMP, ®s); 349222900Snp if (rc != 0) 350222900Snp return (rc); 351222900Snp 352222900Snp vers = get_card_vers(regs.version); 353222900Snp revision = (regs.version >> 10) & 0x3f; 354222900Snp is_pcie = (regs.version & 0x80000000) != 0; 355222900Snp 356222900Snp if (vers == 4) { 357222900Snp if (revision == 0x3f) 358222900Snp rc = dump_regs_t4vf(argc, argv, regs.data); 359222900Snp else 360222900Snp rc = dump_regs_t4(argc, argv, regs.data); 361222900Snp } else { 362222900Snp warnx("%s (type %d, rev %d) is not a T4 card.", 363222900Snp nexus, vers, revision); 364222900Snp return (ENOTSUP); 365222900Snp } 366222900Snp 367222900Snp free(regs.data); 368222900Snp return (rc); 369222900Snp} 370222900Snp 371222900Snpstatic void 372222900Snpdo_show_info_header(uint32_t mode) 373222900Snp{ 374222900Snp uint32_t i; 375222900Snp 376222900Snp printf ("%4s %8s", "Idx", "Hits"); 377222900Snp for (i = T4_FILTER_FCoE; i <= T4_FILTER_IP_FRAGMENT; i <<= 1) { 378222900Snp switch (mode & i) { 379222900Snp case T4_FILTER_FCoE: 380222900Snp printf (" FCoE"); 381222900Snp break; 382222900Snp 383222900Snp case T4_FILTER_PORT: 384222900Snp printf (" Port"); 385222900Snp break; 386222900Snp 387222900Snp case T4_FILTER_OVLAN: 388222900Snp printf (" vld:oVLAN"); 389222900Snp break; 390222900Snp 391222900Snp case T4_FILTER_IVLAN: 392222900Snp printf (" vld:iVLAN"); 393222900Snp break; 394222900Snp 395222900Snp case T4_FILTER_IP_TOS: 396222900Snp printf (" TOS"); 397222900Snp break; 398222900Snp 399222900Snp case T4_FILTER_IP_PROTO: 400222900Snp printf (" Prot"); 401222900Snp break; 402222900Snp 403222900Snp case T4_FILTER_ETH_TYPE: 404222900Snp printf (" EthType"); 405222900Snp break; 406222900Snp 407222900Snp case T4_FILTER_MAC_IDX: 408222900Snp printf (" MACIdx"); 409222900Snp break; 410222900Snp 411222900Snp case T4_FILTER_MPS_HIT_TYPE: 412222900Snp printf (" MPS"); 413222900Snp break; 414222900Snp 415222900Snp case T4_FILTER_IP_FRAGMENT: 416222900Snp printf (" Frag"); 417222900Snp break; 418222900Snp 419222900Snp default: 420222900Snp /* compressed filter field not enabled */ 421222900Snp break; 422222900Snp } 423222900Snp } 424222900Snp printf(" %20s %20s %9s %9s %s\n", 425222900Snp "DIP", "SIP", "DPORT", "SPORT", "Action"); 426222900Snp} 427222900Snp 428222900Snp/* 429222900Snp * Parse an argument sub-vector as a { <parameter name> <value>[:<mask>] } 430222900Snp * ordered tuple. If the parameter name in the argument sub-vector does not 431222900Snp * match the passed in parameter name, then a zero is returned for the 432222900Snp * function and no parsing is performed. If there is a match, then the value 433222900Snp * and optional mask are parsed and returned in the provided return value 434222900Snp * pointers. If no optional mask is specified, then a default mask of all 1s 435222900Snp * will be returned. 436222900Snp * 437222900Snp * An error in parsing the value[:mask] will result in an error message and 438222900Snp * program termination. 439222900Snp */ 440222900Snpstatic int 441222900Snpparse_val_mask(const char *param, const char *args[], uint32_t *val, 442222900Snp uint32_t *mask) 443222900Snp{ 444222900Snp char *p; 445222900Snp 446222900Snp if (strcmp(param, args[0]) != 0) 447222900Snp return (EINVAL); 448222900Snp 449222900Snp *val = strtoul(args[1], &p, 0); 450222900Snp if (p > args[1]) { 451222900Snp if (p[0] == 0) { 452222900Snp *mask = ~0; 453222900Snp return (0); 454222900Snp } 455222900Snp 456222900Snp if (p[0] == ':' && p[1] != 0) { 457222900Snp *mask = strtoul(p+1, &p, 0); 458222900Snp if (p[0] == 0) 459222900Snp return (0); 460222900Snp } 461222900Snp } 462222900Snp 463222900Snp warnx("parameter \"%s\" has bad \"value[:mask]\" %s", 464222900Snp args[0], args[1]); 465222900Snp 466222900Snp return (EINVAL); 467222900Snp} 468222900Snp 469222900Snp/* 470222900Snp * Parse an argument sub-vector as a { <parameter name> <addr>[/<mask>] } 471222900Snp * ordered tuple. If the parameter name in the argument sub-vector does not 472222900Snp * match the passed in parameter name, then a zero is returned for the 473222900Snp * function and no parsing is performed. If there is a match, then the value 474222900Snp * and optional mask are parsed and returned in the provided return value 475222900Snp * pointers. If no optional mask is specified, then a default mask of all 1s 476222900Snp * will be returned. 477222900Snp * 478222900Snp * The value return parameter "afp" is used to specify the expected address 479222900Snp * family -- IPv4 or IPv6 -- of the address[/mask] and return its actual 480222900Snp * format. A passed in value of AF_UNSPEC indicates that either IPv4 or IPv6 481222900Snp * is acceptable; AF_INET means that only IPv4 addresses are acceptable; and 482222900Snp * AF_INET6 means that only IPv6 are acceptable. AF_INET is returned for IPv4 483222900Snp * and AF_INET6 for IPv6 addresses, respectively. IPv4 address/mask pairs are 484222900Snp * returned in the first four bytes of the address and mask return values with 485222900Snp * the address A.B.C.D returned with { A, B, C, D } returned in addresses { 0, 486222900Snp * 1, 2, 3}, respectively. 487222900Snp * 488222900Snp * An error in parsing the value[:mask] will result in an error message and 489222900Snp * program termination. 490222900Snp */ 491222900Snpstatic int 492222900Snpparse_ipaddr(const char *param, const char *args[], int *afp, uint8_t addr[], 493222900Snp uint8_t mask[]) 494222900Snp{ 495222900Snp const char *colon, *afn; 496222900Snp char *slash; 497222900Snp uint8_t *m; 498222900Snp int af, ret; 499222900Snp unsigned int masksize; 500222900Snp 501222900Snp /* 502222900Snp * Is this our parameter? 503222900Snp */ 504222900Snp if (strcmp(param, args[0]) != 0) 505222900Snp return (EINVAL); 506222900Snp 507222900Snp /* 508222900Snp * Fundamental IPv4 versus IPv6 selection. 509222900Snp */ 510222900Snp colon = strchr(args[1], ':'); 511222900Snp if (!colon) { 512222900Snp afn = "IPv4"; 513222900Snp af = AF_INET; 514222900Snp masksize = 32; 515222900Snp } else { 516222900Snp afn = "IPv6"; 517222900Snp af = AF_INET6; 518222900Snp masksize = 128; 519222900Snp } 520222900Snp if (*afp == AF_UNSPEC) 521222900Snp *afp = af; 522222900Snp else if (*afp != af) { 523222900Snp warnx("address %s is not of expected family %s", 524222900Snp args[1], *afp == AF_INET ? "IP" : "IPv6"); 525222900Snp return (EINVAL); 526222900Snp } 527222900Snp 528222900Snp /* 529222900Snp * Parse address (temporarily stripping off any "/mask" 530222900Snp * specification). 531222900Snp */ 532222900Snp slash = strchr(args[1], '/'); 533222900Snp if (slash) 534222900Snp *slash = 0; 535222900Snp ret = inet_pton(af, args[1], addr); 536222900Snp if (slash) 537222900Snp *slash = '/'; 538222900Snp if (ret <= 0) { 539222900Snp warnx("Cannot parse %s %s address %s", param, afn, args[1]); 540222900Snp return (EINVAL); 541222900Snp } 542222900Snp 543222900Snp /* 544222900Snp * Parse optional mask specification. 545222900Snp */ 546222900Snp if (slash) { 547222900Snp char *p; 548222900Snp unsigned int prefix = strtoul(slash + 1, &p, 10); 549222900Snp 550222900Snp if (p == slash + 1) { 551222900Snp warnx("missing address prefix for %s", param); 552222900Snp return (EINVAL); 553222900Snp } 554222900Snp if (*p) { 555222900Snp warnx("%s is not a valid address prefix", slash + 1); 556222900Snp return (EINVAL); 557222900Snp } 558222900Snp if (prefix > masksize) { 559222900Snp warnx("prefix %u is too long for an %s address", 560222900Snp prefix, afn); 561222900Snp return (EINVAL); 562222900Snp } 563222900Snp memset(mask, 0, masksize / 8); 564222900Snp masksize = prefix; 565222900Snp } 566222900Snp 567222900Snp /* 568222900Snp * Fill in mask. 569222900Snp */ 570222900Snp for (m = mask; masksize >= 8; m++, masksize -= 8) 571222900Snp *m = ~0; 572222900Snp if (masksize) 573222900Snp *m = ~0 << (8 - masksize); 574222900Snp 575222900Snp return (0); 576222900Snp} 577222900Snp 578222900Snp/* 579222900Snp * Parse an argument sub-vector as a { <parameter name> <value> } ordered 580222900Snp * tuple. If the parameter name in the argument sub-vector does not match the 581222900Snp * passed in parameter name, then a zero is returned for the function and no 582222900Snp * parsing is performed. If there is a match, then the value is parsed and 583222900Snp * returned in the provided return value pointer. 584222900Snp */ 585222900Snpstatic int 586222900Snpparse_val(const char *param, const char *args[], uint32_t *val) 587222900Snp{ 588222900Snp char *p; 589222900Snp 590222900Snp if (strcmp(param, args[0]) != 0) 591222900Snp return (EINVAL); 592222900Snp 593222900Snp *val = strtoul(args[1], &p, 0); 594222900Snp if (p > args[1] && p[0] == 0) 595222900Snp return (0); 596222900Snp 597222900Snp warnx("parameter \"%s\" has bad \"value\" %s", args[0], args[1]); 598222900Snp return (EINVAL); 599222900Snp} 600222900Snp 601222900Snpstatic void 602222900Snpfilters_show_ipaddr(int type, uint8_t *addr, uint8_t *addrm) 603222900Snp{ 604222900Snp int noctets, octet; 605222900Snp 606222900Snp printf(" "); 607222900Snp if (type == 0) { 608222900Snp noctets = 4; 609222900Snp printf("%3s", " "); 610222900Snp } else 611222900Snp noctets = 16; 612222900Snp 613222900Snp for (octet = 0; octet < noctets; octet++) 614222900Snp printf("%02x", addr[octet]); 615222900Snp printf("/"); 616222900Snp for (octet = 0; octet < noctets; octet++) 617222900Snp printf("%02x", addrm[octet]); 618222900Snp} 619222900Snp 620222900Snpstatic void 621222900Snpdo_show_one_filter_info(struct t4_filter *t, uint32_t mode) 622222900Snp{ 623222900Snp uint32_t i; 624222900Snp 625222900Snp printf("%4d", t->idx); 626222900Snp if (t->hits == UINT64_MAX) 627222900Snp printf(" %8s", "-"); 628222900Snp else 629222900Snp printf(" %8ju", t->hits); 630222900Snp 631222900Snp /* 632222900Snp * Compressed header portion of filter. 633222900Snp */ 634222900Snp for (i = T4_FILTER_FCoE; i <= T4_FILTER_IP_FRAGMENT; i <<= 1) { 635222900Snp switch (mode & i) { 636222900Snp case T4_FILTER_FCoE: 637222900Snp printf(" %1d/%1d", t->fs.val.fcoe, t->fs.mask.fcoe); 638222900Snp break; 639222900Snp 640222900Snp case T4_FILTER_PORT: 641222900Snp printf(" %1d/%1d", t->fs.val.iport, t->fs.mask.iport); 642222900Snp break; 643222900Snp 644222900Snp case T4_FILTER_OVLAN: 645222900Snp printf(" %1d:%1x:%02x/%1d:%1x:%02x", 646222900Snp t->fs.val.ovlan_vld, (t->fs.val.ovlan >> 7) & 0x7, 647222900Snp t->fs.val.ovlan & 0x7f, t->fs.mask.ovlan_vld, 648222900Snp (t->fs.mask.ovlan >> 7) & 0x7, 649222900Snp t->fs.mask.ovlan & 0x7f); 650222900Snp break; 651222900Snp 652222900Snp case T4_FILTER_IVLAN: 653222900Snp printf(" %1d:%04x/%1d:%04x", 654222900Snp t->fs.val.ivlan_vld, t->fs.val.ivlan, 655222900Snp t->fs.mask.ivlan_vld, t->fs.mask.ivlan); 656222900Snp break; 657222900Snp 658222900Snp case T4_FILTER_IP_TOS: 659222900Snp printf(" %02x/%02x", t->fs.val.tos, t->fs.mask.tos); 660222900Snp break; 661222900Snp 662222900Snp case T4_FILTER_IP_PROTO: 663222900Snp printf(" %02x/%02x", t->fs.val.proto, t->fs.mask.proto); 664222900Snp break; 665222900Snp 666222900Snp case T4_FILTER_ETH_TYPE: 667222900Snp printf(" %04x/%04x", t->fs.val.ethtype, 668222900Snp t->fs.mask.ethtype); 669222900Snp break; 670222900Snp 671222900Snp case T4_FILTER_MAC_IDX: 672222900Snp printf(" %03x/%03x", t->fs.val.macidx, 673222900Snp t->fs.mask.macidx); 674222900Snp break; 675222900Snp 676222900Snp case T4_FILTER_MPS_HIT_TYPE: 677222900Snp printf(" %1x/%1x", t->fs.val.matchtype, 678222900Snp t->fs.mask.matchtype); 679222900Snp break; 680222900Snp 681222900Snp case T4_FILTER_IP_FRAGMENT: 682222900Snp printf(" %1d/%1d", t->fs.val.frag, t->fs.mask.frag); 683222900Snp break; 684222900Snp 685222900Snp default: 686222900Snp /* compressed filter field not enabled */ 687222900Snp break; 688222900Snp } 689222900Snp } 690222900Snp 691222900Snp /* 692222900Snp * Fixed portion of filter. 693222900Snp */ 694222900Snp filters_show_ipaddr(t->fs.type, t->fs.val.dip, t->fs.mask.dip); 695222900Snp filters_show_ipaddr(t->fs.type, t->fs.val.sip, t->fs.mask.sip); 696222900Snp printf(" %04x/%04x %04x/%04x", 697222900Snp t->fs.val.dport, t->fs.mask.dport, 698222900Snp t->fs.val.sport, t->fs.mask.sport); 699222900Snp 700222900Snp /* 701222900Snp * Variable length filter action. 702222900Snp */ 703222900Snp if (t->fs.action == FILTER_DROP) 704222900Snp printf(" Drop"); 705222900Snp else if (t->fs.action == FILTER_SWITCH) { 706222900Snp printf(" Switch: port=%d", t->fs.eport); 707222900Snp if (t->fs.newdmac) 708222900Snp printf( 709222900Snp ", dmac=%02x:%02x:%02x:%02x:%02x:%02x " 710222900Snp ", l2tidx=%d", 711222900Snp t->fs.dmac[0], t->fs.dmac[1], 712222900Snp t->fs.dmac[2], t->fs.dmac[3], 713222900Snp t->fs.dmac[4], t->fs.dmac[5], 714222900Snp t->l2tidx); 715222900Snp if (t->fs.newsmac) 716222900Snp printf( 717222900Snp ", smac=%02x:%02x:%02x:%02x:%02x:%02x " 718222900Snp ", smtidx=%d", 719222900Snp t->fs.smac[0], t->fs.smac[1], 720222900Snp t->fs.smac[2], t->fs.smac[3], 721222900Snp t->fs.smac[4], t->fs.smac[5], 722222900Snp t->smtidx); 723222900Snp if (t->fs.newvlan == VLAN_REMOVE) 724222900Snp printf(", vlan=none"); 725222900Snp else if (t->fs.newvlan == VLAN_INSERT) 726222900Snp printf(", vlan=insert(%x)", t->fs.vlan); 727222900Snp else if (t->fs.newvlan == VLAN_REWRITE) 728222900Snp printf(", vlan=rewrite(%x)", t->fs.vlan); 729222900Snp } else { 730222900Snp printf(" Pass: Q="); 731222900Snp if (t->fs.dirsteer == 0) { 732222900Snp printf("RSS"); 733222900Snp if (t->fs.maskhash) 734222900Snp printf("(TCB=hash)"); 735222900Snp } else { 736222900Snp printf("%d", t->fs.iq); 737222900Snp if (t->fs.dirsteerhash == 0) 738222900Snp printf("(QID)"); 739222900Snp else 740222900Snp printf("(hash)"); 741222900Snp } 742222900Snp } 743222900Snp if (t->fs.prio) 744222900Snp printf(" Prio"); 745222900Snp if (t->fs.rpttid) 746222900Snp printf(" RptTID"); 747222900Snp printf("\n"); 748222900Snp} 749222900Snp 750222900Snpstatic int 751222900Snpshow_filters(void) 752222900Snp{ 753222900Snp uint32_t mode = 0, header = 0; 754222900Snp struct t4_filter t; 755222900Snp int rc; 756222900Snp 757222900Snp /* Get the global filter mode first */ 758222900Snp rc = doit(CHELSIO_T4_GET_FILTER_MODE, &mode); 759222900Snp if (rc != 0) 760222900Snp return (rc); 761222900Snp 762222900Snp t.idx = 0; 763222900Snp for (t.idx = 0; ; t.idx++) { 764222900Snp rc = doit(CHELSIO_T4_GET_FILTER, &t); 765222900Snp if (rc != 0 || t.idx == 0xffffffff) 766222900Snp break; 767222900Snp 768222900Snp if (!header) { 769222900Snp do_show_info_header(mode); 770222900Snp header = 1; 771222900Snp } 772222900Snp do_show_one_filter_info(&t, mode); 773222900Snp }; 774222900Snp 775222900Snp return (rc); 776222900Snp} 777222900Snp 778222900Snpstatic int 779222900Snpget_filter_mode(void) 780222900Snp{ 781222900Snp uint32_t mode = 0; 782222900Snp int rc; 783222900Snp 784222900Snp rc = doit(CHELSIO_T4_GET_FILTER_MODE, &mode); 785222900Snp if (rc != 0) 786222900Snp return (rc); 787222900Snp 788222900Snp if (mode & T4_FILTER_IPv4) 789222900Snp printf("ipv4 "); 790222900Snp 791222900Snp if (mode & T4_FILTER_IPv6) 792222900Snp printf("ipv6 "); 793222900Snp 794222900Snp if (mode & T4_FILTER_IP_SADDR) 795222900Snp printf("sip "); 796222900Snp 797222900Snp if (mode & T4_FILTER_IP_DADDR) 798222900Snp printf("dip "); 799222900Snp 800222900Snp if (mode & T4_FILTER_IP_SPORT) 801222900Snp printf("sport "); 802222900Snp 803222900Snp if (mode & T4_FILTER_IP_DPORT) 804222900Snp printf("dport "); 805222900Snp 806222900Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 807222900Snp printf("matchtype "); 808222900Snp 809222900Snp if (mode & T4_FILTER_MAC_IDX) 810222900Snp printf("macidx "); 811222900Snp 812222900Snp if (mode & T4_FILTER_ETH_TYPE) 813222900Snp printf("ethtype "); 814222900Snp 815222900Snp if (mode & T4_FILTER_IP_PROTO) 816222900Snp printf("proto "); 817222900Snp 818222900Snp if (mode & T4_FILTER_IP_TOS) 819222900Snp printf("tos "); 820222900Snp 821222900Snp if (mode & T4_FILTER_IVLAN) 822222900Snp printf("ivlan "); 823222900Snp 824222900Snp if (mode & T4_FILTER_OVLAN) 825222900Snp printf("ovlan "); 826222900Snp 827222900Snp if (mode & T4_FILTER_PORT) 828222900Snp printf("iport "); 829222900Snp 830222900Snp if (mode & T4_FILTER_FCoE) 831222900Snp printf("fcoe "); 832222900Snp 833222900Snp printf("\n"); 834222900Snp 835222900Snp return (0); 836222900Snp} 837222900Snp 838222900Snpstatic int 839222900Snpset_filter_mode(int argc, const char *argv[]) 840222900Snp{ 841222900Snp uint32_t mode = 0; 842222900Snp 843222900Snp for (; argc; argc--, argv++) { 844222900Snp if (!strcmp(argv[0], "matchtype")) 845222900Snp mode |= T4_FILTER_MPS_HIT_TYPE; 846222900Snp 847222900Snp if (!strcmp(argv[0], "macidx")) 848222900Snp mode |= T4_FILTER_MAC_IDX; 849222900Snp 850222900Snp if (!strcmp(argv[0], "ethtype")) 851222900Snp mode |= T4_FILTER_ETH_TYPE; 852222900Snp 853222900Snp if (!strcmp(argv[0], "proto")) 854222900Snp mode |= T4_FILTER_IP_PROTO; 855222900Snp 856222900Snp if (!strcmp(argv[0], "tos")) 857222900Snp mode |= T4_FILTER_IP_TOS; 858222900Snp 859222900Snp if (!strcmp(argv[0], "ivlan")) 860222900Snp mode |= T4_FILTER_IVLAN; 861222900Snp 862222900Snp if (!strcmp(argv[0], "ovlan")) 863222900Snp mode |= T4_FILTER_OVLAN; 864222900Snp 865222900Snp if (!strcmp(argv[0], "iport")) 866222900Snp mode |= T4_FILTER_PORT; 867222900Snp 868222900Snp if (!strcmp(argv[0], "fcoe")) 869222900Snp mode |= T4_FILTER_FCoE; 870222900Snp } 871222900Snp 872222900Snp return doit(CHELSIO_T4_SET_FILTER_MODE, &mode); 873222900Snp} 874222900Snp 875222900Snpstatic int 876222900Snpdel_filter(uint32_t idx) 877222900Snp{ 878222900Snp struct t4_filter t; 879222900Snp 880222900Snp t.idx = idx; 881222900Snp 882222900Snp return doit(CHELSIO_T4_DEL_FILTER, &t); 883222900Snp} 884222900Snp 885222900Snpstatic int 886222900Snpset_filter(uint32_t idx, int argc, const char *argv[]) 887222900Snp{ 888222900Snp int af = AF_UNSPEC, start_arg = 0; 889222900Snp struct t4_filter t; 890222900Snp 891222900Snp if (argc < 2) { 892222900Snp warnc(EINVAL, "%s", __func__); 893222900Snp return (EINVAL); 894222900Snp }; 895222900Snp bzero(&t, sizeof (t)); 896222900Snp t.idx = idx; 897222900Snp 898222900Snp for (start_arg = 0; start_arg + 2 <= argc; start_arg += 2) { 899222900Snp const char **args = &argv[start_arg]; 900222900Snp uint32_t val, mask; 901222900Snp 902222900Snp if (!strcmp(argv[start_arg], "type")) { 903222900Snp int newaf; 904222900Snp if (!strcasecmp(argv[start_arg + 1], "ipv4")) 905222900Snp newaf = AF_INET; 906222900Snp else if (!strcasecmp(argv[start_arg + 1], "ipv6")) 907222900Snp newaf = AF_INET6; 908222900Snp else { 909222900Snp warnx("invalid type \"%s\"; " 910222900Snp "must be one of \"ipv4\" or \"ipv6\"", 911222900Snp argv[start_arg + 1]); 912222900Snp return (EINVAL); 913222900Snp } 914222900Snp 915222900Snp if (af != AF_UNSPEC && af != newaf) { 916222900Snp warnx("conflicting IPv4/IPv6 specifications."); 917222900Snp return (EINVAL); 918222900Snp } 919222900Snp af = newaf; 920222900Snp } else if (!parse_val_mask("fcoe", args, &val, &mask)) { 921222900Snp t.fs.val.fcoe = val; 922222900Snp t.fs.mask.fcoe = mask; 923222900Snp } else if (!parse_val_mask("iport", args, &val, &mask)) { 924222900Snp t.fs.val.iport = val; 925222900Snp t.fs.mask.iport = mask; 926222900Snp } else if (!parse_val_mask("ovlan", args, &val, &mask)) { 927222900Snp t.fs.val.ovlan = val; 928222900Snp t.fs.mask.ovlan = mask; 929222900Snp t.fs.val.ovlan_vld = 1; 930222900Snp t.fs.mask.ovlan_vld = 1; 931222900Snp } else if (!parse_val_mask("ivlan", args, &val, &mask)) { 932222900Snp t.fs.val.ivlan = val; 933222900Snp t.fs.mask.ivlan = mask; 934222900Snp t.fs.val.ivlan_vld = 1; 935222900Snp t.fs.mask.ivlan_vld = 1; 936222900Snp } else if (!parse_val_mask("tos", args, &val, &mask)) { 937222900Snp t.fs.val.tos = val; 938222900Snp t.fs.mask.tos = mask; 939222900Snp } else if (!parse_val_mask("proto", args, &val, &mask)) { 940222900Snp t.fs.val.proto = val; 941222900Snp t.fs.mask.proto = mask; 942222900Snp } else if (!parse_val_mask("ethtype", args, &val, &mask)) { 943222900Snp t.fs.val.ethtype = val; 944222900Snp t.fs.mask.ethtype = mask; 945222900Snp } else if (!parse_val_mask("macidx", args, &val, &mask)) { 946222900Snp t.fs.val.macidx = val; 947222900Snp t.fs.mask.macidx = mask; 948222900Snp } else if (!parse_val_mask("matchtype", args, &val, &mask)) { 949222900Snp t.fs.val.matchtype = val; 950222900Snp t.fs.mask.matchtype = mask; 951222900Snp } else if (!parse_val_mask("frag", args, &val, &mask)) { 952222900Snp t.fs.val.frag = val; 953222900Snp t.fs.mask.frag = mask; 954222900Snp } else if (!parse_val_mask("dport", args, &val, &mask)) { 955222900Snp t.fs.val.dport = val; 956222900Snp t.fs.mask.dport = mask; 957222900Snp } else if (!parse_val_mask("sport", args, &val, &mask)) { 958222900Snp t.fs.val.sport = val; 959222900Snp t.fs.mask.sport = mask; 960222900Snp } else if (!parse_ipaddr("dip", args, &af, t.fs.val.dip, 961222900Snp t.fs.mask.dip)) { 962222900Snp /* nada */; 963222900Snp } else if (!parse_ipaddr("sip", args, &af, t.fs.val.sip, 964222900Snp t.fs.mask.sip)) { 965222900Snp /* nada */; 966222900Snp } else if (!strcmp(argv[start_arg], "action")) { 967222900Snp if (!strcmp(argv[start_arg + 1], "pass")) 968222900Snp t.fs.action = FILTER_PASS; 969222900Snp else if (!strcmp(argv[start_arg + 1], "drop")) 970222900Snp t.fs.action = FILTER_DROP; 971222900Snp else if (!strcmp(argv[start_arg + 1], "switch")) 972222900Snp t.fs.action = FILTER_SWITCH; 973222900Snp else { 974222900Snp warnx("invalid action \"%s\"; must be one of" 975222900Snp " \"pass\", \"drop\" or \"switch\"", 976222900Snp argv[start_arg + 1]); 977222900Snp return (EINVAL); 978222900Snp } 979222900Snp } else if (!parse_val("hitcnts", args, &val)) { 980222900Snp t.fs.hitcnts = val; 981222900Snp } else if (!parse_val("prio", args, &val)) { 982222900Snp t.fs.prio = val; 983222900Snp } else if (!parse_val("rpttid", args, &val)) { 984222900Snp t.fs.rpttid = 1; 985222900Snp } else if (!parse_val("queue", args, &val)) { 986222900Snp t.fs.dirsteer = 1; 987222900Snp t.fs.iq = val; 988222900Snp } else if (!parse_val("tcbhash", args, &val)) { 989222900Snp t.fs.maskhash = 1; 990222900Snp t.fs.dirsteerhash = 1; 991222900Snp } else if (!parse_val("eport", args, &val)) { 992222900Snp t.fs.eport = val; 993222900Snp } else if (!strcmp(argv[start_arg], "dmac")) { 994222900Snp struct ether_addr *daddr; 995222900Snp 996222900Snp daddr = ether_aton(argv[start_arg + 1]); 997222900Snp if (daddr == NULL) { 998222900Snp warnx("invalid dmac address \"%s\"", 999222900Snp argv[start_arg + 1]); 1000222900Snp return (EINVAL); 1001222900Snp } 1002222900Snp memcpy(t.fs.dmac, daddr, ETHER_ADDR_LEN); 1003222900Snp t.fs.newdmac = 1; 1004222900Snp } else if (!strcmp(argv[start_arg], "smac")) { 1005222900Snp struct ether_addr *saddr; 1006222900Snp 1007222900Snp saddr = ether_aton(argv[start_arg + 1]); 1008222900Snp if (saddr == NULL) { 1009222900Snp warnx("invalid smac address \"%s\"", 1010222900Snp argv[start_arg + 1]); 1011222900Snp return (EINVAL); 1012222900Snp } 1013222900Snp memcpy(t.fs.smac, saddr, ETHER_ADDR_LEN); 1014222900Snp t.fs.newsmac = 1; 1015222900Snp } else if (!strcmp(argv[start_arg], "vlan")) { 1016222900Snp char *p; 1017222900Snp if (!strcmp(argv[start_arg + 1], "none")) { 1018222900Snp t.fs.newvlan = VLAN_REMOVE; 1019222900Snp } else if (argv[start_arg + 1][0] == '=') { 1020222900Snp t.fs.newvlan = VLAN_REWRITE; 1021222900Snp } else if (argv[start_arg + 1][0] == '+') { 1022222900Snp t.fs.newvlan = VLAN_INSERT; 1023222900Snp } else { 1024222900Snp warnx("unknown vlan parameter \"%s\"; must" 1025222900Snp " be one of \"none\", \"=<vlan>\" or" 1026222900Snp " \"+<vlan>\"", argv[start_arg + 1]); 1027222900Snp return (EINVAL); 1028222900Snp } 1029222900Snp if (t.fs.newvlan == VLAN_REWRITE || 1030222900Snp t.fs.newvlan == VLAN_INSERT) { 1031222900Snp t.fs.vlan = strtoul(argv[start_arg + 1] + 1, 1032222900Snp &p, 0); 1033222900Snp if (p == argv[start_arg + 1] + 1 || p[0] != 0) { 1034222900Snp warnx("invalid vlan \"%s\"", 1035222900Snp argv[start_arg + 1]); 1036222900Snp return (EINVAL); 1037222900Snp } 1038222900Snp } 1039222900Snp } else { 1040222900Snp warnx("invalid parameter \"%s\"", argv[start_arg]); 1041222900Snp return (EINVAL); 1042222900Snp } 1043222900Snp } 1044222900Snp if (start_arg != argc) { 1045222900Snp warnx("no value for \"%s\"", argv[start_arg]); 1046222900Snp return (EINVAL); 1047222900Snp } 1048222900Snp 1049222900Snp /* 1050222900Snp * Check basic sanity of option combinations. 1051222900Snp */ 1052222900Snp if (t.fs.action != FILTER_SWITCH && 1053222900Snp (t.fs.eport || t.fs.newdmac || t.fs.newsmac || t.fs.newvlan)) { 1054222900Snp warnx("prio, port dmac, smac and vlan only make sense with" 1055222900Snp " \"action switch\""); 1056222900Snp return (EINVAL); 1057222900Snp } 1058222900Snp if (t.fs.action != FILTER_PASS && 1059222900Snp (t.fs.rpttid || t.fs.dirsteer || t.fs.maskhash)) { 1060222900Snp warnx("rpttid, queue and tcbhash don't make sense with" 1061222900Snp " action \"drop\" or \"switch\""); 1062222900Snp return (EINVAL); 1063222900Snp } 1064222900Snp 1065222900Snp t.fs.type = (af == AF_INET6 ? 1 : 0); /* default IPv4 */ 1066222900Snp return doit(CHELSIO_T4_SET_FILTER, &t); 1067222900Snp} 1068222900Snp 1069222900Snpstatic int 1070222900Snpfilter_cmd(int argc, const char *argv[]) 1071222900Snp{ 1072222900Snp long long val; 1073222900Snp uint32_t idx; 1074222900Snp char *s; 1075222900Snp 1076222900Snp if (argc == 0) { 1077222900Snp warnx("filter: no arguments."); 1078222900Snp return (EINVAL); 1079222900Snp }; 1080222900Snp 1081222900Snp /* list */ 1082222900Snp if (strcmp(argv[0], "list") == 0) { 1083222900Snp if (argc != 1) 1084222900Snp warnx("trailing arguments after \"list\" ignored."); 1085222900Snp 1086222900Snp return show_filters(); 1087222900Snp } 1088222900Snp 1089222900Snp /* mode */ 1090222900Snp if (argc == 1 && strcmp(argv[0], "mode") == 0) 1091222900Snp return get_filter_mode(); 1092222900Snp 1093222900Snp /* mode <mode> */ 1094222900Snp if (strcmp(argv[0], "mode") == 0) 1095222900Snp return set_filter_mode(argc - 1, argv + 1); 1096222900Snp 1097222900Snp /* <idx> ... */ 1098222900Snp s = str_to_number(argv[0], NULL, &val); 1099222900Snp if (*s || val > 0xffffffffU) { 1100222900Snp warnx("\"%s\" is neither an index nor a filter subcommand.", 1101222900Snp argv[0]); 1102222900Snp return (EINVAL); 1103222900Snp } 1104222900Snp idx = (uint32_t) val; 1105222900Snp 1106222900Snp /* <idx> delete|clear */ 1107222900Snp if (argc == 2 && 1108222900Snp (strcmp(argv[1], "delete") == 0 || strcmp(argv[1], "clear") == 0)) { 1109222900Snp return del_filter(idx); 1110222900Snp } 1111222900Snp 1112222900Snp /* <idx> [<param> <val>] ... */ 1113222900Snp return set_filter(idx, argc - 1, argv + 1); 1114222900Snp} 1115222900Snp 1116222900Snpstatic int 1117222900Snprun_cmd(int argc, const char *argv[]) 1118222900Snp{ 1119222900Snp int rc = -1; 1120222900Snp const char *cmd = argv[0]; 1121222900Snp 1122222900Snp /* command */ 1123222900Snp argc--; 1124222900Snp argv++; 1125222900Snp 1126222900Snp if (!strcmp(cmd, "reg") || !strcmp(cmd, "reg32")) 1127222900Snp rc = register_io(argc, argv, 4); 1128222900Snp else if (!strcmp(cmd, "reg64")) 1129222900Snp rc = register_io(argc, argv, 8); 1130222900Snp else if (!strcmp(cmd, "regdump")) 1131222900Snp rc = dump_regs(argc, argv); 1132222900Snp else if (!strcmp(cmd, "filter")) 1133222900Snp rc = filter_cmd(argc, argv); 1134222900Snp else { 1135222900Snp rc = EINVAL; 1136222900Snp warnx("invalid command \"%s\"", cmd); 1137222900Snp } 1138222900Snp 1139222900Snp return (rc); 1140222900Snp} 1141222900Snp 1142222900Snp#define MAX_ARGS 15 1143222900Snpstatic int 1144222900Snprun_cmd_loop(void) 1145222900Snp{ 1146222900Snp int i, rc = 0; 1147222900Snp char buffer[128], *buf; 1148222900Snp const char *args[MAX_ARGS + 1]; 1149222900Snp 1150222900Snp /* 1151222900Snp * Simple loop: displays a "> " prompt and processes any input as a 1152222900Snp * cxgbetool command. You're supposed to enter only the part after 1153222900Snp * "cxgbetool t4nexX". Use "quit" or "exit" to exit. 1154222900Snp */ 1155222900Snp for (;;) { 1156222900Snp fprintf(stdout, "> "); 1157222900Snp fflush(stdout); 1158222900Snp buf = fgets(buffer, sizeof(buffer), stdin); 1159222900Snp if (buf == NULL) { 1160222900Snp if (ferror(stdin)) { 1161222900Snp warn("stdin error"); 1162222900Snp rc = errno; /* errno from fgets */ 1163222900Snp } 1164222900Snp break; 1165222900Snp } 1166222900Snp 1167222900Snp i = 0; 1168222900Snp while ((args[i] = strsep(&buf, " \t\n")) != NULL) { 1169222900Snp if (args[i][0] != 0 && ++i == MAX_ARGS) 1170222900Snp break; 1171222900Snp } 1172222900Snp args[i] = 0; 1173222900Snp 1174222900Snp if (i == 0) 1175222900Snp continue; /* skip empty line */ 1176222900Snp 1177222900Snp if (!strcmp(args[0], "quit") || !strcmp(args[0], "exit")) 1178222900Snp break; 1179222900Snp 1180222900Snp rc = run_cmd(i, args); 1181222900Snp } 1182222900Snp 1183222900Snp /* rc normally comes from the last command (not including quit/exit) */ 1184222900Snp return (rc); 1185222900Snp} 1186222900Snp 1187222900Snpint 1188222900Snpmain(int argc, const char *argv[]) 1189222900Snp{ 1190222900Snp int rc = -1; 1191222900Snp 1192222900Snp progname = argv[0]; 1193222900Snp 1194222900Snp if (argc == 2) { 1195222900Snp if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { 1196222900Snp usage(stdout); 1197222900Snp exit(0); 1198222900Snp } 1199222900Snp } 1200222900Snp 1201222900Snp if (argc < 3) { 1202222900Snp usage(stderr); 1203222900Snp exit(EINVAL); 1204222900Snp } 1205222900Snp 1206222900Snp nexus = argv[1]; 1207222900Snp 1208222900Snp /* progname and nexus */ 1209222900Snp argc -= 2; 1210222900Snp argv += 2; 1211222900Snp 1212222900Snp if (argc == 1 && !strcmp(argv[0], "stdio")) 1213222900Snp rc = run_cmd_loop(); 1214222900Snp else 1215222900Snp rc = run_cmd(argc, argv); 1216222900Snp 1217222900Snp return (rc); 1218222900Snp} 1219