]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/mlx5tool/mlx5tool.c
MFS r353184, r353186, r353188, r353190, r353192, r353194, r353196, r353198,
[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 #define MLX5_EEPROM_HIGH_PAGE_OFFSET            128
204 #define MLX5_EEPROM_PAGE_LENGTH                 256
205
206 static void
207 mlx5tool_eeprom_print(struct mlx5_eeprom_get *eeprom_info)
208 {
209         int index_in_row, line_length, row;
210         size_t byte_to_write;
211
212         byte_to_write = 0;
213         line_length = 16;
214
215         printf("\nOffset\t\tValues\n");
216         printf("------\t\t------");
217         while (byte_to_write < eeprom_info->eeprom_info_out_len) {
218                 printf("\n0x%04zX\t\t", byte_to_write);
219                 for (index_in_row = 0; index_in_row < line_length;
220                     index_in_row++) {
221                         printf("%02X ",
222                             ((uint8_t *)eeprom_info->eeprom_info_buf)[
223                             byte_to_write]);
224                         byte_to_write++;
225                 }
226         }
227
228         if (eeprom_info->eeprom_info_page_valid) {
229                 row = MLX5_EEPROM_HIGH_PAGE_OFFSET;
230                 printf("\n\nUpper Page 0x03\n");
231                 printf("\nOffset\t\tValues\n");
232                 printf("------\t\t------");
233                 for (row = MLX5_EEPROM_HIGH_PAGE_OFFSET;
234                     row < MLX5_EEPROM_PAGE_LENGTH;) {
235                         printf("\n0x%04X\t\t", row);
236                         for (index_in_row = 0;
237                              index_in_row < line_length;
238                              index_in_row++) {
239                                 printf("%02X ",
240                                     ((uint8_t *)eeprom_info->
241                                     eeprom_info_buf)[byte_to_write]);
242                                 byte_to_write++;
243                                 row++;
244                         }
245                 }
246         }
247         printf("\n");
248 }
249
250 static int
251 mlx5tool_get_eeprom_info(int ctldev, const struct mlx5_tool_addr *addr)
252 {
253         struct mlx5_eeprom_get eeprom_info;
254         int error;
255
256         memset(&eeprom_info, 0, sizeof(eeprom_info));
257         eeprom_info.devaddr = *addr;
258
259         error = ioctl(ctldev, MLX5_EEPROM_GET, &eeprom_info);
260         if (error != 0) {
261                 warn("MLX5_EEPROM_GET");
262                 return (error);
263         }
264         eeprom_info.eeprom_info_buf =
265             malloc(eeprom_info.eeprom_info_out_len + MLX5_EEPROM_PAGE_LENGTH);
266         if (eeprom_info.eeprom_info_buf == NULL) {
267                 warn("alloc eeprom_info.eeprom_info_buf ");
268                 return (ENOMEM);
269         }
270         error = ioctl(ctldev, MLX5_EEPROM_GET, &eeprom_info);
271         if (error != 0) {
272                 warn("MLX5_EEPROM_GET");
273                 free(eeprom_info.eeprom_info_buf);
274                 return (error);
275         }
276
277         mlx5tool_eeprom_print(&eeprom_info);
278
279         free(eeprom_info.eeprom_info_buf);
280         return (0);
281 }
282
283 static void
284 usage(void)
285 {
286
287         fprintf(stderr,
288             "Usage: mlx5tool -d pci<d:b:s:f> [-w -o dump.file | -r |"
289             " -e | -f fw.mfa2 | -z]\n");
290         fprintf(stderr, "\t-w - write firmware dump to the specified file\n");
291         fprintf(stderr, "\t-r - reset dump\n");
292         fprintf(stderr, "\t-E - get eeprom info\n");
293         fprintf(stderr, "\t-e - force dump\n");
294         fprintf(stderr, "\t-f fw.img - flash firmware from fw.img\n");
295         fprintf(stderr, "\t-z - initiate firmware reset\n");
296         exit(1);
297 }
298
299 enum mlx5_action {
300         ACTION_DUMP_GET,
301         ACTION_DUMP_RESET,
302         ACTION_DUMP_FORCE,
303         ACTION_FW_UPDATE,
304         ACTION_FW_RESET,
305         ACTION_GET_EEPROM_INFO,
306         ACTION_NONE,
307 };
308
309 int
310 main(int argc, char *argv[])
311 {
312         struct mlx5_tool_addr addr;
313         char *dumpname;
314         char *addrstr;
315         char *img_fw_path;
316         int c, ctldev, res;
317         enum mlx5_action act;
318
319         act = ACTION_NONE;
320         addrstr = NULL;
321         dumpname = NULL;
322         img_fw_path = NULL;
323         while ((c = getopt(argc, argv, "d:Eef:ho:rwz")) != -1) {
324                 switch (c) {
325                 case 'd':
326                         addrstr = optarg;
327                         break;
328                 case 'w':
329                         if (act != ACTION_NONE)
330                                 usage();
331                         act = ACTION_DUMP_GET;
332                         break;
333                 case 'E':
334                         if (act != ACTION_NONE)
335                                 usage();
336                         act = ACTION_GET_EEPROM_INFO;
337                         break;
338                 case 'e':
339                         if (act != ACTION_NONE)
340                                 usage();
341                         act = ACTION_DUMP_FORCE;
342                         break;
343                 case 'o':
344                         dumpname = optarg;
345                         break;
346                 case 'r':
347                         if (act != ACTION_NONE)
348                                 usage();
349                         act = ACTION_DUMP_RESET;
350                         break;
351                 case 'f':
352                         if (act != ACTION_NONE)
353                                 usage();
354                         act = ACTION_FW_UPDATE;
355                         img_fw_path = optarg;
356                         break;
357                 case 'z':
358                         if (act != ACTION_NONE)
359                                 usage();
360                         act = ACTION_FW_RESET;
361                         break;
362                 case 'h':
363                 default:
364                         usage();
365                 }
366         }
367         if (act == ACTION_NONE || (dumpname != NULL &&
368             act != ACTION_DUMP_GET) || (img_fw_path != NULL &&
369             act != ACTION_FW_UPDATE))
370                 usage();
371         if (parse_pci_addr(addrstr, &addr) != 0)
372                 exit(1);
373
374         ctldev = open(MLX5_DEV_PATH, O_RDWR);
375         if (ctldev == -1)
376                 err(1, "open "MLX5_DEV_PATH);
377         switch (act) {
378         case ACTION_DUMP_GET:
379                 res = mlx5tool_save_dump(ctldev, &addr, dumpname);
380                 break;
381         case ACTION_DUMP_RESET:
382                 res = mlx5tool_dump_reset(ctldev, &addr);
383                 break;
384         case ACTION_DUMP_FORCE:
385                 res = mlx5tool_dump_force(ctldev, &addr);
386                 break;
387         case ACTION_FW_UPDATE:
388                 res = mlx5tool_fw_update(ctldev, &addr, img_fw_path);
389                 break;
390         case ACTION_FW_RESET:
391                 res = mlx5tool_fw_reset(ctldev, &addr);
392                 break;
393         case ACTION_GET_EEPROM_INFO:
394                 res = mlx5tool_get_eeprom_info(ctldev, &addr);
395                 break;
396         default:
397                 res = 0;
398                 break;
399         }
400         close(ctldev);
401         exit(res);
402 }