xref: /freebsd/tools/tools/cxgbtool/cxgbtool.c (revision abd87254)
1 /**************************************************************************
2 SPDX-License-Identifier: BSD-3-Clause
3 
4 Copyright (c) 2007-2010, Chelsio Inc.
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10  1. Redistributions of source code must retain the above copyright notice,
11     this list of conditions and the following disclaimer.
12 
13  2. Redistributions in binary form must reproduce the above copyright
14     notice, this list of conditions and the following disclaimer in the
15     documentation and/or other materials provided with the distribution.
16 
17  3. Neither the name of the Chelsio Corporation nor the names of its
18     contributors may be used to endorse or promote products derived from
19     this software without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32 
33 
34 ***************************************************************************/
35 #include <sys/cdefs.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <stdint.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42 #include <err.h>
43 #include <errno.h>
44 #include <inttypes.h>
45 #include <sys/param.h>
46 #include <sys/time.h>
47 #include <sys/ioctl.h>
48 #include <sys/socket.h>
49 
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
52 
53 #include <net/if.h>
54 #include <net/if_types.h>
55 #include <sys/endian.h>
56 
57 #define NMTUS 16
58 #define TCB_SIZE 128
59 #define TCB_WORDS (TCB_SIZE / 4)
60 #define PROTO_SRAM_LINES 128
61 #define PROTO_SRAM_LINE_BITS 132
62 #define PROTO_SRAM_LINE_NIBBLES (132 / 4)
63 #define PROTO_SRAM_SIZE (PROTO_SRAM_LINE_NIBBLES * PROTO_SRAM_LINES / 2)
64 #define PROTO_SRAM_EEPROM_ADDR 4096
65 
66 #include <cxgb_ioctl.h>
67 #include <common/cxgb_regs.h>
68 #include "version.h"
69 
70 struct reg_info {
71         const char *name;
72         uint16_t addr;
73         uint16_t len;
74 };
75 
76 
77 #include "reg_defs.c"
78 #if defined(CONFIG_T3_REGS)
79 # include "reg_defs_t3.c"
80 # include "reg_defs_t3b.c"
81 # include "reg_defs_t3c.c"
82 #endif
83 
84 static const char *progname;
85 
86 static void
87 usage(FILE *fp)
88 {
89 	fprintf(fp, "Usage: %s <interface> [operation]\n", progname);
90 	fprintf(fp,
91 	    	"\tclearstats                          clear MAC statistics\n"
92 		"\tcontext <type> <id>                 show an SGE context\n"
93 		"\tdesc <qset> <queue> <idx> [<cnt>]   dump SGE descriptors\n"
94 		"\tfilter <idx> [<param> <val>] ...    set a filter\n"
95 		"\tfilter <idx> delete|clear           delete a filter\n"
96 		"\tfilter list                         list all filters\n"
97 		"\tioqs                                dump uP IOQs\n"
98 		"\tla                                  dump uP logic analyzer info\n"
99 		"\tloadboot <boot image>               download boot image\n"
100 		"\tloadfw <FW image>                   download firmware\n"
101 		"\tmdio <phy_addr> <mmd_addr>\n"
102 	        "\t     <reg_addr> [<val>]             read/write MDIO register\n"
103 		"\tmemdump cm|tx|rx <addr> <len>       dump a mem range\n"
104 		"\tmeminfo                             show memory info\n"
105 		"\tmtus [<mtu0>...<mtuN>]              read/write MTU table\n"
106 		"\tpktsched port <idx> <min> <max>     set TX port scheduler params\n"
107 		"\tpktsched tunnelq <idx> <max>\n"
108 		"\t         <binding>                  set TX tunnelq scheduler params\n"
109 		"\tpktsched tx <idx>\n"
110 	        "\t         [<param> <val>] ...        set Tx HW scheduler\n"
111 		"\tpm [<TX page spec> <RX page spec>]  read/write PM config\n"
112 		"\tproto                               read proto SRAM\n"
113 		"\tqset                                read qset parameters\n"
114 		"\tqsets                               read # of qsets\n"
115 		"\treg <address>[=<val>]               read/write register\n"
116 		"\tregdump [<module>]                  dump registers\n"
117 		"\ttcamdump <address> <count>          show TCAM contents\n"
118 		"\ttcb <index>                         read TCB\n"
119 		"\ttrace tx|rx|all on|off [not]\n"
120 	        "\t      [<param> <val>[:<mask>]] ...  write trace parameters\n"
121 		);
122 	exit(fp == stderr ? 1 : 0);
123 }
124 
125 static int
126 doit(const char *iff_name, unsigned long cmd, void *data)
127 {
128 	static int fd = 0;
129 
130 	if (fd == 0) {
131 		char buf[64];
132 		snprintf(buf, 64, "/dev/%s", iff_name);
133 
134 		if ((fd = open(buf, O_RDWR)) < 0)
135 			return -1;
136 	}
137 
138 	return ioctl(fd, cmd, data) < 0 ? -1 : 0;
139 }
140 
141 static int
142 get_int_arg(const char *s, uint32_t *valp)
143 {
144 	char *p;
145 
146 	*valp = strtoul(s, &p, 0);
147 	if (*p) {
148 		warnx("bad parameter \"%s\"", s);
149 		return -1;
150 	}
151 	return 0;
152 }
153 
154 static uint32_t
155 read_reg(const char *iff_name, uint32_t addr)
156 {
157 	struct ch_reg reg;
158 
159 	reg.addr = addr;
160 
161 	if (doit(iff_name, CHELSIO_GETREG, &reg) < 0)
162 		err(1, "register read");
163 	return reg.val;
164 }
165 
166 static void
167 write_reg(const char *iff_name, uint32_t addr, uint32_t val)
168 {
169 	struct ch_reg ch_reg;
170 
171 	ch_reg.addr = addr;
172 	ch_reg.val = val;
173 
174 	if (doit(iff_name, CHELSIO_SETREG, &ch_reg) < 0)
175 		err(1, "register write");
176 }
177 
178 static int
179 register_io(int argc, char *argv[], int start_arg,
180 		       const char *iff_name)
181 {
182 	char *p;
183 	uint32_t addr, val = 0, w = 0;
184 
185 	if (argc != start_arg + 1) return -1;
186 
187 	addr = strtoul(argv[start_arg], &p, 0);
188 	if (p == argv[start_arg]) return -1;
189 	if (*p == '=' && p[1]) {
190 		val = strtoul(p + 1, &p, 0);
191 		w = 1;
192 	}
193 	if (*p) {
194 		warnx("bad parameter \"%s\"", argv[start_arg]);
195 		return -1;
196 	}
197 
198 	if (w)
199 		write_reg(iff_name, addr, val);
200 	else {
201 		val = read_reg(iff_name, addr);
202 		printf("%#x [%u]\n", val, val);
203 	}
204 	return 0;
205 }
206 
207 static int
208 mdio_io(int argc, char *argv[], int start_arg, const char *iff_name)
209 {
210         struct ch_mii_data p;
211         unsigned int cmd, phy_addr, reg, mmd, val;
212 
213         if (argc == start_arg + 3)
214                 cmd = CHELSIO_GET_MIIREG;
215         else if (argc == start_arg + 4)
216                 cmd = CHELSIO_SET_MIIREG;
217         else
218                 return -1;
219 
220         if (get_int_arg(argv[start_arg], &phy_addr) ||
221             get_int_arg(argv[start_arg + 1], &mmd) ||
222             get_int_arg(argv[start_arg + 2], &reg) ||
223             (cmd == CHELSIO_SET_MIIREG && get_int_arg(argv[start_arg + 3], &val)))
224                 return -1;
225 
226         p.phy_id  = phy_addr | (mmd << 8);
227         p.reg_num = reg;
228         p.val_in  = val;
229 
230         if (doit(iff_name, cmd, &p) < 0)
231                 err(1, "MDIO %s", cmd == CHELSIO_GET_MIIREG ? "read" : "write");
232         if (cmd == CHELSIO_GET_MIIREG)
233                 printf("%#x [%u]\n", p.val_out, p.val_out);
234         return 0;
235 }
236 
237 static inline
238 uint32_t xtract(uint32_t val, int shift, int len)
239 {
240 	return (val >> shift) & ((1 << len) - 1);
241 }
242 
243 static int
244 dump_block_regs(const struct reg_info *reg_array, uint32_t *regs)
245 {
246 	uint32_t reg_val = 0; // silence compiler warning
247 
248 	for ( ; reg_array->name; ++reg_array)
249 		if (!reg_array->len) {
250 			reg_val = regs[reg_array->addr / 4];
251 			printf("[%#5x] %-40s %#-10x [%u]\n", reg_array->addr,
252 			       reg_array->name, reg_val, reg_val);
253 		} else {
254 			uint32_t v = xtract(reg_val, reg_array->addr,
255 					    reg_array->len);
256 
257 			printf("        %-40s %#-10x [%u]\n", reg_array->name,
258 			       v, v);
259 		}
260 	return 1;
261 }
262 
263 static int
264 dump_regs_t2(int argc, char *argv[], int start_arg, uint32_t *regs)
265 {
266 	int match = 0;
267 	char *block_name = NULL;
268 
269 	if (argc == start_arg + 1)
270 		block_name = argv[start_arg];
271 	else if (argc != start_arg)
272 		return -1;
273 
274 	if (!block_name || !strcmp(block_name, "sge"))
275 		match += dump_block_regs(sge_regs, regs);
276 	if (!block_name || !strcmp(block_name, "mc3"))
277 		match += dump_block_regs(mc3_regs, regs);
278 	if (!block_name || !strcmp(block_name, "mc4"))
279 		match += dump_block_regs(mc4_regs, regs);
280 	if (!block_name || !strcmp(block_name, "tpi"))
281 		match += dump_block_regs(tpi_regs, regs);
282 	if (!block_name || !strcmp(block_name, "tp"))
283 		match += dump_block_regs(tp_regs, regs);
284 	if (!block_name || !strcmp(block_name, "rat"))
285 		match += dump_block_regs(rat_regs, regs);
286 	if (!block_name || !strcmp(block_name, "cspi"))
287 		match += dump_block_regs(cspi_regs, regs);
288 	if (!block_name || !strcmp(block_name, "espi"))
289 		match += dump_block_regs(espi_regs, regs);
290 	if (!block_name || !strcmp(block_name, "ulp"))
291 		match += dump_block_regs(ulp_regs, regs);
292 	if (!block_name || !strcmp(block_name, "pl"))
293 		match += dump_block_regs(pl_regs, regs);
294 	if (!block_name || !strcmp(block_name, "mc5"))
295 		match += dump_block_regs(mc5_regs, regs);
296 	if (!match)
297 		errx(1, "unknown block \"%s\"", block_name);
298 	return 0;
299 }
300 
301 #if defined(CONFIG_T3_REGS)
302 static int
303 dump_regs_t3(int argc, char *argv[], int start_arg, uint32_t *regs, int is_pcie)
304 {
305 	int match = 0;
306 	char *block_name = NULL;
307 
308 	if (argc == start_arg + 1)
309 		block_name = argv[start_arg];
310 	else if (argc != start_arg)
311 		return -1;
312 
313 	if (!block_name || !strcmp(block_name, "sge"))
314 		match += dump_block_regs(sge3_regs, regs);
315 	if (!block_name || !strcmp(block_name, "pci"))
316 		match += dump_block_regs(is_pcie ? pcie0_regs : pcix1_regs,
317 					 regs);
318 	if (!block_name || !strcmp(block_name, "t3dbg"))
319 		match += dump_block_regs(t3dbg_regs, regs);
320 	if (!block_name || !strcmp(block_name, "pmrx"))
321 		match += dump_block_regs(mc7_pmrx_regs, regs);
322 	if (!block_name || !strcmp(block_name, "pmtx"))
323 		match += dump_block_regs(mc7_pmtx_regs, regs);
324 	if (!block_name || !strcmp(block_name, "cm"))
325 		match += dump_block_regs(mc7_cm_regs, regs);
326 	if (!block_name || !strcmp(block_name, "cim"))
327 		match += dump_block_regs(cim_regs, regs);
328 	if (!block_name || !strcmp(block_name, "tp"))
329 		match += dump_block_regs(tp1_regs, regs);
330 	if (!block_name || !strcmp(block_name, "ulp_rx"))
331 		match += dump_block_regs(ulp2_rx_regs, regs);
332 	if (!block_name || !strcmp(block_name, "ulp_tx"))
333 		match += dump_block_regs(ulp2_tx_regs, regs);
334 	if (!block_name || !strcmp(block_name, "pmrx"))
335 		match += dump_block_regs(pm1_rx_regs, regs);
336 	if (!block_name || !strcmp(block_name, "pmtx"))
337 		match += dump_block_regs(pm1_tx_regs, regs);
338 	if (!block_name || !strcmp(block_name, "mps"))
339 		match += dump_block_regs(mps0_regs, regs);
340 	if (!block_name || !strcmp(block_name, "cplsw"))
341 		match += dump_block_regs(cpl_switch_regs, regs);
342 	if (!block_name || !strcmp(block_name, "smb"))
343 		match += dump_block_regs(smb0_regs, regs);
344 	if (!block_name || !strcmp(block_name, "i2c"))
345 		match += dump_block_regs(i2cm0_regs, regs);
346 	if (!block_name || !strcmp(block_name, "mi1"))
347 		match += dump_block_regs(mi1_regs, regs);
348 	if (!block_name || !strcmp(block_name, "sf"))
349 		match += dump_block_regs(sf1_regs, regs);
350 	if (!block_name || !strcmp(block_name, "pl"))
351 		match += dump_block_regs(pl3_regs, regs);
352 	if (!block_name || !strcmp(block_name, "mc5"))
353 		match += dump_block_regs(mc5a_regs, regs);
354 	if (!block_name || !strcmp(block_name, "xgmac0"))
355 		match += dump_block_regs(xgmac0_0_regs, regs);
356 	if (!block_name || !strcmp(block_name, "xgmac1"))
357 		match += dump_block_regs(xgmac0_1_regs, regs);
358 	if (!match)
359 		errx(1, "unknown block \"%s\"", block_name);
360 	return 0;
361 }
362 
363 static int
364 dump_regs_t3b(int argc, char *argv[], int start_arg, uint32_t *regs,
365     int is_pcie)
366 {
367 	int match = 0;
368 	char *block_name = NULL;
369 
370 	if (argc == start_arg + 1)
371 		block_name = argv[start_arg];
372 	else if (argc != start_arg)
373 		return -1;
374 
375 	if (!block_name || !strcmp(block_name, "sge"))
376 		match += dump_block_regs(t3b_sge3_regs, regs);
377 	if (!block_name || !strcmp(block_name, "pci"))
378 		match += dump_block_regs(is_pcie ? t3b_pcie0_regs :
379 						   t3b_pcix1_regs, regs);
380 	if (!block_name || !strcmp(block_name, "t3dbg"))
381 		match += dump_block_regs(t3b_t3dbg_regs, regs);
382 	if (!block_name || !strcmp(block_name, "pmrx"))
383 		match += dump_block_regs(t3b_mc7_pmrx_regs, regs);
384 	if (!block_name || !strcmp(block_name, "pmtx"))
385 		match += dump_block_regs(t3b_mc7_pmtx_regs, regs);
386 	if (!block_name || !strcmp(block_name, "cm"))
387 		match += dump_block_regs(t3b_mc7_cm_regs, regs);
388 	if (!block_name || !strcmp(block_name, "cim"))
389 		match += dump_block_regs(t3b_cim_regs, regs);
390 	if (!block_name || !strcmp(block_name, "tp"))
391 		match += dump_block_regs(t3b_tp1_regs, regs);
392 	if (!block_name || !strcmp(block_name, "ulp_rx"))
393 		match += dump_block_regs(t3b_ulp2_rx_regs, regs);
394 	if (!block_name || !strcmp(block_name, "ulp_tx"))
395 		match += dump_block_regs(t3b_ulp2_tx_regs, regs);
396 	if (!block_name || !strcmp(block_name, "pmrx"))
397 		match += dump_block_regs(t3b_pm1_rx_regs, regs);
398 	if (!block_name || !strcmp(block_name, "pmtx"))
399 		match += dump_block_regs(t3b_pm1_tx_regs, regs);
400 	if (!block_name || !strcmp(block_name, "mps"))
401 		match += dump_block_regs(t3b_mps0_regs, regs);
402 	if (!block_name || !strcmp(block_name, "cplsw"))
403 		match += dump_block_regs(t3b_cpl_switch_regs, regs);
404 	if (!block_name || !strcmp(block_name, "smb"))
405 		match += dump_block_regs(t3b_smb0_regs, regs);
406 	if (!block_name || !strcmp(block_name, "i2c"))
407 		match += dump_block_regs(t3b_i2cm0_regs, regs);
408 	if (!block_name || !strcmp(block_name, "mi1"))
409 		match += dump_block_regs(t3b_mi1_regs, regs);
410 	if (!block_name || !strcmp(block_name, "sf"))
411 		match += dump_block_regs(t3b_sf1_regs, regs);
412 	if (!block_name || !strcmp(block_name, "pl"))
413 		match += dump_block_regs(t3b_pl3_regs, regs);
414 	if (!block_name || !strcmp(block_name, "mc5"))
415 		match += dump_block_regs(t3b_mc5a_regs, regs);
416 	if (!block_name || !strcmp(block_name, "xgmac0"))
417 		match += dump_block_regs(t3b_xgmac0_0_regs, regs);
418 	if (!block_name || !strcmp(block_name, "xgmac1"))
419 		match += dump_block_regs(t3b_xgmac0_1_regs, regs);
420 	if (!match)
421 		errx(1, "unknown block \"%s\"", block_name);
422 	return 0;
423 }
424 
425 static int
426 dump_regs_t3c(int argc, char *argv[], int start_arg, uint32_t *regs,
427     int is_pcie)
428 {
429 	int match = 0;
430 	char *block_name = NULL;
431 
432 	if (argc == start_arg + 1)
433 		block_name = argv[start_arg];
434 	else if (argc != start_arg)
435 		return -1;
436 
437 	if (!block_name || !strcmp(block_name, "sge"))
438 		match += dump_block_regs(t3c_sge3_regs, regs);
439 	if (!block_name || !strcmp(block_name, "pci"))
440 		match += dump_block_regs(is_pcie ? t3c_pcie0_regs :
441 						   t3c_pcix1_regs, regs);
442 	if (!block_name || !strcmp(block_name, "t3dbg"))
443 		match += dump_block_regs(t3c_t3dbg_regs, regs);
444 	if (!block_name || !strcmp(block_name, "pmrx"))
445 		match += dump_block_regs(t3c_mc7_pmrx_regs, regs);
446 	if (!block_name || !strcmp(block_name, "pmtx"))
447 		match += dump_block_regs(t3c_mc7_pmtx_regs, regs);
448 	if (!block_name || !strcmp(block_name, "cm"))
449 		match += dump_block_regs(t3c_mc7_cm_regs, regs);
450 	if (!block_name || !strcmp(block_name, "cim"))
451 		match += dump_block_regs(t3c_cim_regs, regs);
452 	if (!block_name || !strcmp(block_name, "tp"))
453 		match += dump_block_regs(t3c_tp1_regs, regs);
454 	if (!block_name || !strcmp(block_name, "ulp_rx"))
455 		match += dump_block_regs(t3c_ulp2_rx_regs, regs);
456 	if (!block_name || !strcmp(block_name, "ulp_tx"))
457 		match += dump_block_regs(t3c_ulp2_tx_regs, regs);
458 	if (!block_name || !strcmp(block_name, "pmrx"))
459 		match += dump_block_regs(t3c_pm1_rx_regs, regs);
460 	if (!block_name || !strcmp(block_name, "pmtx"))
461 		match += dump_block_regs(t3c_pm1_tx_regs, regs);
462 	if (!block_name || !strcmp(block_name, "mps"))
463 		match += dump_block_regs(t3c_mps0_regs, regs);
464 	if (!block_name || !strcmp(block_name, "cplsw"))
465 		match += dump_block_regs(t3c_cpl_switch_regs, regs);
466 	if (!block_name || !strcmp(block_name, "smb"))
467 		match += dump_block_regs(t3c_smb0_regs, regs);
468 	if (!block_name || !strcmp(block_name, "i2c"))
469 		match += dump_block_regs(t3c_i2cm0_regs, regs);
470 	if (!block_name || !strcmp(block_name, "mi1"))
471 		match += dump_block_regs(t3c_mi1_regs, regs);
472 	if (!block_name || !strcmp(block_name, "sf"))
473 		match += dump_block_regs(t3c_sf1_regs, regs);
474 	if (!block_name || !strcmp(block_name, "pl"))
475 		match += dump_block_regs(t3c_pl3_regs, regs);
476 	if (!block_name || !strcmp(block_name, "mc5"))
477 		match += dump_block_regs(t3c_mc5a_regs, regs);
478 	if (!block_name || !strcmp(block_name, "xgmac0"))
479 		match += dump_block_regs(t3c_xgmac0_0_regs, regs);
480 	if (!block_name || !strcmp(block_name, "xgmac1"))
481 		match += dump_block_regs(t3c_xgmac0_1_regs, regs);
482 	if (!match)
483 		errx(1, "unknown block \"%s\"", block_name);
484 	return 0;
485 }
486 #endif
487 
488 static int
489 dump_regs(int argc, char *argv[], int start_arg, const char *iff_name)
490 {
491 	int vers, revision, is_pcie;
492 	struct ch_ifconf_regs regs;
493 
494 	regs.len = REGDUMP_SIZE;
495 
496 	/* XXX: This is never freed.  Looks like we don't care. */
497 	if ((regs.data = malloc(regs.len)) == NULL)
498 		err(1, "can't malloc");
499 
500 	if (doit(iff_name, CHELSIO_IFCONF_GETREGS, &regs))
501 		err(1, "can't read registers");
502 
503 	vers = regs.version & 0x3ff;
504 	revision = (regs.version >> 10) & 0x3f;
505 	is_pcie = (regs.version & 0x80000000) != 0;
506 
507 	if (vers <= 2)
508 		return dump_regs_t2(argc, argv, start_arg, (uint32_t *)regs.data);
509 #if defined(CONFIG_T3_REGS)
510 	if (vers == 3) {
511 		if (revision == 0)
512 			return dump_regs_t3(argc, argv, start_arg,
513 					    (uint32_t *)regs.data, is_pcie);
514 		if (revision == 2 || revision == 3)
515 			return dump_regs_t3b(argc, argv, start_arg,
516 					     (uint32_t *)regs.data, is_pcie);
517 		if (revision == 4)
518 			return dump_regs_t3c(argc, argv, start_arg,
519 			    		     (uint32_t *)regs.data, is_pcie);
520 	}
521 #endif
522 	errx(1, "unknown card type %d.%d", vers, revision);
523 	return 0;
524 }
525 
526 static int
527 t3_meminfo(const uint32_t *regs)
528 {
529 	enum {
530 		SG_EGR_CNTX_BADDR       = 0x58,
531 		SG_CQ_CONTEXT_BADDR     = 0x6c,
532 		CIM_SDRAM_BASE_ADDR     = 0x28c,
533 		CIM_SDRAM_ADDR_SIZE     = 0x290,
534 		TP_CMM_MM_BASE          = 0x314,
535 		TP_CMM_TIMER_BASE       = 0x318,
536 		TP_CMM_MM_RX_FLST_BASE  = 0x460,
537 		TP_CMM_MM_TX_FLST_BASE  = 0x464,
538 		TP_CMM_MM_PS_FLST_BASE  = 0x468,
539 		ULPRX_ISCSI_LLIMIT      = 0x50c,
540 		ULPRX_ISCSI_ULIMIT      = 0x510,
541 		ULPRX_TDDP_LLIMIT       = 0x51c,
542 		ULPRX_TDDP_ULIMIT       = 0x520,
543 		ULPRX_STAG_LLIMIT       = 0x52c,
544 		ULPRX_STAG_ULIMIT       = 0x530,
545 		ULPRX_RQ_LLIMIT         = 0x534,
546 		ULPRX_RQ_ULIMIT         = 0x538,
547 		ULPRX_PBL_LLIMIT        = 0x53c,
548 		ULPRX_PBL_ULIMIT        = 0x540,
549 	};
550 
551 	unsigned int egr_cntxt = regs[SG_EGR_CNTX_BADDR / 4],
552 		     cq_cntxt = regs[SG_CQ_CONTEXT_BADDR / 4],
553 		     timers = regs[TP_CMM_TIMER_BASE / 4] & 0xfffffff,
554 		     pstructs = regs[TP_CMM_MM_BASE / 4],
555 		     pstruct_fl = regs[TP_CMM_MM_PS_FLST_BASE / 4],
556 		     rx_fl = regs[TP_CMM_MM_RX_FLST_BASE / 4],
557 		     tx_fl = regs[TP_CMM_MM_TX_FLST_BASE / 4],
558 		     cim_base = regs[CIM_SDRAM_BASE_ADDR / 4],
559 		     cim_size = regs[CIM_SDRAM_ADDR_SIZE / 4];
560 	unsigned int iscsi_ll = regs[ULPRX_ISCSI_LLIMIT / 4],
561 		     iscsi_ul = regs[ULPRX_ISCSI_ULIMIT / 4],
562 		     tddp_ll = regs[ULPRX_TDDP_LLIMIT / 4],
563 		     tddp_ul = regs[ULPRX_TDDP_ULIMIT / 4],
564 		     stag_ll = regs[ULPRX_STAG_LLIMIT / 4],
565 		     stag_ul = regs[ULPRX_STAG_ULIMIT / 4],
566 		     rq_ll = regs[ULPRX_RQ_LLIMIT / 4],
567 		     rq_ul = regs[ULPRX_RQ_ULIMIT / 4],
568 		     pbl_ll = regs[ULPRX_PBL_LLIMIT / 4],
569 		     pbl_ul = regs[ULPRX_PBL_ULIMIT / 4];
570 
571 	printf("CM memory map:\n");
572 	printf("  TCB region:      0x%08x - 0x%08x [%u]\n", 0, egr_cntxt - 1,
573 	       egr_cntxt);
574 	printf("  Egress contexts: 0x%08x - 0x%08x [%u]\n", egr_cntxt,
575 	       cq_cntxt - 1, cq_cntxt - egr_cntxt);
576 	printf("  CQ contexts:     0x%08x - 0x%08x [%u]\n", cq_cntxt,
577 	       timers - 1, timers - cq_cntxt);
578 	printf("  Timers:          0x%08x - 0x%08x [%u]\n", timers,
579 	       pstructs - 1, pstructs - timers);
580 	printf("  Pstructs:        0x%08x - 0x%08x [%u]\n", pstructs,
581 	       pstruct_fl - 1, pstruct_fl - pstructs);
582 	printf("  Pstruct FL:      0x%08x - 0x%08x [%u]\n", pstruct_fl,
583 	       rx_fl - 1, rx_fl - pstruct_fl);
584 	printf("  Rx FL:           0x%08x - 0x%08x [%u]\n", rx_fl, tx_fl - 1,
585 	       tx_fl - rx_fl);
586 	printf("  Tx FL:           0x%08x - 0x%08x [%u]\n", tx_fl, cim_base - 1,
587 	       cim_base - tx_fl);
588 	printf("  uP RAM:          0x%08x - 0x%08x [%u]\n", cim_base,
589 	       cim_base + cim_size - 1, cim_size);
590 
591 	printf("\nPMRX memory map:\n");
592 	printf("  iSCSI region:    0x%08x - 0x%08x [%u]\n", iscsi_ll, iscsi_ul,
593 	       iscsi_ul - iscsi_ll + 1);
594 	printf("  TCP DDP region:  0x%08x - 0x%08x [%u]\n", tddp_ll, tddp_ul,
595 	       tddp_ul - tddp_ll + 1);
596 	printf("  TPT region:      0x%08x - 0x%08x [%u]\n", stag_ll, stag_ul,
597 	       stag_ul - stag_ll + 1);
598 	printf("  RQ region:       0x%08x - 0x%08x [%u]\n", rq_ll, rq_ul,
599 	       rq_ul - rq_ll + 1);
600 	printf("  PBL region:      0x%08x - 0x%08x [%u]\n", pbl_ll, pbl_ul,
601 	       pbl_ul - pbl_ll + 1);
602 	return 0;
603 }
604 
605 static int
606 meminfo(int argc, char *argv[], int start_arg, const char *iff_name)
607 {
608 	int vers;
609 	struct ch_ifconf_regs regs;
610 
611 	(void) argc;
612 	(void) argv;
613 	(void) start_arg;
614 
615 	regs.len = REGDUMP_SIZE;
616 	if ((regs.data = malloc(regs.len)) == NULL)
617 		err(1, "can't malloc");
618 
619 	if (doit(iff_name, CHELSIO_IFCONF_GETREGS, &regs))
620 		err(1, "can't read registers");
621 
622 	vers = regs.version & 0x3ff;
623 	if (vers == 3)
624 		return t3_meminfo((uint32_t *)regs.data);
625 
626 	errx(1, "unknown card type %d", vers);
627 	return 0;
628 }
629 
630 static int
631 mtu_tab_op(int argc, char *argv[], int start_arg, const char *iff_name)
632 {
633 	struct ch_mtus m;
634 	unsigned int i;
635 
636 	if (argc == start_arg) {
637 		if (doit(iff_name, CHELSIO_GETMTUTAB, &m) < 0)
638 			err(1, "get MTU table");
639 		for (i = 0; i < m.nmtus; ++i)
640 			printf("%u ", m.mtus[i]);
641 		printf("\n");
642 	} else if (argc <= start_arg + NMTUS) {
643 		m.nmtus = argc - start_arg;
644 
645 		for (i = 0; i < m.nmtus; ++i) {
646 			char *p;
647 			unsigned long mt = strtoul(argv[start_arg + i], &p, 0);
648 
649 			if (*p || mt > 9600) {
650 				warnx("bad parameter \"%s\"",
651 				      argv[start_arg + i]);
652 				return -1;
653 			}
654 			if (i && mt < m.mtus[i - 1])
655 				errx(1, "MTUs must be in ascending order");
656 			m.mtus[i] = mt;
657 		}
658 		if (doit(iff_name, CHELSIO_SETMTUTAB, &m) < 0)
659 			err(1, "set MTU table");
660 	} else
661 		return -1;
662 
663 	return 0;
664 }
665 
666 #ifdef CHELSIO_INTERNAL
667 static void
668 show_egress_cntxt(uint32_t data[])
669 {
670 	printf("credits:      %u\n", data[0] & 0x7fff);
671 	printf("GTS:          %u\n", (data[0] >> 15) & 1);
672 	printf("index:        %u\n", data[0] >> 16);
673 	printf("queue size:   %u\n", data[1] & 0xffff);
674 	printf("base address: 0x%" PRIx64 "\n",
675 	       ((data[1] >> 16) | ((uint64_t)data[2] << 16) |
676 	       (((uint64_t)data[3] & 0xf) << 48)) << 12);
677 	printf("rsp queue #:  %u\n", (data[3] >> 4) & 7);
678 	printf("cmd queue #:  %u\n", (data[3] >> 7) & 1);
679 	printf("TUN:          %u\n", (data[3] >> 8) & 1);
680 	printf("TOE:          %u\n", (data[3] >> 9) & 1);
681 	printf("generation:   %u\n", (data[3] >> 10) & 1);
682 	printf("uP token:     %u\n", (data[3] >> 11) & 0xfffff);
683 	printf("valid:        %u\n", (data[3] >> 31) & 1);
684 }
685 
686 static void
687 show_fl_cntxt(uint32_t data[])
688 {
689 	printf("base address: 0x%" PRIx64 "\n",
690 	       ((uint64_t)data[0] | ((uint64_t)data[1] & 0xfffff) << 32) << 12);
691 	printf("index:        %u\n", (data[1] >> 20) | ((data[2] & 0xf) << 12));
692 	printf("queue size:   %u\n", (data[2] >> 4) & 0xffff);
693 	printf("generation:   %u\n", (data[2] >> 20) & 1);
694 	printf("entry size:   %u\n",
695 	       (data[2] >> 21) | (data[3] & 0x1fffff) << 11);
696 	printf("congest thr:  %u\n", (data[3] >> 21) & 0x3ff);
697 	printf("GTS:          %u\n", (data[3] >> 31) & 1);
698 }
699 
700 static void
701 show_response_cntxt(uint32_t data[])
702 {
703 	printf("index:        %u\n", data[0] & 0xffff);
704 	printf("size:         %u\n", data[0] >> 16);
705 	printf("base address: 0x%" PRIx64 "\n",
706 	       ((uint64_t)data[1] | ((uint64_t)data[2] & 0xfffff) << 32) << 12);
707 	printf("MSI-X/RspQ:   %u\n", (data[2] >> 20) & 0x3f);
708 	printf("intr enable:  %u\n", (data[2] >> 26) & 1);
709 	printf("intr armed:   %u\n", (data[2] >> 27) & 1);
710 	printf("generation:   %u\n", (data[2] >> 28) & 1);
711 	printf("CQ mode:      %u\n", (data[2] >> 31) & 1);
712 	printf("FL threshold: %u\n", data[3]);
713 }
714 
715 static void
716 show_cq_cntxt(uint32_t data[])
717 {
718 	printf("index:            %u\n", data[0] & 0xffff);
719 	printf("size:             %u\n", data[0] >> 16);
720 	printf("base address:     0x%" PRIx64 "\n",
721 	       ((uint64_t)data[1] | ((uint64_t)data[2] & 0xfffff) << 32) << 12);
722 	printf("rsp queue #:      %u\n", (data[2] >> 20) & 0x3f);
723 	printf("AN:               %u\n", (data[2] >> 26) & 1);
724 	printf("armed:            %u\n", (data[2] >> 27) & 1);
725 	printf("ANS:              %u\n", (data[2] >> 28) & 1);
726 	printf("generation:       %u\n", (data[2] >> 29) & 1);
727 	printf("overflow mode:    %u\n", (data[2] >> 31) & 1);
728 	printf("credits:          %u\n", data[3] & 0xffff);
729 	printf("credit threshold: %u\n", data[3] >> 16);
730 }
731 
732 static int
733 get_sge_context(int argc, char *argv[], int start_arg, const char *iff_name)
734 {
735 	struct ch_cntxt ctx;
736 
737 	if (argc != start_arg + 2) return -1;
738 
739 	if (!strcmp(argv[start_arg], "egress"))
740 		ctx.cntxt_type = CNTXT_TYPE_EGRESS;
741 	else if (!strcmp(argv[start_arg], "fl"))
742 		ctx.cntxt_type = CNTXT_TYPE_FL;
743 	else if (!strcmp(argv[start_arg], "response"))
744 		ctx.cntxt_type = CNTXT_TYPE_RSP;
745 	else if (!strcmp(argv[start_arg], "cq"))
746 		ctx.cntxt_type = CNTXT_TYPE_CQ;
747 	else {
748 		warnx("unknown context type \"%s\"; known types are egress, "
749 		      "fl, cq, and response", argv[start_arg]);
750 		return -1;
751 	}
752 
753 	if (get_int_arg(argv[start_arg + 1], &ctx.cntxt_id))
754 		return -1;
755 
756 	if (doit(iff_name, CHELSIO_GET_SGE_CONTEXT, &ctx) < 0)
757 		err(1, "get SGE context");
758 
759 	if (!strcmp(argv[start_arg], "egress"))
760 		show_egress_cntxt(ctx.data);
761 	else if (!strcmp(argv[start_arg], "fl"))
762 		show_fl_cntxt(ctx.data);
763 	else if (!strcmp(argv[start_arg], "response"))
764 		show_response_cntxt(ctx.data);
765 	else if (!strcmp(argv[start_arg], "cq"))
766 		show_cq_cntxt(ctx.data);
767 	return 0;
768 }
769 
770 #define ntohll(x) be64toh((x))
771 
772 static int
773 get_sge_desc(int argc, char *argv[], int start_arg, const char *iff_name)
774 {
775 	uint64_t *p, wr_hdr;
776 	unsigned int n = 1, qset, qnum;
777 	struct ch_desc desc;
778 
779 	if (argc != start_arg + 3 && argc != start_arg + 4)
780 		return -1;
781 
782 	if (get_int_arg(argv[start_arg], &qset) ||
783 	    get_int_arg(argv[start_arg + 1], &qnum) ||
784 	    get_int_arg(argv[start_arg + 2], &desc.idx))
785 		return -1;
786 
787 	if (argc == start_arg + 4 && get_int_arg(argv[start_arg + 3], &n))
788 		return -1;
789 
790 	if (qnum > 5)
791 		errx(1, "invalid queue number %d, range is 0..5", qnum);
792 
793 	desc.queue_num = qset * 6 + qnum;
794 
795 	for (; n--; desc.idx++) {
796 		if (doit(iff_name, CHELSIO_GET_SGE_DESC, &desc) < 0)
797 			err(1, "get SGE descriptor");
798 
799 		p = (uint64_t *)desc.data;
800 		wr_hdr = ntohll(*p);
801 		printf("Descriptor %u: cmd %u, TID %u, %s%s%s%s%u flits\n",
802 		       desc.idx, (unsigned int)(wr_hdr >> 56),
803 		       ((unsigned int)wr_hdr >> 8) & 0xfffff,
804 		       ((wr_hdr >> 55) & 1) ? "SOP, " : "",
805 		       ((wr_hdr >> 54) & 1) ? "EOP, " : "",
806 		       ((wr_hdr >> 53) & 1) ? "COMPL, " : "",
807 		       ((wr_hdr >> 52) & 1) ? "SGL, " : "",
808 		       (unsigned int)wr_hdr & 0xff);
809 
810 		for (; desc.size; p++, desc.size -= sizeof(uint64_t))
811 			printf("%016" PRIx64 "%c", ntohll(*p),
812 			    desc.size % 32 == 8 ? '\n' : ' ');
813 	}
814 	return 0;
815 }
816 #endif
817 
818 static int
819 get_tcb2(int argc, char *argv[], int start_arg, const char *iff_name)
820 {
821 	uint64_t *d;
822 	unsigned int i;
823 	unsigned int tcb_idx;
824 	struct ch_mem_range mr;
825 
826 	if (argc != start_arg + 1)
827 		return -1;
828 
829 	if (get_int_arg(argv[start_arg], &tcb_idx))
830 		return -1;
831 
832 	mr.buf = calloc(1, TCB_SIZE);
833 	if (!mr.buf)
834 		err(1, "get TCB");
835 
836 	mr.mem_id = MEM_CM;
837 	mr.addr   = tcb_idx * TCB_SIZE;
838 	mr.len    = TCB_SIZE;
839 
840 	if (doit(iff_name, CHELSIO_GET_MEM, &mr) < 0)
841 		err(1, "get TCB");
842 
843 	for (d = (uint64_t *)mr.buf, i = 0; i < TCB_SIZE / 32; i++) {
844 		printf("%2u:", i);
845 		printf(" %08x %08x %08x %08x", (uint32_t)d[1],
846 		       (uint32_t)(d[1] >> 32), (uint32_t)d[0],
847 		       (uint32_t)(d[0] >> 32));
848 		d += 2;
849 		printf(" %08x %08x %08x %08x\n", (uint32_t)d[1],
850 		       (uint32_t)(d[1] >> 32), (uint32_t)d[0],
851 		       (uint32_t)(d[0] >> 32));
852 		d += 2;
853 	}
854 	free(mr.buf);
855 	return 0;
856 }
857 
858 static int
859 get_pm_page_spec(const char *s, unsigned int *page_size,
860     unsigned int *num_pages)
861 {
862 	char *p;
863 	unsigned long val;
864 
865 	val = strtoul(s, &p, 0);
866 	if (p == s) return -1;
867 	if (*p == 'x' && p[1]) {
868 		*num_pages = val;
869 		*page_size = strtoul(p + 1, &p, 0);
870 	} else {
871 		*num_pages = -1;
872 		*page_size = val;
873 	}
874 	*page_size <<= 10;     // KB -> bytes
875 	return *p;
876 }
877 
878 static int
879 conf_pm(int argc, char *argv[], int start_arg, const char *iff_name)
880 {
881 	struct ch_pm pm;
882 
883 	if (argc == start_arg) {
884 		if (doit(iff_name, CHELSIO_GET_PM, &pm) < 0)
885 			err(1, "read pm config");
886 		printf("%ux%uKB TX pages, %ux%uKB RX pages, %uKB total memory\n",
887 		       pm.tx_num_pg, pm.tx_pg_sz >> 10, pm.rx_num_pg,
888 		       pm.rx_pg_sz >> 10, pm.pm_total >> 10);
889 		return 0;
890 	}
891 
892 	if (argc != start_arg + 2) return -1;
893 
894 	if (get_pm_page_spec(argv[start_arg], &pm.tx_pg_sz, &pm.tx_num_pg)) {
895 		warnx("bad parameter \"%s\"", argv[start_arg]);
896 		return -1;
897 	}
898 	if (get_pm_page_spec(argv[start_arg + 1], &pm.rx_pg_sz,
899 			     &pm.rx_num_pg)) {
900 		warnx("bad parameter \"%s\"", argv[start_arg + 1]);
901 		return -1;
902 	}
903 	if (doit(iff_name, CHELSIO_SET_PM, &pm) < 0)
904 		err(1, "pm config");
905 	return 0;
906 }
907 
908 #ifdef	CHELSIO_INTERNAL
909 static int
910 dump_tcam(int argc, char *argv[], int start_arg, const char *iff_name)
911 {
912 	unsigned int nwords;
913 	struct ch_tcam_word op;
914 
915 	if (argc != start_arg + 2) return -1;
916 
917 	if (get_int_arg(argv[start_arg], &op.addr) ||
918 	    get_int_arg(argv[start_arg + 1], &nwords))
919 		return -1;
920 
921 	while (nwords--) {
922 		if (doit(iff_name, CHELSIO_READ_TCAM_WORD, &op) < 0)
923 			err(1, "tcam dump");
924 
925 		printf("0x%08x: 0x%02x 0x%08x 0x%08x\n", op.addr,
926 		       op.buf[0] & 0xff, op.buf[1], op.buf[2]);
927 		op.addr++;
928 	}
929 	return 0;
930 }
931 
932 static void
933 hexdump_8b(unsigned int start, uint64_t *data, unsigned int len)
934 {
935 	int i;
936 
937 	while (len) {
938 		printf("0x%08x:", start);
939 		for (i = 0; i < 4 && len; ++i, --len)
940 			printf(" %016llx", (unsigned long long)*data++);
941 		printf("\n");
942 		start += 32;
943 	}
944 }
945 
946 static int
947 dump_mc7(int argc, char *argv[], int start_arg, const char *iff_name)
948 {
949 	struct ch_mem_range mem;
950 	unsigned int mem_id, addr, len;
951 
952 	if (argc != start_arg + 3) return -1;
953 
954 	if (!strcmp(argv[start_arg], "cm"))
955 		mem_id = MEM_CM;
956 	else if (!strcmp(argv[start_arg], "rx"))
957 		mem_id = MEM_PMRX;
958 	else if (!strcmp(argv[start_arg], "tx"))
959 		mem_id = MEM_PMTX;
960 	else
961 		errx(1, "unknown memory \"%s\"; must be one of \"cm\", \"tx\","
962 			" or \"rx\"", argv[start_arg]);
963 
964 	if (get_int_arg(argv[start_arg + 1], &addr) ||
965 	    get_int_arg(argv[start_arg + 2], &len))
966 		return -1;
967 
968 	mem.buf = malloc(len);
969 	if (!mem.buf)
970 		err(1, "memory dump");
971 
972 	mem.mem_id = mem_id;
973 	mem.addr   = addr;
974 	mem.len    = len;
975 
976 	if (doit(iff_name, CHELSIO_GET_MEM, &mem) < 0)
977 		err(1, "memory dump");
978 
979 	hexdump_8b(mem.addr, (uint64_t *)mem.buf, mem.len >> 3);
980 	free(mem.buf);
981 	return 0;
982 }
983 #endif
984 
985 /* Max FW size is 64K including version, +4 bytes for the checksum. */
986 #define MAX_FW_IMAGE_SIZE (64 * 1024)
987 
988 static int
989 load_fw(int argc, char *argv[], int start_arg, const char *iff_name)
990 {
991 	int fd, len;
992 	struct ch_mem_range op;
993 	const char *fname = argv[start_arg];
994 
995 	if (argc != start_arg + 1) return -1;
996 
997 	fd = open(fname, O_RDONLY);
998 	if (fd < 0)
999 		err(1, "load firmware");
1000 
1001 	bzero(&op, sizeof(op));
1002 	op.buf = malloc(MAX_FW_IMAGE_SIZE + 1);
1003 	if (!op.buf)
1004 		err(1, "load firmware");
1005 
1006 	len = read(fd, op.buf, MAX_FW_IMAGE_SIZE + 1);
1007 	if (len < 0)
1008 		err(1, "load firmware");
1009  	if (len > MAX_FW_IMAGE_SIZE)
1010 		errx(1, "FW image too large");
1011 
1012 	op.len = len;
1013 	if (doit(iff_name, CHELSIO_LOAD_FW, &op) < 0)
1014 		err(1, "load firmware");
1015 
1016 	close(fd);
1017 	return 0;
1018 }
1019 
1020 /* Max BOOT size is 255*512 bytes including the BIOS boot ROM basic header */
1021 #define MAX_BOOT_IMAGE_SIZE (0xff * 512)
1022 
1023 static int
1024 load_boot(int argc, char *argv[], int start_arg, const char *iff_name)
1025 {
1026 	int fd, len;
1027 	struct ch_mem_range op;
1028 	const char *fname = argv[start_arg];
1029 
1030 	if (argc != start_arg + 1) return -1;
1031 
1032 	fd = open(fname, O_RDONLY);
1033 	if (fd < 0)
1034 		err(1, "load boot image");
1035 
1036 	op.buf = malloc(MAX_BOOT_IMAGE_SIZE + 1);
1037 	if (!op.buf)
1038 		err(1, "load boot image");
1039 
1040 	len = read(fd, op.buf, MAX_BOOT_IMAGE_SIZE + 1);
1041 	if (len < 0)
1042 		err(1, "load boot image");
1043  	if (len > MAX_BOOT_IMAGE_SIZE)
1044 		errx(1, "boot image too large");
1045 
1046 	op.len = len;
1047 
1048 	if (doit(iff_name, CHELSIO_LOAD_BOOT, &op) < 0)
1049 		err(1, "load boot image");
1050 
1051 	close(fd);
1052 	return 0;
1053 }
1054 
1055 static int
1056 dump_proto_sram(const char *iff_name)
1057 {
1058 	int i, j;
1059 	uint8_t buf[PROTO_SRAM_SIZE];
1060 	struct ch_eeprom ee;
1061 	uint8_t *p = buf;
1062 
1063 	bzero(buf, sizeof(buf));
1064 	ee.offset = PROTO_SRAM_EEPROM_ADDR;
1065 	ee.data = p;
1066 	ee.len = sizeof(buf);
1067 	if (doit(iff_name, CHELSIO_GET_EEPROM, &ee))
1068 		err(1, "show protocol sram");
1069 
1070 	for (i = 0; i < PROTO_SRAM_LINES; i++) {
1071 		for (j = PROTO_SRAM_LINE_NIBBLES - 1; j >= 0; j--) {
1072 			int nibble_idx = i * PROTO_SRAM_LINE_NIBBLES + j;
1073 			uint8_t nibble = p[nibble_idx / 2];
1074 
1075 			if (nibble_idx & 1)
1076 				nibble >>= 4;
1077 			else
1078 				nibble &= 0xf;
1079 			printf("%x", nibble);
1080 		}
1081 		putchar('\n');
1082 	}
1083 	return 0;
1084 }
1085 
1086 static int
1087 proto_sram_op(int argc, char *argv[], int start_arg,
1088 			 const char *iff_name)
1089 {
1090 	(void) argv;
1091 	(void) start_arg;
1092 
1093 	if (argc == start_arg)
1094 		return dump_proto_sram(iff_name);
1095 	return -1;
1096 }
1097 
1098 static int
1099 dump_qset_params(const char *iff_name)
1100 {
1101 	struct ch_qset_params qp;
1102 
1103 	qp.qset_idx = 0;
1104 
1105 	while (doit(iff_name, CHELSIO_GET_QSET_PARAMS, &qp) == 0) {
1106 		if (!qp.qset_idx)
1107 			printf("Qset   TxQ0   TxQ1   TxQ2   RspQ   RxQ0   RxQ1"
1108 			       "  Cong  Lat   IRQ\n");
1109 		printf("%4u %6u %6u %6u %6u %6u %6u %5u %4u %5d\n",
1110 		       qp.qnum,
1111 		       qp.txq_size[0], qp.txq_size[1], qp.txq_size[2],
1112 		       qp.rspq_size, qp.fl_size[0], qp.fl_size[1],
1113 		       qp.cong_thres, qp.intr_lat, qp.vector);
1114 		qp.qset_idx++;
1115 	}
1116 	if (!qp.qset_idx || (errno && errno != EINVAL))
1117 		err(1, "get qset parameters");
1118 	return 0;
1119 }
1120 
1121 static int
1122 qset_config(int argc, char *argv[], int start_arg, const char *iff_name)
1123 {
1124 	(void) argv;
1125 
1126 	if (argc == start_arg)
1127 		return dump_qset_params(iff_name);
1128 
1129 	return -1;
1130 }
1131 
1132 static int
1133 qset_num_config(int argc, char *argv[], int start_arg, const char *iff_name)
1134 {
1135 	struct ch_reg reg;
1136 
1137 	(void) argv;
1138 
1139 	if (argc == start_arg) {
1140 		if (doit(iff_name, CHELSIO_GET_QSET_NUM, &reg) < 0)
1141 			err(1, "get qsets");
1142 		printf("%u\n", reg.val);
1143 		return 0;
1144 	}
1145 
1146 	return -1;
1147 }
1148 
1149 /*
1150  * Parse a string containing an IP address with an optional network prefix.
1151  */
1152 static int
1153 parse_ipaddr(const char *s, uint32_t *addr, uint32_t *mask)
1154 {
1155 	char *p, *slash;
1156 	struct in_addr ia;
1157 
1158 	*mask = 0xffffffffU;
1159 	slash = strchr(s, '/');
1160 	if (slash)
1161 		*slash = 0;
1162 	if (!inet_aton(s, &ia)) {
1163 		if (slash)
1164 			*slash = '/';
1165 		*addr = 0;
1166 		return -1;
1167 	}
1168 	*addr = ntohl(ia.s_addr);
1169 	if (slash) {
1170 		unsigned int prefix = strtoul(slash + 1, &p, 10);
1171 
1172 		*slash = '/';
1173 		if (p == slash + 1 || *p || prefix > 32)
1174 			return -1;
1175 		*mask <<= (32 - prefix);
1176 	}
1177 	return 0;
1178 }
1179 
1180 /*
1181  * Parse a string containing a value and an optional colon separated mask.
1182  */
1183 static int
1184 parse_val_mask_param(const char *s, uint32_t *val, uint32_t *mask,
1185     uint32_t default_mask)
1186 {
1187 	char *p;
1188 
1189 	*mask = default_mask;
1190 	*val = strtoul(s, &p, 0);
1191 	if (p == s || *val > default_mask)
1192 		return -1;
1193 	if (*p == ':' && p[1])
1194 		*mask = strtoul(p + 1, &p, 0);
1195 	return *p || *mask > default_mask ? -1 : 0;
1196 }
1197 
1198 static int
1199 parse_trace_param(const char *s, uint32_t *val, uint32_t *mask)
1200 {
1201 	return strchr(s, '.') ? parse_ipaddr(s, val, mask) :
1202 				parse_val_mask_param(s, val, mask, 0xffffffffU);
1203 }
1204 
1205 static int
1206 trace_config(int argc, char *argv[], int start_arg, const char *iff_name)
1207 {
1208 	uint32_t val, mask;
1209 	struct ch_trace trace;
1210 
1211 	if (argc == start_arg)
1212 		return -1;
1213 
1214 	memset(&trace, 0, sizeof(trace));
1215 	if (!strcmp(argv[start_arg], "tx"))
1216 		trace.config_tx = 1;
1217 	else if (!strcmp(argv[start_arg], "rx"))
1218 		trace.config_rx = 1;
1219 	else if (!strcmp(argv[start_arg], "all"))
1220 		trace.config_tx = trace.config_rx = 1;
1221 	else
1222 		errx(1, "bad trace filter \"%s\"; must be one of \"rx\", "
1223 		     "\"tx\" or \"all\"", argv[start_arg]);
1224 
1225 	if (argc == ++start_arg)
1226 		return -1;
1227 	if (!strcmp(argv[start_arg], "on")) {
1228 		trace.trace_tx = trace.config_tx;
1229 		trace.trace_rx = trace.config_rx;
1230 	} else if (strcmp(argv[start_arg], "off"))
1231 		errx(1, "bad argument \"%s\"; must be \"on\" or \"off\"",
1232 		     argv[start_arg]);
1233 
1234 	start_arg++;
1235 	if (start_arg < argc && !strcmp(argv[start_arg], "not")) {
1236 		trace.invert_match = 1;
1237 		start_arg++;
1238 	}
1239 
1240 	while (start_arg + 2 <= argc) {
1241 		int ret = parse_trace_param(argv[start_arg + 1], &val, &mask);
1242 
1243 		if (!strcmp(argv[start_arg], "interface")) {
1244 			trace.intf = val;
1245 			trace.intf_mask = mask;
1246 		} else if (!strcmp(argv[start_arg], "sip")) {
1247 			trace.sip = val;
1248 			trace.sip_mask = mask;
1249 		} else if (!strcmp(argv[start_arg], "dip")) {
1250 			trace.dip = val;
1251 			trace.dip_mask = mask;
1252 		} else if (!strcmp(argv[start_arg], "sport")) {
1253 			trace.sport = val;
1254 			trace.sport_mask = mask;
1255 		} else if (!strcmp(argv[start_arg], "dport")) {
1256 			trace.dport = val;
1257 			trace.dport_mask = mask;
1258 		} else if (!strcmp(argv[start_arg], "vlan")) {
1259 			trace.vlan = val;
1260 			trace.vlan_mask = mask;
1261 		} else if (!strcmp(argv[start_arg], "proto")) {
1262 			trace.proto = val;
1263 			trace.proto_mask = mask;
1264 		} else
1265 			errx(1, "unknown trace parameter \"%s\"\n"
1266 			     "known parameters are \"interface\", \"sip\", "
1267 			     "\"dip\", \"sport\", \"dport\", \"vlan\", "
1268 			     "\"proto\"", argv[start_arg]);
1269 		if (ret < 0)
1270 			errx(1, "bad parameter \"%s\"", argv[start_arg + 1]);
1271 		start_arg += 2;
1272 	}
1273 	if (start_arg != argc)
1274 		errx(1, "unknown parameter \"%s\"", argv[start_arg]);
1275 
1276 	if (doit(iff_name, CHELSIO_SET_TRACE_FILTER, &trace) < 0)
1277 		err(1, "trace");
1278 	return 0;
1279 }
1280 
1281 static void
1282 show_filters(const char *iff_name)
1283 {
1284 	static const char *pkt_type[] = { "*", "tcp", "udp", "frag" };
1285 	struct ch_filter op;
1286 	union {
1287 		uint32_t nip;
1288 		uint8_t octet[4];
1289 	} nsip, ndip;
1290 	char sip[20], dip[20];
1291 	int header = 0;
1292 
1293 	bzero(&op, sizeof(op));
1294 	op.filter_id = 0xffffffff;
1295 
1296 	do {
1297 		if (doit(iff_name, CHELSIO_GET_FILTER, &op) < 0)
1298 			err(1, "list filters");
1299 
1300 		if (op.filter_id == 0xffffffff)
1301 			break;
1302 
1303 		if (!header) {
1304 			printf("index         SIP                DIP     sport "
1305 			    "dport VLAN PRI P/MAC type Q\n");
1306 			header = 1;
1307 		}
1308 
1309 		nsip.nip = htonl(op.val.sip);
1310 		ndip.nip = htonl(op.val.dip);
1311 
1312 		sprintf(sip, "%u.%u.%u.%u/%-2u", nsip.octet[0], nsip.octet[1],
1313 		    nsip.octet[2], nsip.octet[3],
1314 		    op.mask.sip ? 33 - ffs(op.mask.sip) : 0);
1315 		sprintf(dip, "%u.%u.%u.%u", ndip.octet[0], ndip.octet[1],
1316 		    ndip.octet[2], ndip.octet[3]);
1317 		printf("%5zu %18s %15s ", (size_t)op.filter_id, sip, dip);
1318 		printf(op.val.sport ? "%5u " : "    * ", op.val.sport);
1319 		printf(op.val.dport ? "%5u " : "    * ", op.val.dport);
1320 		printf(op.val.vlan != 0xfff ? "%4u " : "   * ", op.val.vlan);
1321 		printf(op.val.vlan_prio == 7 ?  "  * " :
1322 		    "%1u/%1u ", op.val.vlan_prio, op.val.vlan_prio | 1);
1323 		if (op.mac_addr_idx == 0xffff)
1324 			printf("*/*   ");
1325 		else if (op.mac_hit)
1326 			printf("%1u/%3u ", (op.mac_addr_idx >> 3) & 0x1,
1327 			    (op.mac_addr_idx) & 0x7);
1328 		else
1329 			printf("%1u/  * ", (op.mac_addr_idx >> 3) & 0x1);
1330 		printf("%4s ", pkt_type[op.proto]);
1331 		if (!op.pass)
1332 			printf("-\n");
1333 		else if (op.rss)
1334 			printf("*\n");
1335 		else
1336 			printf("%1u\n", op.qset);
1337 	} while (1);
1338 }
1339 
1340 static int
1341 filter_config(int argc, char *argv[], int start_arg, const char *iff_name)
1342 {
1343 	int ret = 0;
1344 	uint32_t val, mask;
1345 	struct ch_filter op;
1346 
1347 	if (argc < start_arg + 1)
1348 		return -1;
1349 
1350 	memset(&op, 0, sizeof(op));
1351 	op.mac_addr_idx = 0xffff;
1352 	op.rss = 1;
1353 
1354 	if (argc == start_arg + 1 && !strcmp(argv[start_arg], "list")) {
1355 		show_filters(iff_name);
1356 		return 0;
1357 	}
1358 
1359 	if (get_int_arg(argv[start_arg++], &op.filter_id))
1360 		return -1;
1361 	if (argc == start_arg + 1 && (!strcmp(argv[start_arg], "delete") ||
1362 				      !strcmp(argv[start_arg], "clear"))) {
1363 		if (doit(iff_name, CHELSIO_DEL_FILTER, &op) < 0) {
1364 			if (errno == EBUSY)
1365 				err(1, "no filter support when offload in use");
1366 			err(1, "delete filter");
1367 		}
1368 		return 0;
1369 	}
1370 
1371 	while (start_arg + 2 <= argc) {
1372 		if (!strcmp(argv[start_arg], "sip")) {
1373 			ret = parse_ipaddr(argv[start_arg + 1], &op.val.sip,
1374 					   &op.mask.sip);
1375 		} else if (!strcmp(argv[start_arg], "dip")) {
1376 			ret = parse_ipaddr(argv[start_arg + 1], &op.val.dip,
1377 					   &op.mask.dip);
1378 		} else if (!strcmp(argv[start_arg], "sport")) {
1379 			ret = parse_val_mask_param(argv[start_arg + 1],
1380 						   &val, &mask, 0xffff);
1381 			op.val.sport = val;
1382 			op.mask.sport = mask;
1383 		} else if (!strcmp(argv[start_arg], "dport")) {
1384 			ret = parse_val_mask_param(argv[start_arg + 1],
1385 						   &val, &mask, 0xffff);
1386 			op.val.dport = val;
1387 			op.mask.dport = mask;
1388 		} else if (!strcmp(argv[start_arg], "vlan")) {
1389 			ret = parse_val_mask_param(argv[start_arg + 1],
1390 						   &val, &mask, 0xfff);
1391 			op.val.vlan = val;
1392 			op.mask.vlan = mask;
1393 		} else if (!strcmp(argv[start_arg], "prio")) {
1394 			ret = parse_val_mask_param(argv[start_arg + 1],
1395 						   &val, &mask, 7);
1396 			op.val.vlan_prio = val;
1397 			op.mask.vlan_prio = mask;
1398 		} else if (!strcmp(argv[start_arg], "mac")) {
1399 			if (!strcmp(argv[start_arg + 1], "none"))
1400 				val = -1;
1401 			else
1402 				ret = get_int_arg(argv[start_arg + 1], &val);
1403 			op.mac_hit = val != (uint32_t)-1;
1404 			op.mac_addr_idx = op.mac_hit ? val : 0;
1405 		} else if (!strcmp(argv[start_arg], "type")) {
1406 			if (!strcmp(argv[start_arg + 1], "tcp"))
1407 				op.proto = 1;
1408 			else if (!strcmp(argv[start_arg + 1], "udp"))
1409 				op.proto = 2;
1410 			else if (!strcmp(argv[start_arg + 1], "frag"))
1411 				op.proto = 3;
1412 			else
1413 				errx(1, "unknown type \"%s\"; must be one of "
1414 				     "\"tcp\", \"udp\", or \"frag\"",
1415 				     argv[start_arg + 1]);
1416 		} else if (!strcmp(argv[start_arg], "queue")) {
1417 			ret = get_int_arg(argv[start_arg + 1], &val);
1418 			op.qset = val;
1419 			op.rss = 0;
1420 		} else if (!strcmp(argv[start_arg], "action")) {
1421 			if (!strcmp(argv[start_arg + 1], "pass"))
1422 				op.pass = 1;
1423 			else if (strcmp(argv[start_arg + 1], "drop"))
1424 				errx(1, "unknown action \"%s\"; must be one of "
1425 				     "\"pass\" or \"drop\"",
1426 				     argv[start_arg + 1]);
1427 		} else
1428  			errx(1, "unknown filter parameter \"%s\"\n"
1429 			     "known parameters are \"mac\", \"sip\", "
1430 			     "\"dip\", \"sport\", \"dport\", \"vlan\", "
1431 			     "\"prio\", \"type\", \"queue\", and \"action\"",
1432 			     argv[start_arg]);
1433 		if (ret < 0)
1434 			errx(1, "bad value \"%s\" for parameter \"%s\"",
1435 			     argv[start_arg + 1], argv[start_arg]);
1436 		start_arg += 2;
1437 	}
1438 	if (start_arg != argc)
1439 		errx(1, "no value for \"%s\"", argv[start_arg]);
1440 
1441 	if (doit(iff_name, CHELSIO_SET_FILTER, &op) < 0) {
1442 		if (errno == EBUSY)
1443 			err(1, "no filter support when offload in use");
1444 		err(1, "set filter");
1445 	}
1446 
1447 	return 0;
1448 }
1449 static int
1450 get_sched_param(int argc, char *argv[], int pos, unsigned int *valp)
1451 {
1452 	if (pos + 1 >= argc)
1453 		errx(1, "missing value for %s", argv[pos]);
1454 	if (get_int_arg(argv[pos + 1], valp))
1455 		exit(1);
1456 	return 0;
1457 }
1458 
1459 static int
1460 tx_sched(int argc, char *argv[], int start_arg, const char *iff_name)
1461 {
1462 	struct ch_hw_sched op;
1463 	unsigned int idx, val;
1464 
1465 	if (argc < 5 || get_int_arg(argv[start_arg++], &idx))
1466 		return -1;
1467 
1468 	op.sched = idx;
1469 	op.mode = op.channel = -1;
1470 	op.kbps = op.class_ipg = op.flow_ipg = -1;
1471 
1472 	while (argc > start_arg) {
1473 		if (!strcmp(argv[start_arg], "mode")) {
1474 			if (start_arg + 1 >= argc)
1475 				errx(1, "missing value for mode");
1476 			if (!strcmp(argv[start_arg + 1], "class"))
1477 				op.mode = 0;
1478 			else if (!strcmp(argv[start_arg + 1], "flow"))
1479 				op.mode = 1;
1480 			else
1481 				errx(1, "bad mode \"%s\"", argv[start_arg + 1]);
1482 		} else if (!strcmp(argv[start_arg], "channel") &&
1483 			 !get_sched_param(argc, argv, start_arg, &val))
1484 			op.channel = val;
1485 		else if (!strcmp(argv[start_arg], "rate") &&
1486 			 !get_sched_param(argc, argv, start_arg, &val))
1487 			op.kbps = val;
1488 		else if (!strcmp(argv[start_arg], "ipg") &&
1489 			 !get_sched_param(argc, argv, start_arg, &val))
1490 			op.class_ipg = val;
1491 		else if (!strcmp(argv[start_arg], "flowipg") &&
1492 			 !get_sched_param(argc, argv, start_arg, &val))
1493 			op.flow_ipg = val;
1494 		else
1495 			errx(1, "unknown scheduler parameter \"%s\"",
1496 			     argv[start_arg]);
1497 		start_arg += 2;
1498 	}
1499 
1500 	if (doit(iff_name, CHELSIO_SET_HW_SCHED, &op) < 0)
1501 		 err(1, "pktsched");
1502 
1503 	return 0;
1504 }
1505 
1506 static int
1507 pktsched(int argc, char *argv[], int start_arg, const char *iff_name)
1508 {
1509 	struct ch_pktsched_params op;
1510 	unsigned int idx, min = -1, max, binding = -1;
1511 
1512 	if (argc < 4)
1513 		errx(1, "no scheduler specified");
1514 
1515 	if (!strcmp(argv[start_arg], "port")) {
1516 		if (argc != start_arg + 4)
1517 			return -1;
1518 		if (get_int_arg(argv[start_arg + 1], &idx) ||
1519 		    get_int_arg(argv[start_arg + 2], &min) ||
1520 		    get_int_arg(argv[start_arg + 3], &max))
1521 			return -1;
1522 		op.sched = 0;
1523 	} else if (!strcmp(argv[start_arg], "tunnelq")) {
1524 		if (argc != start_arg + 4)
1525 			return -1;
1526 		if (get_int_arg(argv[start_arg + 1], &idx) ||
1527 		    get_int_arg(argv[start_arg + 2], &max) ||
1528 		    get_int_arg(argv[start_arg + 3], &binding))
1529 			return -1;
1530 		op.sched = 1;
1531 	} else if (!strcmp(argv[start_arg], "tx"))
1532 		return tx_sched(argc, argv, start_arg + 1, iff_name);
1533 	else
1534 		errx(1, "unknown scheduler \"%s\"; must be one of \"port\", "
1535 			"\"tunnelq\" or \"tx\"", argv[start_arg]);
1536 
1537 	op.idx = idx;
1538 	op.min = min;
1539 	op.max = max;
1540 	op.binding = binding;
1541 	if (doit(iff_name, CHELSIO_SET_PKTSCHED, &op) < 0)
1542 		 err(1, "pktsched");
1543 
1544 	return 0;
1545 }
1546 
1547 static int
1548 clear_stats(int argc, char *argv[], int start_arg, const char *iff_name)
1549 {
1550 	(void) argc;
1551 	(void) argv;
1552 	(void) start_arg;
1553 
1554 	if (doit(iff_name, CHELSIO_CLEAR_STATS, NULL) < 0)
1555 		 err(1, "clearstats");
1556 
1557 	return 0;
1558 }
1559 
1560 static int
1561 get_up_la(int argc, char *argv[], int start_arg, const char *iff_name)
1562 {
1563 	struct ch_up_la la;
1564 	int i, idx, max_idx, entries;
1565 
1566 	(void) argc;
1567 	(void) argv;
1568 	(void) start_arg;
1569 
1570 	la.stopped = 0;
1571 	la.idx = -1;
1572 	la.bufsize = LA_BUFSIZE;
1573 	la.data = malloc(la.bufsize);
1574 	if (!la.data)
1575 		err(1, "uP_LA malloc");
1576 
1577 	if (doit(iff_name, CHELSIO_GET_UP_LA, &la) < 0)
1578 		 err(1, "uP_LA");
1579 
1580 	if (la.stopped)
1581 		printf("LA is not running\n");
1582 
1583 	entries = la.bufsize / 4;
1584 	idx = (int)la.idx;
1585 	max_idx = (entries / 4) - 1;
1586 	for (i = 0; i < max_idx; i++) {
1587 		printf("%04x %08x %08x\n",
1588 		       la.data[idx], la.data[idx+2], la.data[idx+1]);
1589 		idx = (idx + 4) & (entries - 1);
1590 	}
1591 
1592 	return 0;
1593 }
1594 
1595 static int
1596 get_up_ioqs(int argc, char *argv[], int start_arg, const char *iff_name)
1597 {
1598 	struct ch_up_ioqs ioqs;
1599 	int i, entries;
1600 
1601 	(void) argc;
1602 	(void) argv;
1603 	(void) start_arg;
1604 
1605 	bzero(&ioqs, sizeof(ioqs));
1606 	ioqs.bufsize = IOQS_BUFSIZE;
1607 	ioqs.data = malloc(IOQS_BUFSIZE);
1608 	if (!ioqs.data)
1609 		err(1, "uP_IOQs malloc");
1610 
1611 	if (doit(iff_name, CHELSIO_GET_UP_IOQS, &ioqs) < 0)
1612 		 err(1, "uP_IOQs");
1613 
1614 	printf("ioq_rx_enable   : 0x%08x\n", ioqs.ioq_rx_enable);
1615 	printf("ioq_tx_enable   : 0x%08x\n", ioqs.ioq_tx_enable);
1616 	printf("ioq_rx_status   : 0x%08x\n", ioqs.ioq_rx_status);
1617 	printf("ioq_tx_status   : 0x%08x\n", ioqs.ioq_tx_status);
1618 
1619 	entries = ioqs.bufsize / sizeof(struct t3_ioq_entry);
1620 	for (i = 0; i < entries; i++) {
1621 		printf("\nioq[%d].cp       : 0x%08x\n", i,
1622 		       ioqs.data[i].ioq_cp);
1623 		printf("ioq[%d].pp       : 0x%08x\n", i,
1624 		       ioqs.data[i].ioq_pp);
1625 		printf("ioq[%d].alen     : 0x%08x\n", i,
1626 		       ioqs.data[i].ioq_alen);
1627 		printf("ioq[%d].stats    : 0x%08x\n", i,
1628 		       ioqs.data[i].ioq_stats);
1629 		printf("  sop %u\n", ioqs.data[i].ioq_stats >> 16);
1630 		printf("  eop %u\n", ioqs.data[i].ioq_stats  & 0xFFFF);
1631 	}
1632 
1633 	return 0;
1634 }
1635 
1636 static int
1637 run_cmd(int argc, char *argv[], const char *iff_name)
1638 {
1639 	int r = -1;
1640 
1641 	if (!strcmp(argv[2], "reg"))
1642 		r = register_io(argc, argv, 3, iff_name);
1643 	else if (!strcmp(argv[2], "mdio"))
1644 		r = mdio_io(argc, argv, 3, iff_name);
1645 	else if (!strcmp(argv[2], "mtus"))
1646 		r = mtu_tab_op(argc, argv, 3, iff_name);
1647 	else if (!strcmp(argv[2], "pm"))
1648 		r = conf_pm(argc, argv, 3, iff_name);
1649 	else if (!strcmp(argv[2], "regdump"))
1650 		r = dump_regs(argc, argv, 3, iff_name);
1651 	else if (!strcmp(argv[2], "tcamdump"))
1652 		r = dump_tcam(argc, argv, 3, iff_name);
1653 	else if (!strcmp(argv[2], "memdump"))
1654 		r = dump_mc7(argc, argv, 3, iff_name);
1655 	else if (!strcmp(argv[2], "meminfo"))
1656 		r = meminfo(argc, argv, 3, iff_name);
1657 	else if (!strcmp(argv[2], "context"))
1658 		r = get_sge_context(argc, argv, 3, iff_name);
1659 	else if (!strcmp(argv[2], "desc"))
1660 		r = get_sge_desc(argc, argv, 3, iff_name);
1661 	else if (!strcmp(argv[2], "loadfw"))
1662 		r = load_fw(argc, argv, 3, iff_name);
1663 	else if (!strcmp(argv[2], "loadboot"))
1664 		r = load_boot(argc, argv, 3, iff_name);
1665 	else if (!strcmp(argv[2], "proto"))
1666 		r = proto_sram_op(argc, argv, 3, iff_name);
1667 	else if (!strcmp(argv[2], "qset"))
1668 		r = qset_config(argc, argv, 3, iff_name);
1669 	else if (!strcmp(argv[2], "qsets"))
1670 		r = qset_num_config(argc, argv, 3, iff_name);
1671 	else if (!strcmp(argv[2], "trace"))
1672 		r = trace_config(argc, argv, 3, iff_name);
1673 	else if (!strcmp(argv[2], "pktsched"))
1674 		r = pktsched(argc, argv, 3, iff_name);
1675 	else if (!strcmp(argv[2], "tcb"))
1676 		r = get_tcb2(argc, argv, 3, iff_name);
1677 	else if (!strcmp(argv[2], "filter"))
1678 		r = filter_config(argc, argv, 3, iff_name);
1679 	else if (!strcmp(argv[2], "clearstats"))
1680 		r = clear_stats(argc, argv, 3, iff_name);
1681 	else if (!strcmp(argv[2], "la"))
1682 		r = get_up_la(argc, argv, 3, iff_name);
1683 	else if (!strcmp(argv[2], "ioqs"))
1684 		r = get_up_ioqs(argc, argv, 3, iff_name);
1685 
1686 	if (r == -1)
1687 		usage(stderr);
1688 
1689 	return (0);
1690 }
1691 
1692 static int
1693 run_cmd_loop(int argc, char *argv[], const char *iff_name)
1694 {
1695 	int n;
1696 	unsigned int i;
1697 	char buf[64];
1698 	char *args[8], *s;
1699 
1700 	(void) argc;
1701 	args[0] = argv[0];
1702 	args[1] = argv[1];
1703 
1704 	/*
1705 	 * Fairly simplistic loop.  Displays a "> " prompt and processes any
1706 	 * input as a cxgbtool command.  You're supposed to enter only the part
1707 	 * after "cxgbtool cxgbX".  Use "quit" or "exit" to exit.  Any error in
1708 	 * the command will also terminate cxgbtool.
1709 	 */
1710 	for (;;) {
1711 		fprintf(stdout, "> ");
1712 		fflush(stdout);
1713 		n = read(STDIN_FILENO, buf, sizeof(buf) - 1);
1714 		if (n <= 0)
1715 			return (0);
1716 
1717 		if (buf[--n] != '\n')
1718 			continue;
1719 		else
1720 			buf[n] = 0;
1721 
1722 		s = &buf[0];
1723 		for (i = 2; i < sizeof(args)/sizeof(args[0]) - 1; i++) {
1724 			while (s && (*s == ' ' || *s == '\t'))
1725 				s++;
1726 			if ((args[i] = strsep(&s, " \t")) == NULL)
1727 				break;
1728 		}
1729 		args[sizeof(args)/sizeof(args[0]) - 1] = 0;
1730 
1731 		if (!strcmp(args[2], "quit") || !strcmp(args[2], "exit"))
1732 			return (0);
1733 
1734 		(void) run_cmd(i, args, iff_name);
1735 	}
1736 
1737 	/* Can't really get here */
1738 	return (0);
1739 }
1740 
1741 int
1742 main(int argc, char *argv[])
1743 {
1744 	int r = -1;
1745 	const char *iff_name;
1746 
1747 	progname = argv[0];
1748 
1749 	if (argc == 2) {
1750 		if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
1751 			usage(stdout);
1752 		if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) {
1753 			printf("%s version %s\n", PROGNAME, VERSION);
1754 			printf("%s\n", COPYRIGHT);
1755 			exit(0);
1756 		}
1757 	}
1758 
1759 	if (argc < 3) usage(stderr);
1760 
1761 	iff_name = argv[1];
1762 
1763 	if (argc == 3 && !strcmp(argv[2], "stdio"))
1764 		r = run_cmd_loop(argc, argv, iff_name);
1765 	else
1766 		r = run_cmd(argc, argv, iff_name);
1767 
1768 	return (r);
1769 }
1770