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