cxgbtool.c revision 167518
1/**************************************************************************
2
3Copyright (c) 2007, Chelsio Inc.
4All rights reserved.
5
6Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are met:
8
9 1. Redistributions of source code must retain the above copyright notice,
10    this list of conditions and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15
16 3. Neither the name of the Chelsio Corporation nor the names of its
17    contributors may be used to endorse or promote products derived from
18    this software without specific prior written permission.
19
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30POSSIBILITY OF SUCH DAMAGE.
31
32
33***************************************************************************/
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/usr.sbin/cxgbtool/cxgbtool.c 167518 2007-03-14 02:51:57Z kmacy $");
36
37#include <stdlib.h>
38#include <stdio.h>
39#include <stdint.h>
40#include <string.h>
41#include <unistd.h>
42#include <fcntl.h>
43#include <err.h>
44#include <errno.h>
45#include <inttypes.h>
46#include <sys/param.h>
47#include <sys/time.h>
48#include <sys/ioctl.h>
49#include <sys/socket.h>
50
51#include <netinet/in.h>
52#include <arpa/inet.h>
53
54#include <net/if.h>
55#include <net/if_var.h>
56#include <net/if_types.h>
57
58#define NMTUS 16
59#define TCB_SIZE 128
60#define TCB_WORDS (TCB_SIZE / 4)
61#define PROTO_SRAM_LINES 128
62#define PROTO_SRAM_LINE_BITS 132
63#define PROTO_SRAM_LINE_NIBBLES (132 / 4)
64#define PROTO_SRAM_SIZE (PROTO_SRAM_LINE_NIBBLES * PROTO_SRAM_LINES / 2)
65#define PROTO_SRAM_EEPROM_ADDR 4096
66
67#include <cxgb3_ioctl.h>
68#include <common/cxgb3_regs.h>
69#include "version.h"
70
71struct reg_info {
72        const char *name;
73        uint16_t addr;
74        uint16_t len;
75};
76
77
78#include "reg_defs.c"
79#if defined(CONFIG_T3_REGS)
80# include "reg_defs_t3.c"
81# include "reg_defs_t3b.c"
82#endif
83
84static const char *progname;
85
86static void __attribute__((noreturn)) usage(FILE *fp)
87{
88	fprintf(fp, "Usage: %s <interface> [operation]\n", progname);
89	fprintf(fp,
90#ifdef CHELSIO_INTERNAL
91		"\treg <address>[=<val>]               read/write register\n"
92		"\ttpi <address>[=<val>]               read/write TPI register\n"
93		"\tmdio <phy_addr> <mmd_addr>\n"
94	        "\t     <reg_addr> [<val>]             read/write MDIO register\n"
95#endif
96		"\tmtus [<mtu0>...<mtuN>]              read/write MTU table\n"
97#ifdef CHELSIO_INTERNAL
98		"\tpm [<TX page spec> <RX page spec>]  read/write PM config\n"
99		"\ttcam [<#serv> <#routes> <#filters>] read/write TCAM config\n"
100		"\ttcb <index>                         read TCB\n"
101#endif
102		"\tregdump [<module>]                  dump registers\n"
103#ifdef CHELSIO_INTERNAL
104		"\ttcamdump <address> <count>          show TCAM contents\n"
105		"\tcontext <type> <id>                 show an SGE context\n"
106		"\tdesc <qset> <queue> <idx> [<cnt>]   dump SGE descriptors\n"
107		"\tmemdump cm|tx|rx <addr> <len>       dump a mem range\n"
108		"\tmeminfo                             show memory info\n"
109#endif
110		"\tup                                  activate TOE\n"
111		"\tproto [<protocol image>]            read/write proto SRAM\n"
112		"\tloadfw <FW image>                   download firmware\n"
113		"\tqset [<index> [<param> <val>] ...]  read/write qset parameters\n"
114		"\tqsets [<# of qsets>]                read/write # of qsets\n"
115		"\ttrace tx|rx|all on|off [not]\n"
116	        "\t      [<param> <val>[:<mask>]] ...  write trace parameters\n"
117		"\tt1powersave [on|off]                enable/disable T1xx powersave mode\n"
118		"\tpktsched port <idx> <min> <max>     set TX port scheduler params\n"
119		"\tpktsched tunnelq <idx> <max>\n"
120		"\t         <binding>                  set TX tunnelq scheduler params\n"
121		);
122	exit(fp == stderr ? 1 : 0);
123}
124
125/*
126 * Make a TOETOOL ioctl call.
127 */
128static int
129doit(const char *iff_name, unsigned long cmd, void *data)
130{
131	static int fd = 0;
132
133	if (fd == 0) {
134		char buf[64];
135		snprintf(buf, 64, "/dev/%s", iff_name);
136
137		if ((fd = open(buf, O_RDWR)) < 0)
138			return (EINVAL);
139	}
140
141	return ioctl(fd, cmd, data) < 0 ? -1 : 0;
142}
143
144static int 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
156static uint32_t
157read_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
168static void
169write_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
180static int register_io(int argc, char *argv[], int start_arg,
181		       const char *iff_name)
182{
183	char *p;
184	uint32_t addr, val = 0, write = 0;
185
186	if (argc != start_arg + 1) return -1;
187
188	addr = strtoul(argv[start_arg], &p, 0);
189	if (p == argv[start_arg]) return -1;
190	if (*p == '=' && p[1]) {
191		val = strtoul(p + 1, &p, 0);
192		write = 1;
193	}
194	if (*p) {
195		warnx("bad parameter \"%s\"", argv[start_arg]);
196		return -1;
197	}
198
199	if (write)
200		write_reg(iff_name, addr, val);
201	else {
202		val = read_reg(iff_name, addr);
203		printf("%#x [%u]\n", val, val);
204	}
205	return 0;
206}
207
208static int mdio_io(int argc, char *argv[], int start_arg, const char *iff_name)
209{
210        struct ifreq ifr;
211        struct mii_data p;
212        unsigned int cmd, phy_addr, reg, mmd, val;
213
214        if (argc == start_arg + 3)
215                cmd = SIOCGMIIREG;
216        else if (argc == start_arg + 4)
217                cmd = SIOCSMIIREG;
218        else
219                return -1;
220
221        if (get_int_arg(argv[start_arg], &phy_addr) ||
222            get_int_arg(argv[start_arg + 1], &mmd) ||
223            get_int_arg(argv[start_arg + 2], &reg) ||
224            (cmd == SIOCSMIIREG && get_int_arg(argv[start_arg + 3], &val)))
225                return -1;
226
227        p.phy_id  = phy_addr | (mmd << 8);
228        p.reg_num = reg;
229        p.val_in  = val;
230
231        if (doit(iff_name, cmd, &p) < 0)
232                err(1, "MDIO %s", cmd == SIOCGMIIREG ? "read" : "write");
233        if (cmd == SIOCGMIIREG)
234                printf("%#x [%u]\n", p.val_out, p.val_out);
235        return 0;
236}
237
238static inline uint32_t xtract(uint32_t val, int shift, int len)
239{
240	return (val >> shift) & ((1 << len) - 1);
241}
242
243static int dump_block_regs(const struct reg_info *reg_array, uint32_t *regs)
244{
245	uint32_t reg_val = 0; // silence compiler warning
246
247	for ( ; reg_array->name; ++reg_array)
248		if (!reg_array->len) {
249			reg_val = regs[reg_array->addr / 4];
250			printf("[%#5x] %-40s %#-10x [%u]\n", reg_array->addr,
251			       reg_array->name, reg_val, reg_val);
252		} else {
253			uint32_t v = xtract(reg_val, reg_array->addr,
254					    reg_array->len);
255
256			printf("        %-40s %#-10x [%u]\n", reg_array->name,
257			       v, v);
258		}
259	return 1;
260}
261
262static int dump_regs_t2(int argc, char *argv[], int start_arg, uint32_t *regs)
263{
264	int match = 0;
265	char *block_name = NULL;
266
267	if (argc == start_arg + 1)
268		block_name = argv[start_arg];
269	else if (argc != start_arg)
270		return -1;
271
272	if (!block_name || !strcmp(block_name, "sge"))
273		match += dump_block_regs(sge_regs, regs);
274	if (!block_name || !strcmp(block_name, "mc3"))
275		match += dump_block_regs(mc3_regs, regs);
276	if (!block_name || !strcmp(block_name, "mc4"))
277		match += dump_block_regs(mc4_regs, regs);
278	if (!block_name || !strcmp(block_name, "tpi"))
279		match += dump_block_regs(tpi_regs, regs);
280	if (!block_name || !strcmp(block_name, "tp"))
281		match += dump_block_regs(tp_regs, regs);
282	if (!block_name || !strcmp(block_name, "rat"))
283		match += dump_block_regs(rat_regs, regs);
284	if (!block_name || !strcmp(block_name, "cspi"))
285		match += dump_block_regs(cspi_regs, regs);
286	if (!block_name || !strcmp(block_name, "espi"))
287		match += dump_block_regs(espi_regs, regs);
288	if (!block_name || !strcmp(block_name, "ulp"))
289		match += dump_block_regs(ulp_regs, regs);
290	if (!block_name || !strcmp(block_name, "pl"))
291		match += dump_block_regs(pl_regs, regs);
292	if (!block_name || !strcmp(block_name, "mc5"))
293		match += dump_block_regs(mc5_regs, regs);
294	if (!match)
295		errx(1, "unknown block \"%s\"", block_name);
296	return 0;
297}
298
299#if defined(CONFIG_T3_REGS)
300static int dump_regs_t3(int argc, char *argv[], int start_arg, uint32_t *regs,
301			int is_pcie)
302{
303	int match = 0;
304	char *block_name = NULL;
305
306	if (argc == start_arg + 1)
307		block_name = argv[start_arg];
308	else if (argc != start_arg)
309		return -1;
310
311	if (!block_name || !strcmp(block_name, "sge"))
312		match += dump_block_regs(sge3_regs, regs);
313	if (!block_name || !strcmp(block_name, "pci"))
314		match += dump_block_regs(is_pcie ? pcie0_regs : pcix1_regs,
315					 regs);
316	if (!block_name || !strcmp(block_name, "t3dbg"))
317		match += dump_block_regs(t3dbg_regs, regs);
318	if (!block_name || !strcmp(block_name, "pmrx"))
319		match += dump_block_regs(mc7_pmrx_regs, regs);
320	if (!block_name || !strcmp(block_name, "pmtx"))
321		match += dump_block_regs(mc7_pmtx_regs, regs);
322	if (!block_name || !strcmp(block_name, "cm"))
323		match += dump_block_regs(mc7_cm_regs, regs);
324	if (!block_name || !strcmp(block_name, "cim"))
325		match += dump_block_regs(cim_regs, regs);
326	if (!block_name || !strcmp(block_name, "tp"))
327		match += dump_block_regs(tp1_regs, regs);
328	if (!block_name || !strcmp(block_name, "ulp_rx"))
329		match += dump_block_regs(ulp2_rx_regs, regs);
330	if (!block_name || !strcmp(block_name, "ulp_tx"))
331		match += dump_block_regs(ulp2_tx_regs, regs);
332	if (!block_name || !strcmp(block_name, "pmrx"))
333		match += dump_block_regs(pm1_rx_regs, regs);
334	if (!block_name || !strcmp(block_name, "pmtx"))
335		match += dump_block_regs(pm1_tx_regs, regs);
336	if (!block_name || !strcmp(block_name, "mps"))
337		match += dump_block_regs(mps0_regs, regs);
338	if (!block_name || !strcmp(block_name, "cplsw"))
339		match += dump_block_regs(cpl_switch_regs, regs);
340	if (!block_name || !strcmp(block_name, "smb"))
341		match += dump_block_regs(smb0_regs, regs);
342	if (!block_name || !strcmp(block_name, "i2c"))
343		match += dump_block_regs(i2cm0_regs, regs);
344	if (!block_name || !strcmp(block_name, "mi1"))
345		match += dump_block_regs(mi1_regs, regs);
346	if (!block_name || !strcmp(block_name, "sf"))
347		match += dump_block_regs(sf1_regs, regs);
348	if (!block_name || !strcmp(block_name, "pl"))
349		match += dump_block_regs(pl3_regs, regs);
350	if (!block_name || !strcmp(block_name, "mc5"))
351		match += dump_block_regs(mc5a_regs, regs);
352	if (!block_name || !strcmp(block_name, "xgmac0"))
353		match += dump_block_regs(xgmac0_0_regs, regs);
354	if (!block_name || !strcmp(block_name, "xgmac1"))
355		match += dump_block_regs(xgmac0_1_regs, regs);
356	if (!match)
357		errx(1, "unknown block \"%s\"", block_name);
358	return 0;
359}
360
361static int dump_regs_t3b(int argc, char *argv[], int start_arg, uint32_t *regs,
362			 int is_pcie)
363{
364	int match = 0;
365	char *block_name = NULL;
366
367	if (argc == start_arg + 1)
368		block_name = argv[start_arg];
369	else if (argc != start_arg)
370		return -1;
371
372	if (!block_name || !strcmp(block_name, "sge"))
373		match += dump_block_regs(t3b_sge3_regs, regs);
374	if (!block_name || !strcmp(block_name, "pci"))
375		match += dump_block_regs(is_pcie ? t3b_pcie0_regs :
376						   t3b_pcix1_regs, regs);
377	if (!block_name || !strcmp(block_name, "t3dbg"))
378		match += dump_block_regs(t3b_t3dbg_regs, regs);
379	if (!block_name || !strcmp(block_name, "pmrx"))
380		match += dump_block_regs(t3b_mc7_pmrx_regs, regs);
381	if (!block_name || !strcmp(block_name, "pmtx"))
382		match += dump_block_regs(t3b_mc7_pmtx_regs, regs);
383	if (!block_name || !strcmp(block_name, "cm"))
384		match += dump_block_regs(t3b_mc7_cm_regs, regs);
385	if (!block_name || !strcmp(block_name, "cim"))
386		match += dump_block_regs(t3b_cim_regs, regs);
387	if (!block_name || !strcmp(block_name, "tp"))
388		match += dump_block_regs(t3b_tp1_regs, regs);
389	if (!block_name || !strcmp(block_name, "ulp_rx"))
390		match += dump_block_regs(t3b_ulp2_rx_regs, regs);
391	if (!block_name || !strcmp(block_name, "ulp_tx"))
392		match += dump_block_regs(t3b_ulp2_tx_regs, regs);
393	if (!block_name || !strcmp(block_name, "pmrx"))
394		match += dump_block_regs(t3b_pm1_rx_regs, regs);
395	if (!block_name || !strcmp(block_name, "pmtx"))
396		match += dump_block_regs(t3b_pm1_tx_regs, regs);
397	if (!block_name || !strcmp(block_name, "mps"))
398		match += dump_block_regs(t3b_mps0_regs, regs);
399	if (!block_name || !strcmp(block_name, "cplsw"))
400		match += dump_block_regs(t3b_cpl_switch_regs, regs);
401	if (!block_name || !strcmp(block_name, "smb"))
402		match += dump_block_regs(t3b_smb0_regs, regs);
403	if (!block_name || !strcmp(block_name, "i2c"))
404		match += dump_block_regs(t3b_i2cm0_regs, regs);
405	if (!block_name || !strcmp(block_name, "mi1"))
406		match += dump_block_regs(t3b_mi1_regs, regs);
407	if (!block_name || !strcmp(block_name, "sf"))
408		match += dump_block_regs(t3b_sf1_regs, regs);
409	if (!block_name || !strcmp(block_name, "pl"))
410		match += dump_block_regs(t3b_pl3_regs, regs);
411	if (!block_name || !strcmp(block_name, "mc5"))
412		match += dump_block_regs(t3b_mc5a_regs, regs);
413	if (!block_name || !strcmp(block_name, "xgmac0"))
414		match += dump_block_regs(t3b_xgmac0_0_regs, regs);
415	if (!block_name || !strcmp(block_name, "xgmac1"))
416		match += dump_block_regs(t3b_xgmac0_1_regs, regs);
417	if (!match)
418		errx(1, "unknown block \"%s\"", block_name);
419	return 0;
420}
421#endif
422
423static int
424dump_regs(int argc, char *argv[], int start_arg, const char *iff_name)
425{
426
427
428	int i, vers, revision, is_pcie;
429	struct ifconf_regs regs;
430
431	regs.len = REGDUMP_SIZE;
432
433	if ((regs.data = malloc(REGDUMP_SIZE)) == NULL)
434		err(1, "can't malloc");
435
436	if (doit(iff_name, CHELSIO_IFCONF_GETREGS, &regs))
437		err(1, "can't read registers");
438
439	vers = regs.version & 0x3ff;
440	revision = (regs.version >> 10) & 0x3f;
441	is_pcie = (regs.version & 0x80000000) != 0;
442
443	if (vers <= 2)
444		return dump_regs_t2(argc, argv, start_arg, (uint32_t *)regs.data);
445#if defined(CONFIG_T3_REGS)
446	if (vers == 3) {
447		if (revision == 0)
448			return dump_regs_t3(argc, argv, start_arg,
449					    (uint32_t *)regs.data, is_pcie);
450		if (revision == 2)
451			return dump_regs_t3b(argc, argv, start_arg,
452					     (uint32_t *)regs.data, is_pcie);
453	}
454#endif
455	errx(1, "unknown card type %d", vers);
456	return 0;
457}
458
459static int t3_meminfo(const uint32_t *regs)
460{
461	enum {
462		SG_EGR_CNTX_BADDR       = 0x58,
463		SG_CQ_CONTEXT_BADDR     = 0x6c,
464		CIM_SDRAM_BASE_ADDR     = 0x28c,
465		CIM_SDRAM_ADDR_SIZE     = 0x290,
466		TP_CMM_MM_BASE          = 0x314,
467		TP_CMM_TIMER_BASE       = 0x318,
468		TP_CMM_MM_RX_FLST_BASE  = 0x460,
469		TP_CMM_MM_TX_FLST_BASE  = 0x464,
470		TP_CMM_MM_PS_FLST_BASE  = 0x468,
471		ULPRX_ISCSI_LLIMIT      = 0x50c,
472		ULPRX_ISCSI_ULIMIT      = 0x510,
473		ULPRX_TDDP_LLIMIT       = 0x51c,
474		ULPRX_TDDP_ULIMIT       = 0x520,
475		ULPRX_STAG_LLIMIT       = 0x52c,
476		ULPRX_STAG_ULIMIT       = 0x530,
477		ULPRX_RQ_LLIMIT         = 0x534,
478		ULPRX_RQ_ULIMIT         = 0x538,
479		ULPRX_PBL_LLIMIT        = 0x53c,
480		ULPRX_PBL_ULIMIT        = 0x540,
481	};
482
483	unsigned int egr_cntxt = regs[SG_EGR_CNTX_BADDR / 4],
484		     cq_cntxt = regs[SG_CQ_CONTEXT_BADDR / 4],
485		     timers = regs[TP_CMM_TIMER_BASE / 4] & 0xfffffff,
486		     pstructs = regs[TP_CMM_MM_BASE / 4],
487		     pstruct_fl = regs[TP_CMM_MM_PS_FLST_BASE / 4],
488		     rx_fl = regs[TP_CMM_MM_RX_FLST_BASE / 4],
489		     tx_fl = regs[TP_CMM_MM_TX_FLST_BASE / 4],
490		     cim_base = regs[CIM_SDRAM_BASE_ADDR / 4],
491		     cim_size = regs[CIM_SDRAM_ADDR_SIZE / 4];
492	unsigned int iscsi_ll = regs[ULPRX_ISCSI_LLIMIT / 4],
493		     iscsi_ul = regs[ULPRX_ISCSI_ULIMIT / 4],
494		     tddp_ll = regs[ULPRX_TDDP_LLIMIT / 4],
495		     tddp_ul = regs[ULPRX_TDDP_ULIMIT / 4],
496		     stag_ll = regs[ULPRX_STAG_LLIMIT / 4],
497		     stag_ul = regs[ULPRX_STAG_ULIMIT / 4],
498		     rq_ll = regs[ULPRX_RQ_LLIMIT / 4],
499		     rq_ul = regs[ULPRX_RQ_ULIMIT / 4],
500		     pbl_ll = regs[ULPRX_PBL_LLIMIT / 4],
501		     pbl_ul = regs[ULPRX_PBL_ULIMIT / 4];
502
503	printf("CM memory map:\n");
504	printf("  TCB region:      0x%08x - 0x%08x [%u]\n", 0, egr_cntxt - 1,
505	       egr_cntxt);
506	printf("  Egress contexts: 0x%08x - 0x%08x [%u]\n", egr_cntxt,
507	       cq_cntxt - 1, cq_cntxt - egr_cntxt);
508	printf("  CQ contexts:     0x%08x - 0x%08x [%u]\n", cq_cntxt,
509	       timers - 1, timers - cq_cntxt);
510	printf("  Timers:          0x%08x - 0x%08x [%u]\n", timers,
511	       pstructs - 1, pstructs - timers);
512	printf("  Pstructs:        0x%08x - 0x%08x [%u]\n", pstructs,
513	       pstruct_fl - 1, pstruct_fl - pstructs);
514	printf("  Pstruct FL:      0x%08x - 0x%08x [%u]\n", pstruct_fl,
515	       rx_fl - 1, rx_fl - pstruct_fl);
516	printf("  Rx FL:           0x%08x - 0x%08x [%u]\n", rx_fl, tx_fl - 1,
517	       tx_fl - rx_fl);
518	printf("  Tx FL:           0x%08x - 0x%08x [%u]\n", tx_fl, cim_base - 1,
519	       cim_base - tx_fl);
520	printf("  uP RAM:          0x%08x - 0x%08x [%u]\n", cim_base,
521	       cim_base + cim_size - 1, cim_size);
522
523	printf("\nPMRX memory map:\n");
524	printf("  iSCSI region:    0x%08x - 0x%08x [%u]\n", iscsi_ll, iscsi_ul,
525	       iscsi_ul - iscsi_ll + 1);
526	printf("  TCP DDP region:  0x%08x - 0x%08x [%u]\n", tddp_ll, tddp_ul,
527	       tddp_ul - tddp_ll + 1);
528	printf("  TPT region:      0x%08x - 0x%08x [%u]\n", stag_ll, stag_ul,
529	       stag_ul - stag_ll + 1);
530	printf("  RQ region:       0x%08x - 0x%08x [%u]\n", rq_ll, rq_ul,
531	       rq_ul - rq_ll + 1);
532	printf("  PBL region:      0x%08x - 0x%08x [%u]\n", pbl_ll, pbl_ul,
533	       pbl_ul - pbl_ll + 1);
534	return 0;
535}
536
537static int meminfo(int argc, char *argv[], int start_arg, const char *iff_name)
538{
539	int vers;
540	struct ifconf_regs regs;
541
542	if ((regs.data = malloc(REGDUMP_SIZE)) == NULL)
543		err(1, "can't malloc");
544
545	if (doit(iff_name, CHELSIO_IFCONF_GETREGS, &regs))
546		err(1, "can't read registers");
547
548	vers = regs.version & 0x3ff;
549	if (vers == 3)
550		return t3_meminfo((uint32_t *)regs.data);
551
552	errx(1, "unknown card type %d", vers);
553	return 0;
554}
555
556#ifdef notyet
557static int mtu_tab_op(int argc, char *argv[], int start_arg,
558		      const char *iff_name)
559{
560	struct toetool_mtus op;
561	int i;
562
563	if (argc == start_arg) {
564		op.cmd = TOETOOL_GETMTUTAB;
565		op.nmtus = MAX_NMTUS;
566
567		if (doit(iff_name, &op) < 0)
568			err(1, "get MTU table");
569		for (i = 0; i < op.nmtus; ++i)
570			printf("%u ", op.mtus[i]);
571		printf("\n");
572	} else if (argc <= start_arg + MAX_NMTUS) {
573		op.cmd = TOETOOL_SETMTUTAB;
574		op.nmtus = argc - start_arg;
575
576		for (i = 0; i < op.nmtus; ++i) {
577			char *p;
578			unsigned long m = strtoul(argv[start_arg + i], &p, 0);
579
580			if (*p || m > 9600) {
581				warnx("bad parameter \"%s\"",
582				      argv[start_arg + i]);
583				return -1;
584			}
585			if (i && m < op.mtus[i - 1])
586				errx(1, "MTUs must be in ascending order");
587			op.mtus[i] = m;
588		}
589		if (doit(iff_name, &op) < 0)
590			err(1, "set MTU table");
591	} else
592		return -1;
593
594	return 0;
595}
596#endif
597
598#ifdef CHELSIO_INTERNAL
599static void show_egress_cntxt(uint32_t data[])
600{
601	printf("credits:      %u\n", data[0] & 0x7fff);
602	printf("GTS:          %u\n", (data[0] >> 15) & 1);
603	printf("index:        %u\n", data[0] >> 16);
604	printf("queue size:   %u\n", data[1] & 0xffff);
605	printf("base address: 0x%llx\n",
606	       ((data[1] >> 16) | ((uint64_t)data[2] << 16) |
607	       (((uint64_t)data[3] & 0xf) << 48)) << 12);
608	printf("rsp queue #:  %u\n", (data[3] >> 4) & 7);
609	printf("cmd queue #:  %u\n", (data[3] >> 7) & 1);
610	printf("TUN:          %u\n", (data[3] >> 8) & 1);
611	printf("TOE:          %u\n", (data[3] >> 9) & 1);
612	printf("generation:   %u\n", (data[3] >> 10) & 1);
613	printf("uP token:     %u\n", (data[3] >> 11) & 0xfffff);
614	printf("valid:        %u\n", (data[3] >> 31) & 1);
615}
616
617static void show_fl_cntxt(uint32_t data[])
618{
619	printf("base address: 0x%llx\n",
620	       ((uint64_t)data[0] | ((uint64_t)data[1] & 0xfffff) << 32) << 12);
621	printf("index:        %u\n", (data[1] >> 20) | ((data[2] & 0xf) << 12));
622	printf("queue size:   %u\n", (data[2] >> 4) & 0xffff);
623	printf("generation:   %u\n", (data[2] >> 20) & 1);
624	printf("entry size:   %u\n",
625	       ((data[2] >> 21) & 0x7ff) | (data[3] & 0x1fffff));
626	printf("congest thr:  %u\n", (data[3] >> 21) & 0x3ff);
627	printf("GTS:          %u\n", (data[3] >> 31) & 1);
628}
629
630static void show_response_cntxt(uint32_t data[])
631{
632	printf("index:        %u\n", data[0] & 0xffff);
633	printf("size:         %u\n", data[0] >> 16);
634	printf("base address: 0x%llx\n",
635	       ((uint64_t)data[1] | ((uint64_t)data[2] & 0xfffff) << 32) << 12);
636	printf("MSI-X/RspQ:   %u\n", (data[2] >> 20) & 0x3f);
637	printf("intr enable:  %u\n", (data[2] >> 26) & 1);
638	printf("intr armed:   %u\n", (data[2] >> 27) & 1);
639	printf("generation:   %u\n", (data[2] >> 28) & 1);
640	printf("CQ mode:      %u\n", (data[2] >> 31) & 1);
641	printf("FL threshold: %u\n", data[3]);
642}
643
644static void show_cq_cntxt(uint32_t data[])
645{
646	printf("index:            %u\n", data[0] & 0xffff);
647	printf("size:             %u\n", data[0] >> 16);
648	printf("base address:     0x%llx\n",
649	       ((uint64_t)data[1] | ((uint64_t)data[2] & 0xfffff) << 32) << 12);
650	printf("rsp queue #:      %u\n", (data[2] >> 20) & 0x3f);
651	printf("AN:               %u\n", (data[2] >> 26) & 1);
652	printf("armed:            %u\n", (data[2] >> 27) & 1);
653	printf("ANS:              %u\n", (data[2] >> 28) & 1);
654	printf("generation:       %u\n", (data[2] >> 29) & 1);
655	printf("overflow mode:    %u\n", (data[2] >> 31) & 1);
656	printf("credits:          %u\n", data[3] & 0xffff);
657	printf("credit threshold: %u\n", data[3] >> 16);
658}
659
660static int get_sge_context(int argc, char *argv[], int start_arg,
661			   const char *iff_name)
662{
663	struct ch_cntxt ctx;
664
665	if (argc != start_arg + 2) return -1;
666
667	if (!strcmp(argv[start_arg], "egress"))
668		ctx.cntxt_type = CNTXT_TYPE_EGRESS;
669	else if (!strcmp(argv[start_arg], "fl"))
670		ctx.cntxt_type = CNTXT_TYPE_FL;
671	else if (!strcmp(argv[start_arg], "response"))
672		ctx.cntxt_type = CNTXT_TYPE_RSP;
673	else if (!strcmp(argv[start_arg], "cq"))
674		ctx.cntxt_type = CNTXT_TYPE_CQ;
675	else {
676		warnx("unknown context type \"%s\"; known types are egress, "
677		      "fl, cq, and response", argv[start_arg]);
678		return -1;
679	}
680
681	if (get_int_arg(argv[start_arg + 1], &ctx.cntxt_id))
682		return -1;
683
684	if (doit(iff_name, CHELSIO_GET_SGE_CONTEXT, &ctx) < 0)
685		err(1, "get SGE context");
686
687	if (!strcmp(argv[start_arg], "egress"))
688		show_egress_cntxt(ctx.data);
689	else if (!strcmp(argv[start_arg], "fl"))
690		show_fl_cntxt(ctx.data);
691	else if (!strcmp(argv[start_arg], "response"))
692		show_response_cntxt(ctx.data);
693	else if (!strcmp(argv[start_arg], "cq"))
694		show_cq_cntxt(ctx.data);
695	return 0;
696}
697
698#if __BYTE_ORDER == __BIG_ENDIAN
699# define ntohll(n) (n)
700#else
701# define ntohll(n) bswap_64(n)
702#endif
703
704static int get_sge_desc(int argc, char *argv[], int start_arg,
705			const char *iff_name)
706{
707	uint64_t *p, wr_hdr;
708	unsigned int n = 1, qset, qnum;
709	struct ch_desc desc;
710
711	if (argc != start_arg + 3 && argc != start_arg + 4)
712		return -1;
713
714	if (get_int_arg(argv[start_arg], &qset) ||
715	    get_int_arg(argv[start_arg + 1], &qnum) ||
716	    get_int_arg(argv[start_arg + 2], &desc.idx))
717		return -1;
718
719	if (argc == start_arg + 4 && get_int_arg(argv[start_arg + 3], &n))
720		return -1;
721
722	if (qnum > 5)
723		errx(1, "invalid queue number %d, range is 0..5", qnum);
724
725	desc.queue_num = qset * 6 + qnum;
726
727	for (; n--; desc.idx++) {
728		if (doit(iff_name, CHELSIO_GET_SGE_DESC, &desc) < 0)
729			err(1, "get SGE descriptor");
730
731		p = (uint64_t *)desc.data;
732		wr_hdr = ntohll(*p);
733		printf("Descriptor %u: cmd %u, TID %u, %s%s%s%s%u flits\n",
734		       desc.idx, (unsigned int)(wr_hdr >> 56),
735		       ((unsigned int)wr_hdr >> 8) & 0xfffff,
736		       ((wr_hdr >> 55) & 1) ? "SOP, " : "",
737		       ((wr_hdr >> 54) & 1) ? "EOP, " : "",
738		       ((wr_hdr >> 53) & 1) ? "COMPL, " : "",
739		       ((wr_hdr >> 52) & 1) ? "SGL, " : "",
740		       (unsigned int)wr_hdr & 0xff);
741
742		for (; desc.size; p++, desc.size -= sizeof(uint64_t))
743			printf("%016" PRIx64 "%c", ntohll(*p),
744			    desc.size % 32 == 8 ? '\n' : ' ');
745	}
746	return 0;
747}
748#endif
749
750#ifdef notyet
751static int get_tcb2(unsigned int tcb_idx, const char *iff_name)
752{
753	uint64_t *d;
754	unsigned int i;
755	struct toetool_mem_range *op;
756
757	op = malloc(sizeof(*op) + TCB_SIZE);
758	if (!op)
759		err(1, "get TCB");
760
761	op->cmd    = TOETOOL_GET_MEM;
762	op->mem_id = MEM_CM;
763	op->addr   = tcb_idx * TCB_SIZE;
764	op->len    = TCB_SIZE;
765
766	if (doit(iff_name, op) < 0)
767		err(1, "get TCB");
768
769	for (d = (uint64_t *)op->buf, i = 0; i < TCB_SIZE / 32; i++) {
770		printf("%2u:", i);
771		printf(" %08x %08x %08x %08x", (uint32_t)d[1],
772		       (uint32_t)(d[1] >> 32), (uint32_t)d[0],
773		       (uint32_t)(d[0] >> 32));
774		d += 2;
775		printf(" %08x %08x %08x %08x\n", (uint32_t)d[1],
776		       (uint32_t)(d[1] >> 32), (uint32_t)d[0],
777		       (uint32_t)(d[0] >> 32));
778		d += 2;
779	}
780	free(op);
781	return 0;
782}
783
784static int get_tcb(int argc, char *argv[], int start_arg, const char *iff_name)
785{
786	int i;
787	uint32_t *d;
788	struct toetool_tcb op;
789
790	if (argc != start_arg + 1) return -1;
791
792	op.cmd = TOETOOL_GET_TCB;
793	if (get_int_arg(argv[start_arg], &op.tcb_index))
794		return -1;
795
796	/*
797	 * If this operation isn't directly supported by the driver we may
798	 * still be able to read TCBs using the generic memory dump operation.
799	 */
800	if (doit(iff_name, &op) < 0) {
801		if (errno != EOPNOTSUPP)
802			err(1, "get TCB");
803		return get_tcb2(op.tcb_index, iff_name);
804	}
805
806	for (d = op.tcb_data, i = 0; i < TCB_WORDS; i += 8) {
807		int j;
808
809		printf("%2u:", 4 * i);
810		for (j = 0; j < 8; ++j)
811			printf(" %08x", *d++);
812		printf("\n");
813	}
814	return 0;
815}
816#endif
817#ifdef WRC
818/*
819 * The following defines, typedefs and structures are defined in the FW and
820 * should be exported instead of being redefined here (and kept up in sync).
821 * We'll fix this in the next round of FW cleanup.
822 */
823#define CM_WRCONTEXT_BASE       0x20300000
824#define CM_WRCONTEXT_OFFSET	0x300000
825#define WRC_SIZE                (FW_WR_SIZE * (2 + FW_WR_NUM) + 32 + 4 * 128)
826#define FW_WR_SIZE	128
827#define FW_WR_NUM	16
828#define FBUF_SIZE	(FW_WR_SIZE * FW_WR_NUM)
829#define FBUF_WRAP_SIZE	128
830#define FBUF_WRAP_FSZ	(FBUF_WRAP_SZ >> 3)
831#define MEM_CM_WRC_SIZE  WRC_SIZE
832
833typedef char 			int8_t;
834typedef short 			int16_t;
835typedef int 			int32_t;
836typedef long long 		_s64;
837typedef unsigned char           _u8;
838typedef unsigned short          _u16;
839typedef unsigned int            _uint32_t;
840typedef unsigned long long      uint64_t;
841
842enum fw_ri_mpa_attrs {
843	FW_RI_MPA_RX_MARKER_ENABLE = 0x1,
844	FW_RI_MPA_TX_MARKER_ENABLE = 0x2,
845	FW_RI_MPA_CRC_ENABLE	= 0x4,
846	FW_RI_MPA_IETF_ENABLE	= 0x8
847} __attribute__ ((packed));
848
849enum fw_ri_qp_caps {
850	FW_RI_QP_RDMA_READ_ENABLE = 0x01,
851	FW_RI_QP_RDMA_WRITE_ENABLE = 0x02,
852	FW_RI_QP_BIND_ENABLE	= 0x04,
853	FW_RI_QP_FAST_REGISTER_ENABLE = 0x08,
854	FW_RI_QP_STAG0_ENABLE	= 0x10
855} __attribute__ ((packed));
856
857enum wrc_state {
858	WRC_STATE_CLOSED,
859	WRC_STATE_ABORTED,
860	WRC_STATE_HALFCLOSED,
861	WRC_STATE_TOE_ESTABLISHED,
862	WRC_STATE_RDMA_TX_DATA_PEND,
863	WRC_STATE_RDMA_PEND,
864	WRC_STATE_RDMA_ESTABLISHED,
865};
866
867struct _wr {
868	uint32_t a;
869	uint32_t b;
870};
871
872struct fbuf {
873	uint32_t 	pp;			/* fifo producer pointer */
874	uint32_t	cp;			/* fifo consumer pointer */
875	int32_t	num_bytes;		/* num bytes stored in the fbuf */
876	char	bufferb[FBUF_SIZE]; 	/* buffer space in bytes */
877	char	_wrap[FBUF_WRAP_SIZE];	/* wrap buffer size*/
878};
879struct wrc {
880	uint32_t	wrc_tid;
881	_u16	wrc_flags;
882	_u8	wrc_state;
883	_u8	wrc_credits;
884
885	/* IO */
886	_u16	wrc_sge_ec;
887	_u8	wrc_sge_respQ;
888	_u8	wrc_port;
889	_u8	wrc_ulp;
890
891	_u8	wrc_coherency_counter;
892
893	/* REASSEMBLY */
894	_u8	wrc_frag_len;
895	_u8	wrc_frag_credits;
896	uint32_t	wrc_frag;
897
898	union {
899		struct {
900
901			/* TOE */
902			_u8	aborted;
903			_u8	wrc_num_tx_pages;
904			_u8	wrc_max_tx_pages;
905			_u8	wrc_trace_idx;
906			uint32_t 	wrc_snd_nxt;
907			uint32_t 	wrc_snd_max;
908			uint32_t 	wrc_snd_una;
909			uint32_t	wrc_snd_iss;
910
911			/* RI */
912			uint32_t	wrc_pdid;
913			uint32_t	wrc_scqid;
914			uint32_t	wrc_rcqid;
915			uint32_t	wrc_rq_addr_32a;
916			_u16	wrc_rq_size;
917			_u16	wrc_rq_wr_idx;
918			enum fw_ri_mpa_attrs wrc_mpaattrs;
919			enum fw_ri_qp_caps wrc_qpcaps;
920			_u16	wrc_mulpdu_tagged;
921			_u16	wrc_mulpdu_untagged;
922			_u16	wrc_ord_max;
923			_u16	wrc_ird_max;
924			_u16	wrc_ord;
925			_u16	wrc_ird;
926			_u16	wrc_markeroffset;
927			uint32_t	wrc_msn_send;
928			uint32_t	wrc_msn_rdma_read;
929			uint32_t	wrc_msn_rdma_read_req;
930			_u16	wrc_rdma_read_req_err;
931			_u8	wrc_ack_mode;
932			_u8	wrc_sge_ec_credits;
933			_u16	wrc_maxiolen_tagged;
934			_u16	wrc_maxiolen_untagged;
935			uint32_t	wrc_mo;
936		} toe_ri;
937
938		struct {
939
940		} ipmi;
941
942		struct {
943			uint32_t	wrc_pad2[24];
944		} pad;
945	} u __attribute__ ((packed));
946
947	/* BUFFERING */
948	struct fbuf wrc_fbuf __attribute__ ((packed));
949};
950#define wrc_aborted u.toe_ri.aborted
951#define wrc_num_tx_pages u.toe_ri.wrc_num_tx_pages
952#define wrc_max_tx_pages u.toe_ri.wrc_max_tx_pages
953#define wrc_trace_idx u.toe_ri.wrc_trace_idx
954#define wrc_snd_nxt u.toe_ri.wrc_snd_nxt
955#define wrc_snd_max u.toe_ri.wrc_snd_max
956#define wrc_snd_una u.toe_ri.wrc_snd_una
957#define wrc_snd_iss u.toe_ri.wrc_snd_iss
958#define wrc_pdid u.toe_ri.wrc_pdid
959#define wrc_scqid u.toe_ri.wrc_scqid
960#define wrc_rcqid u.toe_ri.wrc_rcqid
961#define wrc_rq_addr_32a u.toe_ri.wrc_rq_addr_32a
962#define wrc_rq_size u.toe_ri.wrc_rq_size
963#define wrc_rq_wr_idx u.toe_ri.wrc_rq_wr_idx
964#define wrc_mpaattrs u.toe_ri.wrc_mpaattrs
965#define wrc_qpcaps u.toe_ri.wrc_qpcaps
966#define wrc_mulpdu_tagged u.toe_ri.wrc_mulpdu_tagged
967#define wrc_mulpdu_untagged u.toe_ri.wrc_mulpdu_untagged
968#define wrc_ord_max u.toe_ri.wrc_ord_max
969#define wrc_ird_max u.toe_ri.wrc_ird_max
970#define wrc_ord u.toe_ri.wrc_ord
971#define wrc_ird u.toe_ri.wrc_ird
972#define wrc_markeroffset u.toe_ri.wrc_markeroffset
973#define wrc_msn_send u.toe_ri.wrc_msn_send
974#define wrc_msn_rdma_read u.toe_ri.wrc_msn_rdma_read
975#define wrc_msn_rdma_read_req u.toe_ri.wrc_msn_rdma_read_req
976#define wrc_rdma_read_req_err u.toe_ri.wrc_rdma_read_req_err
977#define wrc_ack_mode u.toe_ri.wrc_ack_mode
978#define wrc_sge_ec_credits u.toe_ri.wrc_sge_ec_credits
979#define wrc_maxiolen_tagged u.toe_ri.wrc_maxiolen_tagged
980#define wrc_maxiolen_untagged u.toe_ri.wrc_maxiolen_untagged
981#define wrc_mo u.toe_ri.wrc_mo
982
983static void print_wrc_field(char *field, unsigned int value, unsigned int size)
984{
985	switch(size) {
986	case 1:
987		printf("  1 %s: 0x%02x (%u)\n", field, value, value);
988		break;
989	case 2: {
990		unsigned short host_value = ntohs(value);
991		printf("  2 %s: 0x%04x (%u)\n", field, host_value, host_value);
992		break;
993	}
994	case 4: {
995		unsigned int host_value = ntohl(value);
996		printf("  4 %s: 0x%08x (%u)\n", field, host_value, host_value);
997		break;
998	}
999	default:
1000		printf("  unknown size %u for field %s\n", size, field);
1001	}
1002}
1003
1004#define P(field)  print_wrc_field(#field, p->wrc_ ## field, sizeof (p->wrc_ ## field))
1005
1006static void print_wrc(unsigned int wrc_idx, struct wrc *p)
1007{
1008	u32 *buf = (u32 *)p;
1009	unsigned int i, j;
1010
1011	printf("WRC STATE (raw)\n");
1012	for (i = 0; i < 32;) {
1013		printf("[%08x]:", 0x20300000 + wrc_idx * MEM_CM_WRC_SIZE + i * 4);
1014		for (j = 0; j < 8; j++) {
1015			printf(" %08x ", htonl(buf[i++]));
1016		}
1017		printf("\n");
1018	}
1019	printf("WRC BASIC\n");
1020	P(tid); P(flags); P(state); P(credits);
1021	printf("WRC IO\n");
1022	P(sge_ec); P(sge_respQ); P(port); P(ulp); P(coherency_counter);
1023	printf("WRC REASSEMBLY\n");
1024	P(frag_len); P(frag_credits); P(frag);
1025	printf("WRC TOE\n");
1026	P(aborted); P(num_tx_pages); P(max_tx_pages); P(trace_idx); P(snd_nxt);
1027	P(snd_max); P(snd_una); P(snd_iss);
1028	printf("WRC RI\n");
1029	P(pdid); P(scqid); P(rcqid); P(rq_addr_32a); P(rq_size); P(rq_wr_idx);
1030	P(mpaattrs); P(qpcaps); P(mulpdu_tagged); P(mulpdu_untagged); P(ord_max);
1031	P(ird_max); P(ord); P(ird); P(markeroffset); P(msn_send); P(msn_rdma_read);
1032	P(msn_rdma_read_req); P(rdma_read_req_err); P(ack_mode);
1033	P(sge_ec_credits); P(maxiolen_tagged); P(maxiolen_untagged); P(mo);
1034	printf("WRC BUFFERING\n");
1035	printf("  4 fbuf.pp: 0x%08x (%u)\n", htonl(p->wrc_fbuf.pp),  htonl(p->wrc_fbuf.pp));
1036	printf("  4 fbuf.cp: 0x%08x (%u)\n",  htonl(p->wrc_fbuf.cp),  htonl(p->wrc_fbuf.cp));
1037	printf("  4 fbuf.num_bytes: 0x%08x (%d)\n",  htonl(p->wrc_fbuf.num_bytes),  htonl(p->wrc_fbuf.num_bytes));
1038	printf("WRC BUFFER (raw)\n");
1039	for (i = 32; i < (FBUF_SIZE + FBUF_WRAP_SIZE) / 4;) {
1040		printf("[%08x]:", 0x20300000 + wrc_idx * MEM_CM_WRC_SIZE + i * 4);
1041		for (j = 0; j < 4; j++) {
1042			printf(" %08x%08x", htonl(buf[i++]), htonl(buf[i++]));
1043		}
1044		printf("\n");
1045	}
1046}
1047
1048#undef P
1049
1050#define P(field)  print_sizeof(#field, ##field, sizeof (p->##field))
1051
1052struct history_e {
1053	uint32_t wr_addr;
1054	uint32_t debug;
1055	uint64_t wr_flit0;
1056	uint64_t wr_flit1;
1057	uint64_t wr_flit2;
1058};
1059
1060static void print_wrc_zero(unsigned int wrc_idx, struct wrc *p)
1061{
1062	uint32_t *buf =
1063	   (uint32_t *)((unsigned long)p + FW_WR_SIZE * (2 + FW_WR_NUM));
1064	unsigned int i;
1065
1066	printf("WRC ZERO\n");
1067	printf("[%08x]:", CM_WRCONTEXT_BASE + wrc_idx * MEM_CM_WRC_SIZE +
1068	       FW_WR_SIZE * (2 + FW_WR_NUM));
1069	for (i = 0; i < 4;)
1070		printf(" %08x%08x", htonl(buf[i]), htonl(buf[i++]));
1071	printf("\n");
1072}
1073
1074static void print_wrc_history(struct wrc *p)
1075{
1076	unsigned int i, idx;
1077	struct history_e *e =
1078	    (struct history_e *)((unsigned long)p + FW_WR_SIZE *
1079				 (2 + FW_WR_NUM) + 32);
1080	printf("WRC WR HISTORY, idx %u\n", p->wrc_trace_idx);
1081	idx = p->wrc_trace_idx;
1082	for (i = 0; i < 16; i++) {
1083		printf("%02u: %08x %08x %08x%08x %08x%08x %08x%08x\n", idx,
1084		       htonl(e[idx].wr_addr), htonl(e[idx].debug),
1085		       htonl(e[idx].wr_flit0 & 0xFFFFFFFF),
1086		       htonl(e[idx].wr_flit0 >> 32),
1087		       htonl(e[idx].wr_flit1 & 0xFFFFFFFF),
1088		       htonl(e[idx].wr_flit1 >> 32),
1089		       htonl(e[idx].wr_flit2 & 0xFFFFFFFF),
1090		       htonl(e[idx].wr_flit2 >> 32));
1091		idx = (idx - 1) & 0xF;
1092	}
1093}
1094
1095static int get_wrc(int argc, char *argv[], int start_arg, const char *iff_name)
1096{
1097	struct toetool_mem_range *op;
1098	uint64_t *p;
1099	uint32_t *buf;
1100	unsigned int idx, i = 0;
1101
1102	if (argc != start_arg + 1)
1103		return -1;
1104
1105	if (get_int_arg(argv[start_arg], &idx))
1106		return -1;
1107
1108	op = malloc(sizeof(*op) + MEM_CM_WRC_SIZE);
1109	if (!op)
1110		err(1, "get_wrc: malloc failed");
1111
1112	op->cmd    = TOETOOL_GET_MEM;
1113	op->mem_id = MEM_CM;
1114	op->addr   = read_reg(iff_name, 0x28c) + CM_WRCONTEXT_OFFSET +
1115			      idx * MEM_CM_WRC_SIZE;
1116	op->len    = MEM_CM_WRC_SIZE;
1117	buf = (uint32_t *)op->buf;
1118
1119	if (doit(iff_name, op) < 0)
1120		err(1, "get_wrc");
1121
1122	/* driver manges with the data... put it back into the the FW's view
1123	 */
1124	for (p = (uint64_t *)op->buf;
1125	         p < (uint64_t *)(op->buf + MEM_CM_WRC_SIZE); p++) {
1126		uint64_t flit = *p;
1127		buf[i++] = htonl((uint32_t)(flit >> 32));
1128		buf[i++] = htonl((uint32_t)flit);
1129	}
1130
1131	print_wrc(idx, (struct wrc *)op->buf);
1132	print_wrc_zero(idx, (struct wrc *)op->buf);
1133	print_wrc_history((struct wrc *)op->buf);
1134
1135	free(op);
1136	return 0;
1137}
1138#endif
1139
1140#ifdef notyet
1141static int get_pm_page_spec(const char *s, unsigned int *page_size,
1142			    unsigned int *num_pages)
1143{
1144	char *p;
1145	unsigned long val;
1146
1147	val = strtoul(s, &p, 0);
1148	if (p == s) return -1;
1149	if (*p == 'x' && p[1]) {
1150		*num_pages = val;
1151		*page_size = strtoul(p + 1, &p, 0);
1152	} else {
1153		*num_pages = -1;
1154		*page_size = val;
1155	}
1156	*page_size <<= 10;     // KB -> bytes
1157	return *p;
1158}
1159
1160static int conf_pm(int argc, char *argv[], int start_arg, const char *iff_name)
1161{
1162	struct toetool_pm op;
1163
1164	if (argc == start_arg) {
1165	 	op.cmd = TOETOOL_GET_PM;
1166		if (doit(iff_name, &op) < 0)
1167			err(1, "read pm config");
1168		printf("%ux%uKB TX pages, %ux%uKB RX pages, %uKB total memory\n",
1169		       op.tx_num_pg, op.tx_pg_sz >> 10, op.rx_num_pg,
1170		       op.rx_pg_sz >> 10, op.pm_total >> 10);
1171		return 0;
1172	}
1173
1174	if (argc != start_arg + 2) return -1;
1175
1176	if (get_pm_page_spec(argv[start_arg], &op.tx_pg_sz, &op.tx_num_pg)) {
1177		warnx("bad parameter \"%s\"", argv[start_arg]);
1178		return -1;
1179	}
1180	if (get_pm_page_spec(argv[start_arg + 1], &op.rx_pg_sz,
1181			     &op.rx_num_pg)) {
1182		warnx("bad parameter \"%s\"", argv[start_arg + 1]);
1183		return -1;
1184	}
1185	op.cmd = TOETOOL_SET_PM;
1186	if (doit(iff_name, &op) < 0)
1187		err(1, "pm config");
1188	return 0;
1189}
1190
1191static int conf_tcam(int argc, char *argv[], int start_arg,
1192		     const char *iff_name)
1193{
1194	struct toetool_tcam op;
1195
1196	if (argc == start_arg) {
1197		op.cmd = TOETOOL_GET_TCAM;
1198		op.nfilters = 0;
1199		if (doit(iff_name, &op) < 0)
1200			err(1, "read tcam config");
1201		printf("%u total entries, %u servers, %u filters, %u routes\n",
1202		       op.tcam_size, op.nservers, op.nfilters, op.nroutes);
1203		return 0;
1204	}
1205
1206	if (argc != start_arg + 3) return -1;
1207
1208	if (get_int_arg(argv[start_arg], &op.nservers) ||
1209	    get_int_arg(argv[start_arg + 1], &op.nroutes) ||
1210	    get_int_arg(argv[start_arg + 2], &op.nfilters))
1211		return -1;
1212	op.cmd = TOETOOL_SET_TCAM;
1213	if (doit(iff_name, &op) < 0)
1214		err(1, "tcam config");
1215	return 0;
1216}
1217#endif
1218
1219#ifdef	CHELSIO_INTERNAL
1220#ifdef notyet
1221static int dump_tcam(int argc, char *argv[], int start_arg,
1222		     const char *iff_name)
1223{
1224	unsigned int nwords;
1225	struct toetool_tcam_word op;
1226
1227	if (argc != start_arg + 2) return -1;
1228
1229	if (get_int_arg(argv[start_arg], &op.addr) ||
1230	    get_int_arg(argv[start_arg + 1], &nwords))
1231		return -1;
1232	op.cmd = TOETOOL_READ_TCAM_WORD;
1233
1234	while (nwords--) {
1235		if (doit(iff_name, &op) < 0)
1236			err(1, "tcam dump");
1237
1238		printf("0x%08x: 0x%02x 0x%08x 0x%08x\n", op.addr,
1239		       op.buf[0] & 0xff, op.buf[1], op.buf[2]);
1240		op.addr++;
1241	}
1242	return 0;
1243}
1244#endif
1245static void hexdump_8b(unsigned int start, uint64_t *data, unsigned int len)
1246{
1247	int i;
1248
1249	while (len) {
1250		printf("0x%08x:", start);
1251		for (i = 0; i < 4 && len; ++i, --len)
1252			printf(" %016llx", (unsigned long long)*data++);
1253		printf("\n");
1254		start += 32;
1255	}
1256}
1257
1258static int dump_mc7(int argc, char *argv[], int start_arg,
1259		    const char *iff_name)
1260{
1261	struct ch_mem_range mem;
1262	unsigned int mem_id, addr, len;
1263
1264	if (argc != start_arg + 3) return -1;
1265
1266	if (!strcmp(argv[start_arg], "cm"))
1267		mem_id = MEM_CM;
1268	else if (!strcmp(argv[start_arg], "rx"))
1269		mem_id = MEM_PMRX;
1270	else if (!strcmp(argv[start_arg], "tx"))
1271		mem_id = MEM_PMTX;
1272	else
1273		errx(1, "unknown memory \"%s\"; must be one of \"cm\", \"tx\","
1274			" or \"rx\"", argv[start_arg]);
1275
1276	if (get_int_arg(argv[start_arg + 1], &addr) ||
1277	    get_int_arg(argv[start_arg + 2], &len))
1278		return -1;
1279
1280	mem.buf = malloc(len);
1281	if (!mem.buf)
1282		err(1, "memory dump");
1283
1284	mem.mem_id = mem_id;
1285	mem.addr   = addr;
1286	mem.len    = len;
1287
1288	if (doit(iff_name, CHELSIO_GET_MEM, &mem) < 0)
1289		err(1, "memory dump");
1290
1291	hexdump_8b(mem.addr, (uint64_t *)mem.buf, mem.len >> 3);
1292	free(mem.buf);
1293	return 0;
1294}
1295#endif
1296
1297#ifdef notyet
1298/* Max FW size is 32K including version, +4 bytes for the checksum. */
1299#define MAX_FW_IMAGE_SIZE (32768 + 4)
1300
1301static int load_fw(int argc, char *argv[], int start_arg, const char *iff_name)
1302{
1303	int fd, len;
1304	struct toetool_mem_range *op;
1305	const char *fname = argv[start_arg];
1306
1307	if (argc != start_arg + 1) return -1;
1308
1309	fd = open(fname, O_RDONLY);
1310	if (fd < 0)
1311		err(1, "load firmware");
1312
1313	op = malloc(sizeof(*op) + MAX_FW_IMAGE_SIZE + 1);
1314	if (!op)
1315		err(1, "load firmware");
1316
1317	len = read(fd, op->buf, MAX_FW_IMAGE_SIZE + 1);
1318	if (len < 0)
1319		err(1, "load firmware");
1320 	if (len > MAX_FW_IMAGE_SIZE)
1321		errx(1, "FW image too large");
1322
1323	op->cmd = TOETOOL_LOAD_FW;
1324	op->len = len;
1325
1326	if (doit(iff_name, op) < 0)
1327		err(1, "load firmware");
1328	return 0;
1329}
1330
1331
1332static int write_proto_sram(const char *fname, const char *iff_name)
1333{
1334	int i;
1335	char c;
1336	struct toetool_proto op = { .cmd = TOETOOL_SET_PROTO };
1337	uint32_t *p = op.data;
1338	FILE *fp = fopen(fname, "r");
1339
1340	if (!fp)
1341		err(1, "load protocol sram");
1342
1343	for (i = 0; i < 128; i++, p += 5) {
1344		int n = fscanf(fp, "%1x%8x%8x%8x%8x",
1345			       &p[0], &p[1], &p[2], &p[3], &p[4]);
1346		if (n != 5)
1347			errx(1, "%s: bad line %d", fname, i);
1348	}
1349	if (fscanf(fp, "%1s", &c) != EOF)
1350		errx(1, "%s: protocol sram image has too many lines", fname);
1351	fclose(fp);
1352
1353	if (doit(iff_name, &op) < 0)
1354		err(1, "load protocol sram");
1355	return 0;
1356}
1357
1358static int dump_proto_sram(const char *iff_name)
1359{
1360	int i, j;
1361	u8 buf[sizeof(struct ethtool_eeprom) + PROTO_SRAM_SIZE];
1362	struct ethtool_eeprom *ee = (struct ethtool_eeprom *)buf;
1363	u8 *p = buf + sizeof(struct ethtool_eeprom);
1364
1365	ee->cmd = ETHTOOL_GEEPROM;
1366	ee->len = PROTO_SRAM_SIZE;
1367	ee->offset = PROTO_SRAM_EEPROM_ADDR;
1368	if (ethtool_call(iff_name, ee))
1369		err(1, "show protocol sram");
1370
1371	for (i = 0; i < PROTO_SRAM_LINES; i++) {
1372		for (j = PROTO_SRAM_LINE_NIBBLES - 1; j >= 0; j--) {
1373			int nibble_idx = i * PROTO_SRAM_LINE_NIBBLES + j;
1374			u8 nibble = p[nibble_idx / 2];
1375
1376			if (nibble_idx & 1)
1377				nibble >>= 4;
1378			else
1379				nibble &= 0xf;
1380			printf("%x", nibble);
1381		}
1382		putchar('\n');
1383	}
1384	return 0;
1385}
1386
1387static int proto_sram_op(int argc, char *argv[], int start_arg,
1388			 const char *iff_name)
1389{
1390	if (argc == start_arg + 1)
1391		return write_proto_sram(argv[start_arg], iff_name);
1392	if (argc == start_arg)
1393		return dump_proto_sram(iff_name);
1394	return -1;
1395}
1396#endif
1397
1398static int dump_qset_params(const char *iff_name)
1399{
1400	struct ch_qset_params qp;
1401
1402	qp.qset_idx = 0;
1403
1404	while (doit(iff_name, CHELSIO_GET_QSET_PARAMS, &qp) == 0) {
1405		if (!qp.qset_idx)
1406			printf("Qnum   TxQ0   TxQ1   TxQ2   RspQ   RxQ0   RxQ1"
1407			       "  Cong  Intr Lat   Rx Mode\n");
1408		printf("%4u %6u %6u %6u %6u %6u %6u %5u %9u   %s    \n",
1409		       qp.qset_idx,
1410		       qp.txq_size[0], qp.txq_size[1], qp.txq_size[2],
1411		       qp.rspq_size, qp.fl_size[0], qp.fl_size[1],
1412		       qp.cong_thres, qp.intr_lat,
1413		       qp.polling ? "Polling" : "Interrupt");
1414		qp.qset_idx++;
1415	}
1416	if (!qp.qset_idx || (errno && errno != EINVAL))
1417		err(1, "get qset parameters");
1418	return 0;
1419}
1420
1421static int qset_config(int argc, char *argv[], int start_arg,
1422		       const char *iff_name)
1423{
1424	struct ch_qset_params qp;
1425
1426	if (argc == start_arg)
1427		return dump_qset_params(iff_name);
1428
1429	if (get_int_arg(argv[start_arg++], &qp.qset_idx))
1430		return -1;
1431
1432	qp.txq_size[0] = qp.txq_size[1] = qp.txq_size[2] = -1;
1433	qp.fl_size[0] = qp.fl_size[1] = qp.rspq_size = -1;
1434	qp.polling = qp.intr_lat = qp.cong_thres = -1;
1435
1436	while (start_arg + 2 <= argc) {
1437		int32_t *param = NULL;
1438
1439		if (!strcmp(argv[start_arg], "txq0"))
1440			param = &qp.txq_size[0];
1441		else if (!strcmp(argv[start_arg], "txq1"))
1442			param = &qp.txq_size[1];
1443		else if (!strcmp(argv[start_arg], "txq2"))
1444			param = &qp.txq_size[2];
1445		else if (!strcmp(argv[start_arg], "rspq"))
1446			param = &qp.rspq_size;
1447		else if (!strcmp(argv[start_arg], "fl0"))
1448			param = &qp.fl_size[0];
1449		else if (!strcmp(argv[start_arg], "fl1"))
1450			param = &qp.fl_size[1];
1451		else if (!strcmp(argv[start_arg], "lat"))
1452			param = &qp.intr_lat;
1453		else if (!strcmp(argv[start_arg], "cong"))
1454			param = &qp.cong_thres;
1455		else if (!strcmp(argv[start_arg], "mode"))
1456			param = &qp.polling;
1457		else
1458			errx(1, "unknown qset parameter \"%s\"\n"
1459			     "allowed parameters are \"txq0\", \"txq1\", "
1460			     "\"txq2\", \"rspq\", \"fl0\", \"fl1\", \"lat\", "
1461			     "\"cong\", \"mode\' and \"lro\"", argv[start_arg]);
1462
1463		start_arg++;
1464
1465		if (param == &qp.polling) {
1466			if (!strcmp(argv[start_arg], "irq"))
1467				qp.polling = 0;
1468			else if (!strcmp(argv[start_arg], "polling"))
1469				qp.polling = 1;
1470			else
1471				errx(1, "illegal qset mode \"%s\"\n"
1472				     "known modes are \"irq\" and \"polling\"",
1473				     argv[start_arg]);
1474		} else if (get_int_arg(argv[start_arg], (uint32_t *)param))
1475			return -1;
1476		start_arg++;
1477	}
1478	if (start_arg != argc)
1479		errx(1, "unknown parameter %s", argv[start_arg]);
1480
1481#if 0
1482	printf("%4u %6d %6d %6d %6d %6d %6d %5d %9d   %d\n", op.qset_idx,
1483	       op.txq_size[0], op.txq_size[1], op.txq_size[2],
1484	       op.rspq_size, op.fl_size[0], op.fl_size[1], op.cong_thres,
1485	       op.intr_lat, op.polling);
1486#endif
1487	if (doit(iff_name, CHELSIO_SET_QSET_PARAMS, &qp) < 0)
1488		err(1, "set qset parameters");
1489
1490	return 0;
1491}
1492
1493static int qset_num_config(int argc, char *argv[], int start_arg,
1494			   const char *iff_name)
1495{
1496	struct ch_reg reg;
1497
1498	if (argc == start_arg) {
1499		if (doit(iff_name, CHELSIO_GET_QSET_NUM, &reg) < 0)
1500			err(1, "get qsets");
1501		printf("%u\n", reg.val);
1502		return 0;
1503	}
1504
1505	if (argc != start_arg + 1)
1506		return -1;
1507	if (get_int_arg(argv[start_arg], &reg.val))
1508		return -1;
1509
1510	if (doit(iff_name, CHELSIO_SET_QSET_NUM, &reg) < 0)
1511		err(1, "set qsets");
1512	return 0;
1513}
1514
1515/*
1516 * Parse a string containing an IP address with an optional network prefix.
1517 */
1518static int parse_ipaddr(const char *s, uint32_t *addr, uint32_t *mask)
1519{
1520	char *p, *slash;
1521	struct in_addr ia;
1522
1523	*mask = 0xffffffffU;
1524	slash = strchr(s, '/');
1525	if (slash)
1526		*slash = 0;
1527	if (!inet_aton(s, &ia)) {
1528		if (slash)
1529			*slash = '/';
1530		*addr = 0;
1531		return -1;
1532	}
1533	*addr = ntohl(ia.s_addr);
1534	if (slash) {
1535		unsigned int prefix = strtoul(slash + 1, &p, 10);
1536
1537		*slash = '/';
1538		if (p == slash + 1 || *p || prefix > 32)
1539			return -1;
1540		*mask <<= (32 - prefix);
1541	}
1542	return 0;
1543}
1544
1545/*
1546 * Parse a string containing a value and an optional colon separated mask.
1547 */
1548static int parse_val_mask_param(const char *s, uint32_t *val, uint32_t *mask)
1549{
1550	char *p;
1551
1552	*mask = 0xffffffffU;
1553	*val = strtoul(s, &p, 0);
1554	if (p == s)
1555		return -1;
1556	if (*p == ':' && p[1])
1557		*mask = strtoul(p + 1, &p, 0);
1558	return *p ? -1 : 0;
1559}
1560
1561static int parse_trace_param(const char *s, uint32_t *val, uint32_t *mask)
1562{
1563	return strchr(s, '.') ? parse_ipaddr(s, val, mask) :
1564				parse_val_mask_param(s, val, mask);
1565}
1566
1567static int trace_config(int argc, char *argv[], int start_arg,
1568			const char *iff_name)
1569{
1570	uint32_t val, mask;
1571	struct ch_trace trace;
1572
1573	if (argc == start_arg)
1574		return -1;
1575
1576	memset(&trace, 0, sizeof(trace));
1577	if (!strcmp(argv[start_arg], "tx"))
1578		trace.config_tx = 1;
1579	else if (!strcmp(argv[start_arg], "rx"))
1580		trace.config_rx = 1;
1581	else if (!strcmp(argv[start_arg], "all"))
1582		trace.config_tx = trace.config_rx = 1;
1583	else
1584		errx(1, "bad trace filter \"%s\"; must be one of \"rx\", "
1585		     "\"tx\" or \"all\"", argv[start_arg]);
1586
1587	if (argc == ++start_arg)
1588		return -1;
1589	if (!strcmp(argv[start_arg], "on")) {
1590		trace.trace_tx = trace.config_tx;
1591		trace.trace_rx = trace.config_rx;
1592	} else if (strcmp(argv[start_arg], "off"))
1593		errx(1, "bad argument \"%s\"; must be \"on\" or \"off\"",
1594		     argv[start_arg]);
1595
1596	start_arg++;
1597	if (start_arg < argc && !strcmp(argv[start_arg], "not")) {
1598		trace.invert_match = 1;
1599		start_arg++;
1600	}
1601
1602	while (start_arg + 2 <= argc) {
1603		int ret = parse_trace_param(argv[start_arg + 1], &val, &mask);
1604
1605		if (!strcmp(argv[start_arg], "interface")) {
1606			trace.intf = val;
1607			trace.intf_mask = mask;
1608		} else if (!strcmp(argv[start_arg], "sip")) {
1609			trace.sip = val;
1610			trace.sip_mask = mask;
1611		} else if (!strcmp(argv[start_arg], "dip")) {
1612			trace.dip = val;
1613			trace.dip_mask = mask;
1614		} else if (!strcmp(argv[start_arg], "sport")) {
1615			trace.sport = val;
1616			trace.sport_mask = mask;
1617		} else if (!strcmp(argv[start_arg], "dport")) {
1618			trace.dport = val;
1619			trace.dport_mask = mask;
1620		} else if (!strcmp(argv[start_arg], "vlan")) {
1621			trace.vlan = val;
1622			trace.vlan_mask = mask;
1623		} else if (!strcmp(argv[start_arg], "proto")) {
1624			trace.proto = val;
1625			trace.proto_mask = mask;
1626		} else
1627			errx(1, "unknown trace parameter \"%s\"\n"
1628			     "known parameters are \"interface\", \"sip\", "
1629			     "\"dip\", \"sport\", \"dport\", \"vlan\", "
1630			     "\"proto\"", argv[start_arg]);
1631		if (ret < 0)
1632			errx(1, "bad parameter \"%s\"", argv[start_arg + 1]);
1633		start_arg += 2;
1634	}
1635	if (start_arg != argc)
1636		errx(1, "unknown parameter \"%s\"", argv[start_arg]);
1637
1638#if 0
1639	printf("sip: %x:%x, dip: %x:%x, sport: %x:%x, dport: %x:%x, "
1640	       "interface: %x:%x, vlan: %x:%x, tx_config: %u, rx_config: %u, "
1641	       "invert: %u, tx_enable: %u, rx_enable: %u\n", op.sip,
1642	       op.sip_mask, op.dip, op.dip_mask, op.sport, op.sport_mask,
1643	       op.dport, op.dport_mask, op.intf, op.intf_mask, op.vlan,
1644	       op.vlan_mask, op.config_tx, op.config_rx, op.invert_match,
1645	       op.trace_tx, op.trace_rx);
1646#endif
1647	if (doit(iff_name, CHELSIO_SET_TRACE_FILTER, &trace) < 0)
1648		err(1, "trace");
1649	return 0;
1650}
1651
1652#ifdef notyet
1653static int t1_powersave(int argc, char *argv[], int start_arg,
1654		     const char *iff_name)
1655{
1656	struct toetool_t1powersave op = {
1657		.cmd  = TOETOOL_T1POWERSAVE,
1658		.mode = 0
1659	};
1660
1661	if (argc == start_arg)
1662		op.mode = 2; /* Check powersave mode */
1663
1664	else if (argc == start_arg + 1) {
1665		if (strcmp(argv[start_arg], "on") == 0)
1666			op.mode = 1;
1667		else if (strcmp(argv[start_arg], "off") == 0)
1668			op.mode = 0;
1669		else {
1670			warnx("bad parameter \"%s\"", argv[start_arg]);
1671			return -1;
1672		}
1673	} else {
1674		errx(1, "too many arguments");
1675		return -1;
1676	}
1677
1678	if (doit(iff_name, &op) < 0)
1679		err(1, "t1powersave");
1680
1681	if (op.mode & 2)
1682		printf("t1powersave is %s\n", (op.mode & 1) ? "on" : "off");
1683
1684	return 0;
1685}
1686#endif
1687
1688static int pktsched(int argc, char *argv[], int start_arg, const char *iff_name)
1689{
1690	struct ch_pktsched_params pktsched;
1691	unsigned int idx, min = -1, max, binding = -1;
1692
1693	if (!strcmp(argv[start_arg], "port")) {
1694		if (argc != start_arg + 4)
1695			return -1;
1696		if (get_int_arg(argv[start_arg + 1], &idx) ||
1697		    get_int_arg(argv[start_arg + 2], &min) ||
1698		    get_int_arg(argv[start_arg + 3], &max))
1699			return -1;
1700		pktsched.sched = 0;
1701	} else if (!strcmp(argv[start_arg], "tunnelq")) {
1702		if (argc != start_arg + 4)
1703			return -1;
1704		if (get_int_arg(argv[start_arg + 1], &idx) ||
1705		    get_int_arg(argv[start_arg + 2], &max) ||
1706		    get_int_arg(argv[start_arg + 3], &binding))
1707			return -1;
1708		pktsched.sched = 1;
1709	} else
1710		errx(1, "unknown scheduler \"%s\"; must be one of \"port\""
1711			" or \"tunnelq\"", argv[start_arg]);
1712
1713	pktsched.idx = idx;
1714	pktsched.min = min;
1715	pktsched.max = max;
1716	pktsched.binding = binding;
1717	if (doit(iff_name, CHELSIO_SET_PKTSCHED, &pktsched) < 0)
1718		 err(1, "pktsched");
1719
1720	return 0;
1721}
1722
1723int main(int argc, char *argv[])
1724{
1725	int r = -1;
1726	const char *iff_name;
1727
1728	progname = argv[0];
1729
1730	if (argc == 2) {
1731		if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
1732			usage(stdout);
1733		if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) {
1734			printf("%s version %s\n", PROGNAME, VERSION);
1735			printf("%s\n", COPYRIGHT);
1736			exit(0);
1737		}
1738	}
1739
1740	if (argc < 3) usage(stderr);
1741
1742	iff_name = argv[1];
1743	if (!strcmp(argv[2], "reg"))
1744		r = register_io(argc, argv, 3, iff_name);
1745	else if (!strcmp(argv[2], "mdio"))
1746		r = mdio_io(argc, argv, 3, iff_name);
1747#ifdef notyet
1748	else if (!strcmp(argv[2], "tpi"))
1749		r = tpi_io(argc, argv, 3, iff_name);
1750	else if (!strcmp(argv[2], "up"))
1751		r = device_up(argc, argv, 3, iff_name);
1752	else if (!strcmp(argv[2], "mtus"))
1753		r = mtu_tab_op(argc, argv, 3, iff_name);
1754	else if (!strcmp(argv[2], "pm"))
1755		r = conf_pm(argc, argv, 3, iff_name);
1756	else if (!strcmp(argv[2], "tcam"))
1757		r = conf_tcam(argc, argv, 3, iff_name);
1758	else if (!strcmp(argv[2], "tcb"))
1759		r = get_tcb(argc, argv, 3, iff_name);
1760#ifdef WRC
1761	else if (!strcmp(argv[2], "wrc"))
1762		r = get_wrc(argc, argv, 3, iff_name);
1763#endif
1764#endif
1765	else if (!strcmp(argv[2], "regdump"))
1766		r = dump_regs(argc, argv, 3, iff_name);
1767#ifdef CHELSIO_INTERNAL
1768	else if (!strcmp(argv[2], "memdump"))
1769		r = dump_mc7(argc, argv, 3, iff_name);
1770	else if (!strcmp(argv[2], "meminfo"))
1771		r = meminfo(argc, argv, 3, iff_name);
1772	else if (!strcmp(argv[2], "context"))
1773		r = get_sge_context(argc, argv, 3, iff_name);
1774	else if (!strcmp(argv[2], "desc"))
1775		r = get_sge_desc(argc, argv, 3, iff_name);
1776#endif
1777	else if (!strcmp(argv[2], "qset"))
1778		r = qset_config(argc, argv, 3, iff_name);
1779	else if (!strcmp(argv[2], "qsets"))
1780		r = qset_num_config(argc, argv, 3, iff_name);
1781	else if (!strcmp(argv[2], "trace"))
1782		r = trace_config(argc, argv, 3, iff_name);
1783#ifdef notyet
1784	else if (!strcmp(argv[2], "tcamdump"))
1785		r = dump_tcam(argc, argv, 3, iff_name);
1786	else if (!strcmp(argv[2], "loadfw"))
1787		r = load_fw(argc, argv, 3, iff_name);
1788	else if (!strcmp(argv[2], "proto"))
1789		r = proto_sram_op(argc, argv, 3, iff_name);
1790	else if (!strcmp(argv[2], "t1powersave"))
1791		r = t1_powersave(argc, argv, 3, iff_name);
1792#endif
1793	else if (!strcmp(argv[2], "pktsched"))
1794		r = pktsched(argc, argv, 3, iff_name);
1795	if (r == -1)
1796		usage(stderr);
1797	return 0;
1798}
1799