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