]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/mlx5tool/mlx5tool.c
Add two missing eventhandler.h headers
[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 <sys/mman.h>
32 #include <sys/stat.h>
33 #include <dev/mlx5/mlx5io.h>
34 #include <ctype.h>
35 #include <err.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <paths.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43
44 /* stolen from pciconf.c: parsesel() */
45 static int
46 parse_pci_addr(const char *addrstr, struct mlx5_tool_addr *addr)
47 {
48         char *eppos;
49         unsigned long selarr[4];
50         int i;
51
52         if (addrstr == NULL) {
53                 warnx("no pci address specified");
54                 return (1);
55         }
56         if (strncmp(addrstr, "pci", 3) == 0) {
57                 addrstr += 3;
58                 i = 0;
59                 while (isdigit(*addrstr) && i < 4) {
60                         selarr[i++] = strtoul(addrstr, &eppos, 10);
61                         addrstr = eppos;
62                         if (*addrstr == ':')
63                                 addrstr++;
64                 }
65                 if (i > 0 && *addrstr == '\0') {
66                         addr->func = (i > 2) ? selarr[--i] : 0;
67                         addr->slot = (i > 0) ? selarr[--i] : 0;
68                         addr->bus = (i > 0) ? selarr[--i] : 0;
69                         addr->domain = (i > 0) ? selarr[--i] : 0;
70                         return (0);
71                 }
72         }
73         warnx("invalid pci address %s", addrstr);
74         return (1);
75 }
76
77 static int
78 mlx5tool_save_dump(int ctldev, const struct mlx5_tool_addr *addr,
79     const char *dumpname)
80 {
81         struct mlx5_fwdump_get fdg;
82         struct mlx5_fwdump_reg *rege;
83         FILE *dump;
84         size_t cnt;
85         int error, res;
86
87         if (dumpname == NULL)
88                 dump = stdout;
89         else
90                 dump = fopen(dumpname, "w");
91         if (dump == NULL) {
92                 warn("open %s", dumpname);
93                 return (1);
94         }
95         res = 1;
96         memset(&fdg, 0, sizeof(fdg));
97         fdg.devaddr = *addr;
98         error = ioctl(ctldev, MLX5_FWDUMP_GET, &fdg);
99         if (error != 0) {
100                 warn("MLX5_FWDUMP_GET dumpsize");
101                 goto out;
102         }
103         rege = calloc(fdg.reg_filled, sizeof(*rege));
104         if (rege == NULL) {
105                 warn("alloc rege");
106                 goto out;
107         }
108         fdg.buf = rege;
109         fdg.reg_cnt = fdg.reg_filled;
110         error = ioctl(ctldev, MLX5_FWDUMP_GET, &fdg);
111         if (error != 0) {
112                 if (errno == ENOENT)
113                         warnx("no dump recorded");
114                 else
115                         warn("MLX5_FWDUMP_GET dump fetch");
116                 goto out;
117         }
118         for (cnt = 0; cnt < fdg.reg_cnt; cnt++, rege++)
119                 fprintf(dump, "0x%08x\t0x%08x\n", rege->addr, rege->val);
120         res = 0;
121 out:
122         if (dump != stdout)
123                 fclose(dump);
124         return (res);
125 }
126
127 static int
128 mlx5tool_dump_reset(int ctldev, const struct mlx5_tool_addr *addr)
129 {
130
131         if (ioctl(ctldev, MLX5_FWDUMP_RESET, addr) == -1) {
132                 warn("MLX5_FWDUMP_RESET");
133                 return (1);
134         }
135         return (0);
136 }
137
138 static int
139 mlx5tool_dump_force(int ctldev, const struct mlx5_tool_addr *addr)
140 {
141
142         if (ioctl(ctldev, MLX5_FWDUMP_FORCE, addr) == -1) {
143                 warn("MLX5_FWDUMP_FORCE");
144                 return (1);
145         }
146         return (0);
147 }
148
149 static int
150 mlx5tool_fw_update(int ctldev, const struct mlx5_tool_addr *addr,
151     const char *img_fw_path)
152 {
153         struct stat st;
154         struct mlx5_fw_update fwup;
155         int error, fd, res;
156
157         res = 0;
158         fd = open(img_fw_path, O_RDONLY);
159         if (fd == -1) {
160                 warn("Unable to open %s", img_fw_path);
161                 res = 1;
162                 goto close_fd;
163         }
164         error = fstat(fd, &st);
165         if (error != 0) {
166                 warn("Unable to stat %s", img_fw_path);
167                 res = 1;
168                 goto close_fd;
169         }
170         memset(&fwup, 0, sizeof(fwup));
171         memcpy(&fwup.devaddr, addr, sizeof(fwup.devaddr));
172         fwup.img_fw_data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE,
173             fd, 0);
174         if (fwup.img_fw_data == MAP_FAILED) {
175                 warn("Unable to mmap %s", img_fw_path);
176                 res = 1;
177                 goto close_fd;
178         }
179         fwup.img_fw_data_len = st.st_size;
180
181         error = ioctl(ctldev, MLX5_FW_UPDATE, &fwup);
182         if (error == -1) {
183                 warn("MLX5_FW_UPDATE");
184         }
185
186         munmap(fwup.img_fw_data, st.st_size);
187 close_fd:
188         close(fd);
189         return (res);
190 }
191
192 static int
193 mlx5tool_fw_reset(int ctldev, const struct mlx5_tool_addr *addr)
194 {
195
196         if (ioctl(ctldev, MLX5_FW_RESET, addr) == -1) {
197                 warn("MLX5_FW_RESET");
198                 return (1);
199         }
200         return (0);
201 }
202
203 static void
204 usage(void)
205 {
206
207         fprintf(stderr,
208             "Usage: mlx5tool -d pci<d:b:s:f> [-w -o dump.file | -r |"
209             " -e | -f fw.mfa2 | -z]\n");
210         fprintf(stderr, "\t-w - write firmware dump to the specified file\n");
211         fprintf(stderr, "\t-r - reset dump\n");
212         fprintf(stderr, "\t-e - force dump\n");
213         fprintf(stderr, "\t-f fw.img - flash firmware from fw.img\n");
214         fprintf(stderr, "\t-z - initiate firmware reset\n");
215         exit(1);
216 }
217
218 enum mlx5_action {
219         ACTION_DUMP_GET,
220         ACTION_DUMP_RESET,
221         ACTION_DUMP_FORCE,
222         ACTION_FW_UPDATE,
223         ACTION_FW_RESET,
224         ACTION_NONE,
225 };
226
227 int
228 main(int argc, char *argv[])
229 {
230         struct mlx5_tool_addr addr;
231         char *dumpname;
232         char *addrstr;
233         char *img_fw_path;
234         int c, ctldev, res;
235         enum mlx5_action act;
236
237         act = ACTION_NONE;
238         addrstr = NULL;
239         dumpname = NULL;
240         img_fw_path = NULL;
241         while ((c = getopt(argc, argv, "d:ef:ho:rwz")) != -1) {
242                 switch (c) {
243                 case 'd':
244                         addrstr = optarg;
245                         break;
246                 case 'w':
247                         if (act != ACTION_NONE)
248                                 usage();
249                         act = ACTION_DUMP_GET;
250                         break;
251                 case 'e':
252                         if (act != ACTION_NONE)
253                                 usage();
254                         act = ACTION_DUMP_FORCE;
255                         break;
256                 case 'o':
257                         dumpname = optarg;
258                         break;
259                 case 'r':
260                         if (act != ACTION_NONE)
261                                 usage();
262                         act = ACTION_DUMP_RESET;
263                         break;
264                 case 'f':
265                         if (act != ACTION_NONE)
266                                 usage();
267                         act = ACTION_FW_UPDATE;
268                         img_fw_path = optarg;
269                         break;
270                 case 'z':
271                         if (act != ACTION_NONE)
272                                 usage();
273                         act = ACTION_FW_RESET;
274                         break;
275                 case 'h':
276                 default:
277                         usage();
278                 }
279         }
280         if (act == ACTION_NONE || (dumpname != NULL &&
281             act != ACTION_DUMP_GET) || (img_fw_path != NULL &&
282             act != ACTION_FW_UPDATE))
283                 usage();
284         if (parse_pci_addr(addrstr, &addr) != 0)
285                 exit(1);
286
287         ctldev = open(MLX5_DEV_PATH, O_RDWR);
288         if (ctldev == -1)
289                 err(1, "open "MLX5_DEV_PATH);
290         switch (act) {
291         case ACTION_DUMP_GET:
292                 res = mlx5tool_save_dump(ctldev, &addr, dumpname);
293                 break;
294         case ACTION_DUMP_RESET:
295                 res = mlx5tool_dump_reset(ctldev, &addr);
296                 break;
297         case ACTION_DUMP_FORCE:
298                 res = mlx5tool_dump_force(ctldev, &addr);
299                 break;
300         case ACTION_FW_UPDATE:
301                 res = mlx5tool_fw_update(ctldev, &addr, img_fw_path);
302                 break;
303         case ACTION_FW_RESET:
304                 res = mlx5tool_fw_reset(ctldev, &addr);
305                 break;
306         default:
307                 res = 0;
308                 break;
309         }
310         close(ctldev);
311         exit(res);
312 }