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