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