]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - tools/tools/cxgbetool/cxgbetool.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / tools / tools / cxgbetool / cxgbetool.c
1 /*-
2  * Copyright (c) 2011 Chelsio Communications, Inc.
3  * All rights reserved.
4  * Written by: Navdeep Parhar <np@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <err.h>
35 #include <fcntl.h>
36 #include <string.h>
37 #include <stdio.h>
38 #include <sys/ioctl.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <net/ethernet.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44
45 #include "t4_ioctl.h"
46
47 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
48
49 #define max(x, y) ((x) > (y) ? (x) : (y))
50
51 static const char *progname, *nexus;
52
53 struct reg_info {
54         const char *name;
55         uint32_t addr;
56         uint32_t len;
57 };
58
59 struct mod_regs {
60         const char *name;
61         const struct reg_info *ri;
62 };
63
64 struct field_desc {
65         const char *name;     /* Field name */
66         unsigned short start; /* Start bit position */
67         unsigned short end;   /* End bit position */
68         unsigned char shift;  /* # of low order bits omitted and implicitly 0 */
69         unsigned char hex;    /* Print field in hex instead of decimal */
70         unsigned char islog2; /* Field contains the base-2 log of the value */
71 };
72
73 #include "reg_defs_t4.c"
74 #include "reg_defs_t4vf.c"
75
76 static void
77 usage(FILE *fp)
78 {
79         fprintf(fp, "Usage: %s <nexus> [operation]\n", progname);
80         fprintf(fp,
81             "\tcontext <type> <id>                 show an SGE context\n"
82             "\tfilter <idx> [<param> <val>] ...    set a filter\n"
83             "\tfilter <idx> delete|clear           delete a filter\n"
84             "\tfilter list                         list all filters\n"
85             "\tfilter mode [<match>] ...           get/set global filter mode\n"
86             "\treg <address>[=<val>]               read/write register\n"
87             "\treg64 <address>[=<val>]             read/write 64 bit register\n"
88             "\tregdump [<module>] ...              dump registers\n"
89             "\tstdio                               interactive mode\n"
90             );
91 }
92
93 static inline unsigned int
94 get_card_vers(unsigned int version)
95 {
96         return (version & 0x3ff);
97 }
98
99 static int
100 real_doit(unsigned long cmd, void *data, const char *cmdstr)
101 {
102         static int fd = -1;
103         int rc = 0;
104
105         if (fd == -1) {
106                 char buf[64];
107
108                 snprintf(buf, sizeof(buf), "/dev/%s", nexus);
109                 if ((fd = open(buf, O_RDWR)) < 0) {
110                         warn("open(%s)", nexus);
111                         rc = errno;
112                         return (rc);
113                 }
114         }
115
116         rc = ioctl(fd, cmd, data);
117         if (rc < 0) {
118                 warn("%s", cmdstr);
119                 rc = errno;
120         }
121
122         return (rc);
123 }
124 #define doit(x, y) real_doit(x, y, #x)
125
126 static char *
127 str_to_number(const char *s, long *val, long long *vall)
128 {
129         char *p;
130
131         if (vall)
132                 *vall = strtoll(s, &p, 0);
133         else if (val)
134                 *val = strtol(s, &p, 0);
135         else
136                 p = NULL;
137
138         return (p);
139 }
140
141 static int
142 read_reg(long addr, int size, long long *val)
143 {
144         struct t4_reg reg;
145         int rc;
146
147         reg.addr = (uint32_t) addr;
148         reg.size = (uint32_t) size;
149         reg.val = 0;
150
151         rc = doit(CHELSIO_T4_GETREG, &reg);
152
153         *val = reg.val;
154
155         return (rc);
156 }
157
158 static int
159 write_reg(long addr, int size, long long val)
160 {
161         struct t4_reg reg;
162
163         reg.addr = (uint32_t) addr;
164         reg.size = (uint32_t) size;
165         reg.val = (uint64_t) val;
166
167         return doit(CHELSIO_T4_SETREG, &reg);
168 }
169
170 static int
171 register_io(int argc, const char *argv[], int size)
172 {
173         char *p, *v;
174         long addr;
175         long long val;
176         int w = 0, rc;
177
178         if (argc == 1) {
179                 /* <reg> OR <reg>=<value> */
180
181                 p = str_to_number(argv[0], &addr, NULL);
182                 if (*p) {
183                         if (*p != '=') {
184                                 warnx("invalid register \"%s\"", argv[0]);
185                                 return (EINVAL);
186                         }
187
188                         w = 1;
189                         v = p + 1;
190                         p = str_to_number(v, NULL, &val);
191
192                         if (*p) {
193                                 warnx("invalid value \"%s\"", v);
194                                 return (EINVAL);
195                         }
196                 }
197
198         } else if (argc == 2) {
199                 /* <reg> <value> */
200
201                 w = 1;
202
203                 p = str_to_number(argv[0], &addr, NULL);
204                 if (*p) {
205                         warnx("invalid register \"%s\"", argv[0]);
206                         return (EINVAL);
207                 }
208
209                 p = str_to_number(argv[1], NULL, &val);
210                 if (*p) {
211                         warnx("invalid value \"%s\"", argv[1]);
212                         return (EINVAL);
213                 }
214         } else {
215                 warnx("reg: invalid number of arguments (%d)", argc);
216                 return (EINVAL);
217         }
218
219         if (w)
220                 rc = write_reg(addr, size, val);
221         else {
222                 rc = read_reg(addr, size, &val);
223                 if (rc == 0)
224                         printf("0x%llx [%llu]\n", val, val);
225         }
226
227         return (rc);
228 }
229
230 static inline uint32_t
231 xtract(uint32_t val, int shift, int len)
232 {
233         return (val >> shift) & ((1 << len) - 1);
234 }
235
236 static int
237 dump_block_regs(const struct reg_info *reg_array, const uint32_t *regs)
238 {
239         uint32_t reg_val = 0;
240
241         for ( ; reg_array->name; ++reg_array)
242                 if (!reg_array->len) {
243                         reg_val = regs[reg_array->addr / 4];
244                         printf("[%#7x] %-47s %#-10x %u\n", reg_array->addr,
245                                reg_array->name, reg_val, reg_val);
246                 } else {
247                         uint32_t v = xtract(reg_val, reg_array->addr,
248                                             reg_array->len);
249
250                         printf("    %*u:%u %-47s %#-10x %u\n",
251                                reg_array->addr < 10 ? 3 : 2,
252                                reg_array->addr + reg_array->len - 1,
253                                reg_array->addr, reg_array->name, v, v);
254                 }
255
256         return (1);
257 }
258
259 static int
260 dump_regs_table(int argc, const char *argv[], const uint32_t *regs,
261     const struct mod_regs *modtab, int nmodules)
262 {
263         int i, j, match;
264
265         for (i = 0; i < argc; i++) {
266                 for (j = 0; j < nmodules; j++) {
267                         if (!strcmp(argv[i], modtab[j].name))
268                                 break;
269                 }
270
271                 if (j == nmodules) {
272                         warnx("invalid register block \"%s\"", argv[i]);
273                         fprintf(stderr, "\nAvailable blocks:");
274                         for ( ; nmodules; nmodules--, modtab++)
275                                 fprintf(stderr, " %s", modtab->name);
276                         fprintf(stderr, "\n");
277                         return (EINVAL);
278                 }
279         }
280
281         for ( ; nmodules; nmodules--, modtab++) {
282
283                 match = argc == 0 ? 1 : 0;
284                 for (i = 0; !match && i < argc; i++) {
285                         if (!strcmp(argv[i], modtab->name))
286                                 match = 1;
287                 }
288
289                 if (match)
290                         dump_block_regs(modtab->ri, regs);
291         }
292
293         return (0);
294 }
295
296 #define T4_MODREGS(name) { #name, t4_##name##_regs }
297 static int
298 dump_regs_t4(int argc, const char *argv[], const uint32_t *regs)
299 {
300         static struct mod_regs t4_mod[] = {
301                 T4_MODREGS(sge),
302                 { "pci", t4_pcie_regs },
303                 T4_MODREGS(dbg),
304                 T4_MODREGS(mc),
305                 T4_MODREGS(ma),
306                 { "edc0", t4_edc_0_regs },
307                 { "edc1", t4_edc_1_regs },
308                 T4_MODREGS(cim), 
309                 T4_MODREGS(tp),
310                 T4_MODREGS(ulp_rx),
311                 T4_MODREGS(ulp_tx),
312                 { "pmrx", t4_pm_rx_regs },
313                 { "pmtx", t4_pm_tx_regs },
314                 T4_MODREGS(mps),
315                 { "cplsw", t4_cpl_switch_regs },
316                 T4_MODREGS(smb),
317                 { "i2c", t4_i2cm_regs },
318                 T4_MODREGS(mi),
319                 T4_MODREGS(uart),
320                 T4_MODREGS(pmu), 
321                 T4_MODREGS(sf),
322                 T4_MODREGS(pl),
323                 T4_MODREGS(le),
324                 T4_MODREGS(ncsi),
325                 T4_MODREGS(xgmac)
326         };
327
328         return dump_regs_table(argc, argv, regs, t4_mod, ARRAY_SIZE(t4_mod));
329 }
330 #undef T4_MODREGS
331
332 static int
333 dump_regs_t4vf(int argc, const char *argv[], const uint32_t *regs)
334 {
335         static struct mod_regs t4vf_mod[] = {
336                 { "sge", t4vf_sge_regs },
337                 { "mps", t4vf_mps_regs },
338                 { "pl", t4vf_pl_regs },
339                 { "mbdata", t4vf_mbdata_regs },
340                 { "cim", t4vf_cim_regs },
341         };
342
343         return dump_regs_table(argc, argv, regs, t4vf_mod,
344             ARRAY_SIZE(t4vf_mod));
345 }
346
347 static int
348 dump_regs(int argc, const char *argv[])
349 {
350         int vers, revision, is_pcie, rc;
351         struct t4_regdump regs;
352
353         regs.data = calloc(1, T4_REGDUMP_SIZE);
354         if (regs.data == NULL) {
355                 warnc(ENOMEM, "regdump");
356                 return (ENOMEM);
357         }
358
359         regs.len = T4_REGDUMP_SIZE;
360         rc = doit(CHELSIO_T4_REGDUMP, &regs);
361         if (rc != 0)
362                 return (rc);
363
364         vers = get_card_vers(regs.version);
365         revision = (regs.version >> 10) & 0x3f;
366         is_pcie = (regs.version & 0x80000000) != 0;
367
368         if (vers == 4) {
369                 if (revision == 0x3f)
370                         rc = dump_regs_t4vf(argc, argv, regs.data);
371                 else
372                         rc = dump_regs_t4(argc, argv, regs.data);
373         } else {
374                 warnx("%s (type %d, rev %d) is not a T4 card.",
375                     nexus, vers, revision);
376                 return (ENOTSUP);
377         }
378
379         free(regs.data);
380         return (rc);
381 }
382
383 static void
384 do_show_info_header(uint32_t mode)
385 {
386         uint32_t i;
387
388         printf ("%4s %8s", "Idx", "Hits");
389         for (i = T4_FILTER_FCoE; i <= T4_FILTER_IP_FRAGMENT; i <<= 1) {
390                 switch (mode & i) {
391                 case T4_FILTER_FCoE:
392                         printf (" FCoE");
393                         break;
394
395                 case T4_FILTER_PORT:
396                         printf (" Port");
397                         break;
398
399                 case T4_FILTER_OVLAN:
400                         printf ("     vld:oVLAN");
401                         break;
402
403                 case T4_FILTER_IVLAN:
404                         printf ("     vld:iVLAN");
405                         break;
406
407                 case T4_FILTER_IP_TOS:
408                         printf ("   TOS");
409                         break;
410
411                 case T4_FILTER_IP_PROTO:
412                         printf ("  Prot");
413                         break;
414
415                 case T4_FILTER_ETH_TYPE:
416                         printf ("   EthType");
417                         break;
418
419                 case T4_FILTER_MAC_IDX:
420                         printf ("  MACIdx");
421                         break;
422
423                 case T4_FILTER_MPS_HIT_TYPE:
424                         printf (" MPS");
425                         break;
426
427                 case T4_FILTER_IP_FRAGMENT:
428                         printf (" Frag");
429                         break;
430
431                 default:
432                         /* compressed filter field not enabled */
433                         break;
434                 }
435         }
436         printf(" %20s %20s %9s %9s %s\n",
437             "DIP", "SIP", "DPORT", "SPORT", "Action");
438 }
439
440 /*
441  * Parse an argument sub-vector as a { <parameter name> <value>[:<mask>] }
442  * ordered tuple.  If the parameter name in the argument sub-vector does not
443  * match the passed in parameter name, then a zero is returned for the
444  * function and no parsing is performed.  If there is a match, then the value
445  * and optional mask are parsed and returned in the provided return value
446  * pointers.  If no optional mask is specified, then a default mask of all 1s
447  * will be returned.
448  *
449  * An error in parsing the value[:mask] will result in an error message and
450  * program termination.
451  */
452 static int
453 parse_val_mask(const char *param, const char *args[], uint32_t *val,
454     uint32_t *mask)
455 {
456         char *p;
457
458         if (strcmp(param, args[0]) != 0)
459                 return (EINVAL);
460
461         *val = strtoul(args[1], &p, 0);
462         if (p > args[1]) {
463                 if (p[0] == 0) {
464                         *mask = ~0;
465                         return (0);
466                 }
467
468                 if (p[0] == ':' && p[1] != 0) {
469                         *mask = strtoul(p+1, &p, 0);
470                         if (p[0] == 0)
471                                 return (0);
472                 }
473         }
474
475         warnx("parameter \"%s\" has bad \"value[:mask]\" %s",
476             args[0], args[1]);
477
478         return (EINVAL);
479 }
480
481 /*
482  * Parse an argument sub-vector as a { <parameter name> <addr>[/<mask>] }
483  * ordered tuple.  If the parameter name in the argument sub-vector does not
484  * match the passed in parameter name, then a zero is returned for the
485  * function and no parsing is performed.  If there is a match, then the value
486  * and optional mask are parsed and returned in the provided return value
487  * pointers.  If no optional mask is specified, then a default mask of all 1s
488  * will be returned.
489  *
490  * The value return parameter "afp" is used to specify the expected address
491  * family -- IPv4 or IPv6 -- of the address[/mask] and return its actual
492  * format.  A passed in value of AF_UNSPEC indicates that either IPv4 or IPv6
493  * is acceptable; AF_INET means that only IPv4 addresses are acceptable; and
494  * AF_INET6 means that only IPv6 are acceptable.  AF_INET is returned for IPv4
495  * and AF_INET6 for IPv6 addresses, respectively.  IPv4 address/mask pairs are
496  * returned in the first four bytes of the address and mask return values with
497  * the address A.B.C.D returned with { A, B, C, D } returned in addresses { 0,
498  * 1, 2, 3}, respectively.
499  *
500  * An error in parsing the value[:mask] will result in an error message and
501  * program termination.
502  */
503 static int
504 parse_ipaddr(const char *param, const char *args[], int *afp, uint8_t addr[],
505     uint8_t mask[])
506 {
507         const char *colon, *afn;
508         char *slash;
509         uint8_t *m;
510         int af, ret;
511         unsigned int masksize;
512
513         /*
514          * Is this our parameter?
515          */
516         if (strcmp(param, args[0]) != 0)
517                 return (EINVAL);
518
519         /*
520          * Fundamental IPv4 versus IPv6 selection.
521          */
522         colon = strchr(args[1], ':');
523         if (!colon) {
524                 afn = "IPv4";
525                 af = AF_INET;
526                 masksize = 32;
527         } else {
528                 afn = "IPv6";
529                 af = AF_INET6;
530                 masksize = 128;
531         }
532         if (*afp == AF_UNSPEC)
533                 *afp = af;
534         else if (*afp != af) {
535                 warnx("address %s is not of expected family %s",
536                     args[1], *afp == AF_INET ? "IP" : "IPv6");
537                 return (EINVAL);
538         }
539
540         /*
541          * Parse address (temporarily stripping off any "/mask"
542          * specification).
543          */
544         slash = strchr(args[1], '/');
545         if (slash)
546                 *slash = 0;
547         ret = inet_pton(af, args[1], addr);
548         if (slash)
549                 *slash = '/';
550         if (ret <= 0) {
551                 warnx("Cannot parse %s %s address %s", param, afn, args[1]);
552                 return (EINVAL);
553         }
554
555         /*
556          * Parse optional mask specification.
557          */
558         if (slash) {
559                 char *p;
560                 unsigned int prefix = strtoul(slash + 1, &p, 10);
561
562                 if (p == slash + 1) {
563                         warnx("missing address prefix for %s", param);
564                         return (EINVAL);
565                 }
566                 if (*p) {
567                         warnx("%s is not a valid address prefix", slash + 1);
568                         return (EINVAL);
569                 }
570                 if (prefix > masksize) {
571                         warnx("prefix %u is too long for an %s address",
572                              prefix, afn);
573                         return (EINVAL);
574                 }
575                 memset(mask, 0, masksize / 8);
576                 masksize = prefix;
577         }
578
579         /*
580          * Fill in mask.
581          */
582         for (m = mask; masksize >= 8; m++, masksize -= 8)
583                 *m = ~0;
584         if (masksize)
585                 *m = ~0 << (8 - masksize);
586
587         return (0);
588 }
589
590 /*
591  * Parse an argument sub-vector as a { <parameter name> <value> } ordered
592  * tuple.  If the parameter name in the argument sub-vector does not match the
593  * passed in parameter name, then a zero is returned for the function and no
594  * parsing is performed.  If there is a match, then the value is parsed and
595  * returned in the provided return value pointer.
596  */
597 static int
598 parse_val(const char *param, const char *args[], uint32_t *val)
599 {
600         char *p;
601
602         if (strcmp(param, args[0]) != 0)
603                 return (EINVAL);
604
605         *val = strtoul(args[1], &p, 0);
606         if (p > args[1] && p[0] == 0)
607                 return (0);
608
609         warnx("parameter \"%s\" has bad \"value\" %s", args[0], args[1]);
610         return (EINVAL);
611 }
612
613 static void
614 filters_show_ipaddr(int type, uint8_t *addr, uint8_t *addrm)
615 {
616         int noctets, octet;
617
618         printf(" ");
619         if (type == 0) {
620                 noctets = 4;
621                 printf("%3s", " ");
622         } else
623         noctets = 16;
624
625         for (octet = 0; octet < noctets; octet++)
626                 printf("%02x", addr[octet]);
627         printf("/");
628         for (octet = 0; octet < noctets; octet++)
629                 printf("%02x", addrm[octet]);
630 }
631
632 static void
633 do_show_one_filter_info(struct t4_filter *t, uint32_t mode)
634 {
635         uint32_t i;
636
637         printf("%4d", t->idx);
638         if (t->hits == UINT64_MAX)
639                 printf(" %8s", "-");
640         else
641                 printf(" %8ju", t->hits);
642
643         /*
644          * Compressed header portion of filter.
645          */
646         for (i = T4_FILTER_FCoE; i <= T4_FILTER_IP_FRAGMENT; i <<= 1) {
647                 switch (mode & i) {
648                 case T4_FILTER_FCoE:
649                         printf("  %1d/%1d", t->fs.val.fcoe, t->fs.mask.fcoe);
650                         break;
651
652                 case T4_FILTER_PORT:
653                         printf("  %1d/%1d", t->fs.val.iport, t->fs.mask.iport);
654                         break;
655
656                 case T4_FILTER_OVLAN:
657                         printf(" %1d:%1x:%02x/%1d:%1x:%02x",
658                             t->fs.val.ovlan_vld, (t->fs.val.ovlan >> 7) & 0x7,
659                             t->fs.val.ovlan & 0x7f, t->fs.mask.ovlan_vld,
660                             (t->fs.mask.ovlan >> 7) & 0x7,
661                             t->fs.mask.ovlan & 0x7f);
662                         break;
663
664                 case T4_FILTER_IVLAN:
665                         printf(" %1d:%04x/%1d:%04x",
666                             t->fs.val.ivlan_vld, t->fs.val.ivlan,
667                             t->fs.mask.ivlan_vld, t->fs.mask.ivlan);
668                         break;
669
670                 case T4_FILTER_IP_TOS:
671                         printf(" %02x/%02x", t->fs.val.tos, t->fs.mask.tos);
672                         break;
673
674                 case T4_FILTER_IP_PROTO:
675                         printf(" %02x/%02x", t->fs.val.proto, t->fs.mask.proto);
676                         break;
677
678                 case T4_FILTER_ETH_TYPE:
679                         printf(" %04x/%04x", t->fs.val.ethtype,
680                             t->fs.mask.ethtype);
681                         break;
682
683                 case T4_FILTER_MAC_IDX:
684                         printf(" %03x/%03x", t->fs.val.macidx,
685                             t->fs.mask.macidx);
686                         break;
687
688                 case T4_FILTER_MPS_HIT_TYPE:
689                         printf(" %1x/%1x", t->fs.val.matchtype,
690                             t->fs.mask.matchtype);
691                         break;
692
693                 case T4_FILTER_IP_FRAGMENT:
694                         printf("  %1d/%1d", t->fs.val.frag, t->fs.mask.frag);
695                         break;
696
697                 default:
698                         /* compressed filter field not enabled */
699                         break;
700                 }
701         }
702
703         /*
704          * Fixed portion of filter.
705          */
706         filters_show_ipaddr(t->fs.type, t->fs.val.dip, t->fs.mask.dip);
707         filters_show_ipaddr(t->fs.type, t->fs.val.sip, t->fs.mask.sip);
708         printf(" %04x/%04x %04x/%04x",
709                  t->fs.val.dport, t->fs.mask.dport,
710                  t->fs.val.sport, t->fs.mask.sport);
711
712         /*
713          * Variable length filter action.
714          */
715         if (t->fs.action == FILTER_DROP)
716                 printf(" Drop");
717         else if (t->fs.action == FILTER_SWITCH) {
718                 printf(" Switch: port=%d", t->fs.eport);
719         if (t->fs.newdmac)
720                 printf(
721                         ", dmac=%02x:%02x:%02x:%02x:%02x:%02x "
722                         ", l2tidx=%d",
723                         t->fs.dmac[0], t->fs.dmac[1],
724                         t->fs.dmac[2], t->fs.dmac[3],
725                         t->fs.dmac[4], t->fs.dmac[5],
726                         t->l2tidx);
727         if (t->fs.newsmac)
728                 printf(
729                         ", smac=%02x:%02x:%02x:%02x:%02x:%02x "
730                         ", smtidx=%d",
731                         t->fs.smac[0], t->fs.smac[1],
732                         t->fs.smac[2], t->fs.smac[3],
733                         t->fs.smac[4], t->fs.smac[5],
734                         t->smtidx);
735         if (t->fs.newvlan == VLAN_REMOVE)
736                 printf(", vlan=none");
737         else if (t->fs.newvlan == VLAN_INSERT)
738                 printf(", vlan=insert(%x)", t->fs.vlan);
739         else if (t->fs.newvlan == VLAN_REWRITE)
740                 printf(", vlan=rewrite(%x)", t->fs.vlan);
741         } else {
742                 printf(" Pass: Q=");
743                 if (t->fs.dirsteer == 0) {
744                         printf("RSS");
745                         if (t->fs.maskhash)
746                                 printf("(TCB=hash)");
747                 } else {
748                         printf("%d", t->fs.iq);
749                         if (t->fs.dirsteerhash == 0)
750                                 printf("(QID)");
751                         else
752                                 printf("(hash)");
753                 }
754         }
755         if (t->fs.prio)
756                 printf(" Prio");
757         if (t->fs.rpttid)
758                 printf(" RptTID");
759         printf("\n");
760 }
761
762 static int
763 show_filters(void)
764 {
765         uint32_t mode = 0, header = 0;
766         struct t4_filter t;
767         int rc;
768
769         /* Get the global filter mode first */
770         rc = doit(CHELSIO_T4_GET_FILTER_MODE, &mode);
771         if (rc != 0)
772                 return (rc);
773
774         t.idx = 0;
775         for (t.idx = 0; ; t.idx++) {
776                 rc = doit(CHELSIO_T4_GET_FILTER, &t);
777                 if (rc != 0 || t.idx == 0xffffffff)
778                         break;
779
780                 if (!header) {
781                         do_show_info_header(mode);
782                         header = 1;
783                 }
784                 do_show_one_filter_info(&t, mode);
785         };
786
787         return (rc);
788 }
789
790 static int
791 get_filter_mode(void)
792 {
793         uint32_t mode = 0;
794         int rc;
795
796         rc = doit(CHELSIO_T4_GET_FILTER_MODE, &mode);
797         if (rc != 0)
798                 return (rc);
799
800         if (mode & T4_FILTER_IPv4)
801                 printf("ipv4 ");
802
803         if (mode & T4_FILTER_IPv6)
804                 printf("ipv6 ");
805
806         if (mode & T4_FILTER_IP_SADDR)
807                 printf("sip ");
808         
809         if (mode & T4_FILTER_IP_DADDR)
810                 printf("dip ");
811
812         if (mode & T4_FILTER_IP_SPORT)
813                 printf("sport ");
814
815         if (mode & T4_FILTER_IP_DPORT)
816                 printf("dport ");
817
818         if (mode & T4_FILTER_MPS_HIT_TYPE)
819                 printf("matchtype ");
820
821         if (mode & T4_FILTER_MAC_IDX)
822                 printf("macidx ");
823
824         if (mode & T4_FILTER_ETH_TYPE)
825                 printf("ethtype ");
826
827         if (mode & T4_FILTER_IP_PROTO)
828                 printf("proto ");
829
830         if (mode & T4_FILTER_IP_TOS)
831                 printf("tos ");
832
833         if (mode & T4_FILTER_IVLAN)
834                 printf("ivlan ");
835
836         if (mode & T4_FILTER_OVLAN)
837                 printf("ovlan ");
838
839         if (mode & T4_FILTER_PORT)
840                 printf("iport ");
841
842         if (mode & T4_FILTER_FCoE)
843                 printf("fcoe ");
844
845         printf("\n");
846
847         return (0);
848 }
849
850 static int
851 set_filter_mode(int argc, const char *argv[])
852 {
853         uint32_t mode = 0;
854
855         for (; argc; argc--, argv++) {
856                 if (!strcmp(argv[0], "matchtype"))
857                         mode |= T4_FILTER_MPS_HIT_TYPE;
858
859                 if (!strcmp(argv[0], "macidx"))
860                         mode |= T4_FILTER_MAC_IDX;
861
862                 if (!strcmp(argv[0], "ethtype"))
863                         mode |= T4_FILTER_ETH_TYPE;
864
865                 if (!strcmp(argv[0], "proto"))
866                         mode |= T4_FILTER_IP_PROTO;
867
868                 if (!strcmp(argv[0], "tos"))
869                         mode |= T4_FILTER_IP_TOS;
870
871                 if (!strcmp(argv[0], "ivlan"))
872                         mode |= T4_FILTER_IVLAN;
873
874                 if (!strcmp(argv[0], "ovlan"))
875                         mode |= T4_FILTER_OVLAN;
876
877                 if (!strcmp(argv[0], "iport"))
878                         mode |= T4_FILTER_PORT;
879
880                 if (!strcmp(argv[0], "fcoe"))
881                         mode |= T4_FILTER_FCoE;
882         }
883
884         return doit(CHELSIO_T4_SET_FILTER_MODE, &mode);
885 }
886
887 static int
888 del_filter(uint32_t idx)
889 {
890         struct t4_filter t;
891
892         t.idx = idx;
893
894         return doit(CHELSIO_T4_DEL_FILTER, &t);
895 }
896
897 static int
898 set_filter(uint32_t idx, int argc, const char *argv[])
899 {
900         int af = AF_UNSPEC, start_arg = 0;
901         struct t4_filter t;
902
903         if (argc < 2) {
904                 warnc(EINVAL, "%s", __func__);
905                 return (EINVAL);
906         };
907         bzero(&t, sizeof (t));
908         t.idx = idx;
909
910         for (start_arg = 0; start_arg + 2 <= argc; start_arg += 2) {
911                 const char **args = &argv[start_arg];
912                 uint32_t val, mask;
913
914                 if (!strcmp(argv[start_arg], "type")) {
915                         int newaf;
916                         if (!strcasecmp(argv[start_arg + 1], "ipv4"))
917                                 newaf = AF_INET;
918                         else if (!strcasecmp(argv[start_arg + 1], "ipv6"))
919                                 newaf = AF_INET6;
920                         else {
921                                 warnx("invalid type \"%s\"; "
922                                     "must be one of \"ipv4\" or \"ipv6\"",
923                                     argv[start_arg + 1]);
924                                 return (EINVAL);
925                         }
926
927                         if (af != AF_UNSPEC && af != newaf) {
928                                 warnx("conflicting IPv4/IPv6 specifications.");
929                                 return (EINVAL);
930                         }
931                         af = newaf;
932                 } else if (!parse_val_mask("fcoe", args, &val, &mask)) {
933                         t.fs.val.fcoe = val;
934                         t.fs.mask.fcoe = mask;
935                 } else if (!parse_val_mask("iport", args, &val, &mask)) {
936                         t.fs.val.iport = val;
937                         t.fs.mask.iport = mask;
938                 } else if (!parse_val_mask("ovlan", args, &val, &mask)) {
939                         t.fs.val.ovlan = val;
940                         t.fs.mask.ovlan = mask;
941                         t.fs.val.ovlan_vld = 1;
942                         t.fs.mask.ovlan_vld = 1;
943                 } else if (!parse_val_mask("ivlan", args, &val, &mask)) {
944                         t.fs.val.ivlan = val;
945                         t.fs.mask.ivlan = mask;
946                         t.fs.val.ivlan_vld = 1;
947                         t.fs.mask.ivlan_vld = 1;
948                 } else if (!parse_val_mask("tos", args, &val, &mask)) {
949                         t.fs.val.tos = val;
950                         t.fs.mask.tos = mask;
951                 } else if (!parse_val_mask("proto", args, &val, &mask)) {
952                         t.fs.val.proto = val;
953                         t.fs.mask.proto = mask;
954                 } else if (!parse_val_mask("ethtype", args, &val, &mask)) {
955                         t.fs.val.ethtype = val;
956                         t.fs.mask.ethtype = mask;
957                 } else if (!parse_val_mask("macidx", args, &val, &mask)) {
958                         t.fs.val.macidx = val;
959                         t.fs.mask.macidx = mask;
960                 } else if (!parse_val_mask("matchtype", args, &val, &mask)) {
961                         t.fs.val.matchtype = val;
962                         t.fs.mask.matchtype = mask;
963                 } else if (!parse_val_mask("frag", args, &val, &mask)) {
964                         t.fs.val.frag = val;
965                         t.fs.mask.frag = mask;
966                 } else if (!parse_val_mask("dport", args, &val, &mask)) {
967                         t.fs.val.dport = val;
968                         t.fs.mask.dport = mask;
969                 } else if (!parse_val_mask("sport", args, &val, &mask)) {
970                         t.fs.val.sport = val;
971                         t.fs.mask.sport = mask;
972                 } else if (!parse_ipaddr("dip", args, &af, t.fs.val.dip,
973                     t.fs.mask.dip)) {
974                         /* nada */;
975                 } else if (!parse_ipaddr("sip", args, &af, t.fs.val.sip,
976                     t.fs.mask.sip)) {
977                         /* nada */;
978                 } else if (!strcmp(argv[start_arg], "action")) {
979                         if (!strcmp(argv[start_arg + 1], "pass"))
980                                 t.fs.action = FILTER_PASS;
981                         else if (!strcmp(argv[start_arg + 1], "drop"))
982                                 t.fs.action = FILTER_DROP;
983                         else if (!strcmp(argv[start_arg + 1], "switch"))
984                                 t.fs.action = FILTER_SWITCH;
985                         else {
986                                 warnx("invalid action \"%s\"; must be one of"
987                                      " \"pass\", \"drop\" or \"switch\"",
988                                      argv[start_arg + 1]);
989                                 return (EINVAL);
990                         }
991                 } else if (!parse_val("hitcnts", args, &val)) {
992                         t.fs.hitcnts = val;
993                 } else if (!parse_val("prio", args, &val)) {
994                         t.fs.prio = val;
995                 } else if (!parse_val("rpttid", args, &val)) {
996                         t.fs.rpttid = 1;
997                 } else if (!parse_val("queue", args, &val)) {
998                         t.fs.dirsteer = 1;
999                         t.fs.iq = val;
1000                 } else if (!parse_val("tcbhash", args, &val)) {
1001                         t.fs.maskhash = 1;
1002                         t.fs.dirsteerhash = 1;
1003                 } else if (!parse_val("eport", args, &val)) {
1004                         t.fs.eport = val;
1005                 } else if (!strcmp(argv[start_arg], "dmac")) {
1006                         struct ether_addr *daddr;
1007
1008                         daddr = ether_aton(argv[start_arg + 1]);
1009                         if (daddr == NULL) {
1010                                 warnx("invalid dmac address \"%s\"",
1011                                     argv[start_arg + 1]);
1012                                 return (EINVAL);
1013                         }
1014                         memcpy(t.fs.dmac, daddr, ETHER_ADDR_LEN);
1015                         t.fs.newdmac = 1;
1016                 } else if (!strcmp(argv[start_arg], "smac")) {
1017                         struct ether_addr *saddr;
1018
1019                         saddr = ether_aton(argv[start_arg + 1]);
1020                         if (saddr == NULL) {
1021                                 warnx("invalid smac address \"%s\"",
1022                                     argv[start_arg + 1]);
1023                                 return (EINVAL);
1024                         }
1025                         memcpy(t.fs.smac, saddr, ETHER_ADDR_LEN);
1026                         t.fs.newsmac = 1;
1027                 } else if (!strcmp(argv[start_arg], "vlan")) {
1028                         char *p;
1029                         if (!strcmp(argv[start_arg + 1], "none")) {
1030                                 t.fs.newvlan = VLAN_REMOVE;
1031                         } else if (argv[start_arg + 1][0] == '=') {
1032                                 t.fs.newvlan = VLAN_REWRITE;
1033                         } else if (argv[start_arg + 1][0] == '+') {
1034                                 t.fs.newvlan = VLAN_INSERT;
1035                         } else {
1036                                 warnx("unknown vlan parameter \"%s\"; must"
1037                                      " be one of \"none\", \"=<vlan>\" or"
1038                                      " \"+<vlan>\"", argv[start_arg + 1]);
1039                                 return (EINVAL);
1040                         }
1041                         if (t.fs.newvlan == VLAN_REWRITE ||
1042                             t.fs.newvlan == VLAN_INSERT) {
1043                                 t.fs.vlan = strtoul(argv[start_arg + 1] + 1,
1044                                     &p, 0);
1045                                 if (p == argv[start_arg + 1] + 1 || p[0] != 0) {
1046                                         warnx("invalid vlan \"%s\"",
1047                                              argv[start_arg + 1]);
1048                                         return (EINVAL);
1049                                 }
1050                         }
1051                 } else {
1052                         warnx("invalid parameter \"%s\"", argv[start_arg]);
1053                         return (EINVAL);
1054                 }
1055         }
1056         if (start_arg != argc) {
1057                 warnx("no value for \"%s\"", argv[start_arg]);
1058                 return (EINVAL);
1059         }
1060
1061         /*
1062          * Check basic sanity of option combinations.
1063          */
1064         if (t.fs.action != FILTER_SWITCH &&
1065             (t.fs.eport || t.fs.newdmac || t.fs.newsmac || t.fs.newvlan)) {
1066                 warnx("prio, port dmac, smac and vlan only make sense with"
1067                      " \"action switch\"");
1068                 return (EINVAL);
1069         }
1070         if (t.fs.action != FILTER_PASS &&
1071             (t.fs.rpttid || t.fs.dirsteer || t.fs.maskhash)) {
1072                 warnx("rpttid, queue and tcbhash don't make sense with"
1073                      " action \"drop\" or \"switch\"");
1074                 return (EINVAL);
1075         }
1076
1077         t.fs.type = (af == AF_INET6 ? 1 : 0); /* default IPv4 */
1078         return doit(CHELSIO_T4_SET_FILTER, &t);
1079 }
1080
1081 static int
1082 filter_cmd(int argc, const char *argv[])
1083 {
1084         long long val;
1085         uint32_t idx;
1086         char *s;
1087
1088         if (argc == 0) {
1089                 warnx("filter: no arguments.");
1090                 return (EINVAL);
1091         };
1092
1093         /* list */
1094         if (strcmp(argv[0], "list") == 0) {
1095                 if (argc != 1)
1096                         warnx("trailing arguments after \"list\" ignored.");
1097
1098                 return show_filters();
1099         }
1100
1101         /* mode */
1102         if (argc == 1 && strcmp(argv[0], "mode") == 0)
1103                 return get_filter_mode();
1104
1105         /* mode <mode> */
1106         if (strcmp(argv[0], "mode") == 0)
1107                 return set_filter_mode(argc - 1, argv + 1);
1108
1109         /* <idx> ... */
1110         s = str_to_number(argv[0], NULL, &val);
1111         if (*s || val > 0xffffffffU) {
1112                 warnx("\"%s\" is neither an index nor a filter subcommand.",
1113                     argv[0]);
1114                 return (EINVAL);
1115         }
1116         idx = (uint32_t) val;
1117
1118         /* <idx> delete|clear */
1119         if (argc == 2 &&
1120             (strcmp(argv[1], "delete") == 0 || strcmp(argv[1], "clear") == 0)) {
1121                 return del_filter(idx);
1122         }
1123
1124         /* <idx> [<param> <val>] ... */
1125         return set_filter(idx, argc - 1, argv + 1);
1126 }
1127
1128 /*
1129  * Shows the fields of a multi-word structure.  The structure is considered to
1130  * consist of @nwords 32-bit words (i.e, it's an (@nwords * 32)-bit structure)
1131  * whose fields are described by @fd.  The 32-bit words are given in @words
1132  * starting with the least significant 32-bit word.
1133  */
1134 static void
1135 show_struct(const uint32_t *words, int nwords, const struct field_desc *fd)
1136 {
1137         unsigned int w = 0;
1138         const struct field_desc *p;
1139
1140         for (p = fd; p->name; p++)
1141                 w = max(w, strlen(p->name));
1142
1143         while (fd->name) {
1144                 unsigned long long data;
1145                 int first_word = fd->start / 32;
1146                 int shift = fd->start % 32;
1147                 int width = fd->end - fd->start + 1;
1148                 unsigned long long mask = (1ULL << width) - 1;
1149
1150                 data = (words[first_word] >> shift) |
1151                        ((uint64_t)words[first_word + 1] << (32 - shift));
1152                 if (shift)
1153                        data |= ((uint64_t)words[first_word + 2] << (64 - shift));
1154                 data &= mask;
1155                 if (fd->islog2)
1156                         data = 1 << data;
1157                 printf("%-*s ", w, fd->name);
1158                 printf(fd->hex ? "%#llx\n" : "%llu\n", data << fd->shift);
1159                 fd++;
1160         }
1161 }
1162
1163 #define FIELD(name, start, end) { name, start, end, 0, 0, 0 }
1164 #define FIELD1(name, start) FIELD(name, start, start)
1165
1166 static void
1167 show_sge_context(const struct t4_sge_context *p)
1168 {
1169         static struct field_desc egress[] = {
1170                 FIELD1("StatusPgNS:", 180),
1171                 FIELD1("StatusPgRO:", 179),
1172                 FIELD1("FetchNS:", 178),
1173                 FIELD1("FetchRO:", 177),
1174                 FIELD1("Valid:", 176),
1175                 FIELD("PCIeDataChannel:", 174, 175),
1176                 FIELD1("DCAEgrQEn:", 173),
1177                 FIELD("DCACPUID:", 168, 172),
1178                 FIELD1("FCThreshOverride:", 167),
1179                 FIELD("WRLength:", 162, 166),
1180                 FIELD1("WRLengthKnown:", 161),
1181                 FIELD1("ReschedulePending:", 160),
1182                 FIELD1("OnChipQueue:", 159),
1183                 FIELD1("FetchSizeMode", 158),
1184                 { "FetchBurstMin:", 156, 157, 4, 0, 1 },
1185                 { "FetchBurstMax:", 153, 154, 6, 0, 1 },
1186                 FIELD("uPToken:", 133, 152),
1187                 FIELD1("uPTokenEn:", 132),
1188                 FIELD1("UserModeIO:", 131),
1189                 FIELD("uPFLCredits:", 123, 130),
1190                 FIELD1("uPFLCreditEn:", 122),
1191                 FIELD("FID:", 111, 121),
1192                 FIELD("HostFCMode:", 109, 110),
1193                 FIELD1("HostFCOwner:", 108),
1194                 { "CIDXFlushThresh:", 105, 107, 0, 0, 1 },
1195                 FIELD("CIDX:", 89, 104),
1196                 FIELD("PIDX:", 73, 88),
1197                 { "BaseAddress:", 18, 72, 9, 1 },
1198                 FIELD("QueueSize:", 2, 17),
1199                 FIELD1("QueueType:", 1),
1200                 FIELD1("CachePriority:", 0),
1201                 { NULL }
1202         };
1203         static struct field_desc fl[] = {
1204                 FIELD1("StatusPgNS:", 180),
1205                 FIELD1("StatusPgRO:", 179),
1206                 FIELD1("FetchNS:", 178),
1207                 FIELD1("FetchRO:", 177),
1208                 FIELD1("Valid:", 176),
1209                 FIELD("PCIeDataChannel:", 174, 175),
1210                 FIELD1("DCAEgrQEn:", 173),
1211                 FIELD("DCACPUID:", 168, 172),
1212                 FIELD1("FCThreshOverride:", 167),
1213                 FIELD("WRLength:", 162, 166),
1214                 FIELD1("WRLengthKnown:", 161),
1215                 FIELD1("ReschedulePending:", 160),
1216                 FIELD1("OnChipQueue:", 159),
1217                 FIELD1("FetchSizeMode", 158),
1218                 { "FetchBurstMin:", 156, 157, 4, 0, 1 },
1219                 { "FetchBurstMax:", 153, 154, 6, 0, 1 },
1220                 FIELD1("FLMcongMode:", 152),
1221                 FIELD("MaxuPFLCredits:", 144, 151),
1222                 FIELD("FLMcontextID:", 133, 143),
1223                 FIELD1("uPTokenEn:", 132),
1224                 FIELD1("UserModeIO:", 131),
1225                 FIELD("uPFLCredits:", 123, 130),
1226                 FIELD1("uPFLCreditEn:", 122),
1227                 FIELD("FID:", 111, 121),
1228                 FIELD("HostFCMode:", 109, 110),
1229                 FIELD1("HostFCOwner:", 108),
1230                 { "CIDXFlushThresh:", 105, 107, 0, 0, 1 },
1231                 FIELD("CIDX:", 89, 104),
1232                 FIELD("PIDX:", 73, 88),
1233                 { "BaseAddress:", 18, 72, 9, 1 },
1234                 FIELD("QueueSize:", 2, 17),
1235                 FIELD1("QueueType:", 1),
1236                 FIELD1("CachePriority:", 0),
1237                 { NULL }
1238         };
1239         static struct field_desc ingress[] = {
1240                 FIELD1("NoSnoop:", 145),
1241                 FIELD1("RelaxedOrdering:", 144),
1242                 FIELD1("GTSmode:", 143),
1243                 FIELD1("ISCSICoalescing:", 142),
1244                 FIELD1("Valid:", 141),
1245                 FIELD1("TimerPending:", 140),
1246                 FIELD1("DropRSS:", 139),
1247                 FIELD("PCIeChannel:", 137, 138),
1248                 FIELD1("SEInterruptArmed:", 136),
1249                 FIELD1("CongestionMgtEnable:", 135),
1250                 FIELD1("DCAIngQEnable:", 134),
1251                 FIELD("DCACPUID:", 129, 133),
1252                 FIELD1("UpdateScheduling:", 128),
1253                 FIELD("UpdateDelivery:", 126, 127),
1254                 FIELD1("InterruptSent:", 125),
1255                 FIELD("InterruptIDX:", 114, 124),
1256                 FIELD1("InterruptDestination:", 113),
1257                 FIELD1("InterruptArmed:", 112),
1258                 FIELD("RxIntCounter:", 106, 111),
1259                 FIELD("RxIntCounterThreshold:", 104, 105),
1260                 FIELD1("Generation:", 103),
1261                 { "BaseAddress:", 48, 102, 9, 1 },
1262                 FIELD("PIDX:", 32, 47),
1263                 FIELD("CIDX:", 16, 31),
1264                 { "QueueSize:", 4, 15, 4, 0 },
1265                 { "QueueEntrySize:", 2, 3, 4, 0, 1 },
1266                 FIELD1("QueueEntryOverride:", 1),
1267                 FIELD1("CachePriority:", 0),
1268                 { NULL }
1269         };
1270         static struct field_desc flm[] = {
1271                 FIELD1("NoSnoop:", 79),
1272                 FIELD1("RelaxedOrdering:", 78),
1273                 FIELD1("Valid:", 77),
1274                 FIELD("DCACPUID:", 72, 76),
1275                 FIELD1("DCAFLEn:", 71),
1276                 FIELD("EQid:", 54, 70),
1277                 FIELD("SplitEn:", 52, 53),
1278                 FIELD1("PadEn:", 51),
1279                 FIELD1("PackEn:", 50),
1280                 FIELD1("DBpriority:", 48),
1281                 FIELD("PackOffset:", 16, 47),
1282                 FIELD("CIDX:", 8, 15),
1283                 FIELD("PIDX:", 0, 7),
1284                 { NULL }
1285         };
1286         static struct field_desc conm[] = {
1287                 FIELD1("CngDBPHdr:", 6),
1288                 FIELD1("CngDBPData:", 5),
1289                 FIELD1("CngIMSG:", 4),
1290                 FIELD("CngChMap:", 0, 3),
1291                 { NULL }
1292         };
1293
1294         if (p->mem_id == SGE_CONTEXT_EGRESS)
1295                 show_struct(p->data, 6, (p->data[0] & 2) ? fl : egress);
1296         else if (p->mem_id == SGE_CONTEXT_FLM)
1297                 show_struct(p->data, 3, flm);
1298         else if (p->mem_id == SGE_CONTEXT_INGRESS)
1299                 show_struct(p->data, 5, ingress);
1300         else if (p->mem_id == SGE_CONTEXT_CNM)
1301                 show_struct(p->data, 1, conm);
1302 }
1303
1304 #undef FIELD
1305 #undef FIELD1
1306
1307 static int
1308 get_sge_context(int argc, const char *argv[])
1309 {
1310         int rc;
1311         char *p;
1312         long cid;
1313         struct t4_sge_context cntxt = {0};
1314
1315         if (argc != 2) {
1316                 warnx("sge_context: incorrect number of arguments.");
1317                 return (EINVAL);
1318         }
1319
1320         if (!strcmp(argv[0], "egress"))
1321                 cntxt.mem_id = SGE_CONTEXT_EGRESS;
1322         else if (!strcmp(argv[0], "ingress"))
1323                 cntxt.mem_id = SGE_CONTEXT_INGRESS;
1324         else if (!strcmp(argv[0], "fl"))
1325                 cntxt.mem_id = SGE_CONTEXT_FLM;
1326         else if (!strcmp(argv[0], "cong"))
1327                 cntxt.mem_id = SGE_CONTEXT_CNM;
1328         else {
1329                 warnx("unknown context type \"%s\"; known types are egress, "
1330                     "ingress, fl, and cong.", argv[0]);
1331                 return (EINVAL);
1332         }
1333
1334         p = str_to_number(argv[1], &cid, NULL);
1335         if (*p) {
1336                 warnx("invalid context id \"%s\"", argv[1]);
1337                 return (EINVAL);
1338         }
1339         cntxt.cid = cid;
1340
1341         rc = doit(CHELSIO_T4_GET_SGE_CONTEXT, &cntxt);
1342         if (rc != 0)
1343                 return (rc);
1344
1345         show_sge_context(&cntxt);
1346         return (0);
1347 }
1348
1349 static int
1350 run_cmd(int argc, const char *argv[])
1351 {
1352         int rc = -1;
1353         const char *cmd = argv[0];
1354
1355         /* command */
1356         argc--;
1357         argv++;
1358
1359         if (!strcmp(cmd, "reg") || !strcmp(cmd, "reg32"))
1360                 rc = register_io(argc, argv, 4);
1361         else if (!strcmp(cmd, "reg64"))
1362                 rc = register_io(argc, argv, 8);
1363         else if (!strcmp(cmd, "regdump"))
1364                 rc = dump_regs(argc, argv);
1365         else if (!strcmp(cmd, "filter"))
1366                 rc = filter_cmd(argc, argv);
1367         else if (!strcmp(cmd, "context"))
1368                 rc = get_sge_context(argc, argv);
1369         else {
1370                 rc = EINVAL;
1371                 warnx("invalid command \"%s\"", cmd);
1372         }
1373
1374         return (rc);
1375 }
1376
1377 #define MAX_ARGS 15
1378 static int
1379 run_cmd_loop(void)
1380 {
1381         int i, rc = 0;
1382         char buffer[128], *buf;
1383         const char *args[MAX_ARGS + 1];
1384
1385         /*
1386          * Simple loop: displays a "> " prompt and processes any input as a
1387          * cxgbetool command.  You're supposed to enter only the part after
1388          * "cxgbetool t4nexX".  Use "quit" or "exit" to exit.
1389          */
1390         for (;;) {
1391                 fprintf(stdout, "> ");
1392                 fflush(stdout);
1393                 buf = fgets(buffer, sizeof(buffer), stdin);
1394                 if (buf == NULL) {
1395                         if (ferror(stdin)) {
1396                                 warn("stdin error");
1397                                 rc = errno;     /* errno from fgets */
1398                         }
1399                         break;
1400                 }
1401
1402                 i = 0;
1403                 while ((args[i] = strsep(&buf, " \t\n")) != NULL) {
1404                         if (args[i][0] != 0 && ++i == MAX_ARGS)
1405                                 break;
1406                 }
1407                 args[i] = 0;
1408
1409                 if (i == 0)
1410                         continue;       /* skip empty line */
1411
1412                 if (!strcmp(args[0], "quit") || !strcmp(args[0], "exit"))
1413                         break;
1414
1415                 rc = run_cmd(i, args);
1416         }
1417
1418         /* rc normally comes from the last command (not including quit/exit) */
1419         return (rc);
1420 }
1421
1422 int
1423 main(int argc, const char *argv[])
1424 {
1425         int rc = -1;
1426
1427         progname = argv[0];
1428
1429         if (argc == 2) {
1430                 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
1431                         usage(stdout);
1432                         exit(0);
1433                 }
1434         }
1435
1436         if (argc < 3) {
1437                 usage(stderr);
1438                 exit(EINVAL);
1439         }
1440
1441         nexus = argv[1];
1442
1443         /* progname and nexus */
1444         argc -= 2;
1445         argv += 2;
1446
1447         if (argc == 1 && !strcmp(argv[0], "stdio"))
1448                 rc = run_cmd_loop();
1449         else
1450                 rc = run_cmd(argc, argv);
1451
1452         return (rc);
1453 }