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