]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/mlx5tool/mlx5tool.c
MFV 337214:
[FreeBSD/FreeBSD.git] / usr.sbin / mlx5tool / mlx5tool.c
1 /*-
2  * Copyright (c) 2018, Mellanox Technologies, Ltd.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <sys/param.h>
30 #include <sys/ioctl.h>
31 #include <dev/mlx5/mlx5io.h>
32 #include <ctype.h>
33 #include <err.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <paths.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 /* stolen from pciconf.c: parsesel() */
43 static int
44 parse_pci_addr(const char *addrstr, struct mlx5_fwdump_addr *addr)
45 {
46         char *eppos;
47         unsigned long selarr[4];
48         int i;
49
50         if (addrstr == NULL) {
51                 warnx("no pci address specified");
52                 return (1);
53         }
54         if (strncmp(addrstr, "pci", 3) == 0) {
55                 addrstr += 3;
56                 i = 0;
57                 while (isdigit(*addrstr) && i < 4) {
58                         selarr[i++] = strtoul(addrstr, &eppos, 10);
59                         addrstr = eppos;
60                         if (*addrstr == ':')
61                                 addrstr++;
62                 }
63                 if (i > 0 && *addrstr == '\0') {
64                         addr->func = (i > 2) ? selarr[--i] : 0;
65                         addr->slot = (i > 0) ? selarr[--i] : 0;
66                         addr->bus = (i > 0) ? selarr[--i] : 0;
67                         addr->domain = (i > 0) ? selarr[--i] : 0;
68                         return (0);
69                 }
70         }
71         warnx("invalid pci address %s", addrstr);
72         return (1);
73 }
74
75 static int
76 mlx5tool_save_dump(int ctldev, const struct mlx5_fwdump_addr *addr,
77     const char *dumpname)
78 {
79         struct mlx5_fwdump_get fdg;
80         struct mlx5_fwdump_reg *rege;
81         FILE *dump;
82         size_t cnt;
83         int error, res;
84
85         if (dumpname == NULL)
86                 dump = stdout;
87         else
88                 dump = fopen(dumpname, "w");
89         if (dump == NULL) {
90                 warn("open %s", dumpname);
91                 return (1);
92         }
93         res = 1;
94         memset(&fdg, 0, sizeof(fdg));
95         fdg.devaddr = *addr;
96         error = ioctl(ctldev, MLX5_FWDUMP_GET, &fdg);
97         if (error != 0) {
98                 warn("MLX5_FWDUMP_GET dumpsize");
99                 goto out;
100         }
101         rege = calloc(fdg.reg_filled, sizeof(*rege));
102         if (rege == NULL) {
103                 warn("alloc rege");
104                 goto out;
105         }
106         fdg.buf = rege;
107         fdg.reg_cnt = fdg.reg_filled;
108         error = ioctl(ctldev, MLX5_FWDUMP_GET, &fdg);
109         if (error != 0) {
110                 if (errno == ENOENT)
111                         warnx("no dump recorded");
112                 else
113                         warn("MLX5_FWDUMP_GET dump fetch");
114                 goto out;
115         }
116         for (cnt = 0; cnt < fdg.reg_cnt; cnt++, rege++)
117                 fprintf(dump, "0x%08x\t0x%08x\n", rege->addr, rege->val);
118         res = 0;
119 out:
120         if (dump != stdout)
121                 fclose(dump);
122         return (res);
123 }
124
125 static int
126 mlx5tool_dump_reset(int ctldev, const struct mlx5_fwdump_addr *addr)
127 {
128
129         if (ioctl(ctldev, MLX5_FWDUMP_RESET, addr) == -1) {
130                 warn("MLX5_FWDUMP_RESET");
131                 return (1);
132         }
133         return (0);
134 }
135
136 static int
137 mlx5tool_dump_force(int ctldev, const struct mlx5_fwdump_addr *addr)
138 {
139
140         if (ioctl(ctldev, MLX5_FWDUMP_FORCE, addr) == -1) {
141                 warn("MLX5_FWDUMP_FORCE");
142                 return (1);
143         }
144         return (0);
145 }
146
147 static void
148 usage(void)
149 {
150
151         fprintf(stderr,
152             "Usage: mlx5tool -d pci<d:b:s:f> [-w -o dump.file | -r | -e]\n");
153         fprintf(stderr, "\t-w - write firmware dump to the specified file\n");
154         fprintf(stderr, "\t-r - reset dump\n");
155         fprintf(stderr, "\t-e - force dump\n");
156         exit(1);
157 }
158
159 enum mlx5_action {
160         ACTION_DUMP_GET,
161         ACTION_DUMP_RESET,
162         ACTION_DUMP_FORCE,
163         ACTION_NONE,
164 };
165
166 int
167 main(int argc, char *argv[])
168 {
169         struct mlx5_fwdump_addr addr;
170         char *dumpname;
171         char *addrstr;
172         int c, ctldev, res;
173         enum mlx5_action act;
174
175         act = ACTION_NONE;
176         addrstr = NULL;
177         dumpname = NULL;
178         while ((c = getopt(argc, argv, "d:eho:rw")) != -1) {
179                 switch (c) {
180                 case 'd':
181                         addrstr = optarg;
182                         break;
183                 case 'w':
184                         act = ACTION_DUMP_GET;
185                         break;
186                 case 'e':
187                         act= ACTION_DUMP_FORCE;
188                         break;
189                 case 'o':
190                         dumpname = optarg;
191                         break;
192                 case 'r':
193                         act = ACTION_DUMP_RESET;
194                         break;
195                 case 'h':
196                 default:
197                         usage();
198                 }
199         }
200         if (act == ACTION_NONE || (dumpname != NULL && act != ACTION_DUMP_GET))
201                 usage();
202         if (parse_pci_addr(addrstr, &addr) != 0)
203                 exit(1);
204
205         ctldev = open(MLX5_DEV_PATH, O_RDWR);
206         if (ctldev == -1)
207                 err(1, "open "MLX5_DEV_PATH);
208         switch (act) {
209         case ACTION_DUMP_GET:
210                 res = mlx5tool_save_dump(ctldev, &addr, dumpname);
211                 break;
212         case ACTION_DUMP_RESET:
213                 res = mlx5tool_dump_reset(ctldev, &addr);
214                 break;
215         case ACTION_DUMP_FORCE:
216                 res = mlx5tool_dump_force(ctldev, &addr);
217                 break;
218         default:
219                 res = 0;
220                 break;
221         }
222         close(ctldev);
223         exit(res);
224 }