]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/mlx5tool/mlx5tool.c
Add kernel and userspace code to dump the firmware state of supported
[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 (strncmp(addrstr, "pci", 3) == 0) {
51                 addrstr += 3;
52                 i = 0;
53                 while (isdigit(*addrstr) && i < 4) {
54                         selarr[i++] = strtoul(addrstr, &eppos, 10);
55                         addrstr = eppos;
56                         if (*addrstr == ':')
57                                 addrstr++;
58                 }
59                 if (i > 0 && *addrstr == '\0') {
60                         addr->func = (i > 2) ? selarr[--i] : 0;
61                         addr->slot = (i > 0) ? selarr[--i] : 0;
62                         addr->bus = (i > 0) ? selarr[--i] : 0;
63                         addr->domain = (i > 0) ? selarr[--i] : 0;
64                         return (0);
65                 }
66         }
67         warnx("invalid pci address %s", addrstr);
68         return (1);
69 }
70
71 static int
72 mlx5tool_save_dump(int ctldev, const struct mlx5_fwdump_addr *addr,
73     const char *dumpname)
74 {
75         struct mlx5_fwdump_get fdg;
76         struct mlx5_fwdump_reg *rege;
77         FILE *dump;
78         size_t cnt;
79         int error, res;
80
81         if (dumpname == NULL)
82                 dump = stdout;
83         else
84                 dump = fopen(dumpname, "w");
85         if (dump == NULL) {
86                 warn("open %s", dumpname);
87                 return (1);
88         }
89         res = 1;
90         memset(&fdg, 0, sizeof(fdg));
91         fdg.devaddr = *addr;
92         error = ioctl(ctldev, MLX5_FWDUMP_GET, &fdg);
93         if (error != 0) {
94                 warn("MLX5_FWDUMP_GET dumpsize");
95                 goto out;
96         }
97         rege = calloc(fdg.reg_filled, sizeof(*rege));
98         if (rege == NULL) {
99                 warn("alloc rege");
100                 goto out;
101         }
102         fdg.buf = rege;
103         fdg.reg_cnt = fdg.reg_filled;
104         error = ioctl(ctldev, MLX5_FWDUMP_GET, &fdg);
105         if (error != 0) {
106                 if (errno == ENOENT)
107                         warnx("no dump recorded");
108                 else
109                         warn("MLX5_FWDUMP_GET dump fetch");
110                 goto out;
111         }
112         for (cnt = 0; cnt < fdg.reg_cnt; cnt++, rege++)
113                 fprintf(dump, "0x%08x\t0x%08x\n", rege->addr, rege->val);
114         res = 0;
115 out:
116         if (dump != stdout)
117                 fclose(dump);
118         return (res);
119 }
120
121 static int
122 mlx5tool_dump_reset(int ctldev, const struct mlx5_fwdump_addr *addr)
123 {
124
125         if (ioctl(ctldev, MLX5_FWDUMP_RESET, addr) == -1) {
126                 warn("MLX5_FWDUMP_RESET");
127                 return (1);
128         }
129         return (0);
130 }
131
132 static int
133 mlx5tool_dump_force(int ctldev, const struct mlx5_fwdump_addr *addr)
134 {
135
136         if (ioctl(ctldev, MLX5_FWDUMP_FORCE, addr) == -1) {
137                 warn("MLX5_FWDUMP_FORCE");
138                 return (1);
139         }
140         return (0);
141 }
142
143 static void
144 usage(void)
145 {
146
147         fprintf(stderr,
148             "Usage: mlx5tool -d pci<d:b:s:f> [-w -o dump.file | -r | -e]\n");
149         fprintf(stderr, "\t-w - write firmware dump to the specified file\n");
150         fprintf(stderr, "\t-r - reset dump\n");
151         fprintf(stderr, "\t-e - force dump\n");
152         exit(1);
153 }
154
155 enum mlx5_action {
156         ACTION_DUMP_GET,
157         ACTION_DUMP_RESET,
158         ACTION_DUMP_FORCE,
159         ACTION_NONE,
160 };
161
162 int
163 main(int argc, char *argv[])
164 {
165         struct mlx5_fwdump_addr addr;
166         char *dumpname;
167         char *addrstr;
168         int c, ctldev, res;
169         enum mlx5_action act;
170
171         act = ACTION_NONE;
172         addrstr = NULL;
173         dumpname = NULL;
174         while ((c = getopt(argc, argv, "d:eho:rw")) != -1) {
175                 switch (c) {
176                 case 'd':
177                         addrstr = optarg;
178                         break;
179                 case 'w':
180                         act = ACTION_DUMP_GET;
181                         break;
182                 case 'e':
183                         act= ACTION_DUMP_FORCE;
184                         break;
185                 case 'o':
186                         dumpname = optarg;
187                         break;
188                 case 'r':
189                         act = ACTION_DUMP_RESET;
190                         break;
191                 case 'h':
192                 default:
193                         usage();
194                 }
195         }
196         if (act == ACTION_NONE || (dumpname != NULL && act != ACTION_DUMP_GET))
197                 usage();
198         if (parse_pci_addr(addrstr, &addr) != 0)
199                 exit(1);
200
201         ctldev = open(MLX5_DEV_PATH, O_RDWR);
202         if (ctldev == -1)
203                 err(1, "open "MLX5_DEV_PATH);
204         switch (act) {
205         case ACTION_DUMP_GET:
206                 res = mlx5tool_save_dump(ctldev, &addr, dumpname);
207                 break;
208         case ACTION_DUMP_RESET:
209                 res = mlx5tool_dump_reset(ctldev, &addr);
210                 break;
211         case ACTION_DUMP_FORCE:
212                 res = mlx5tool_dump_force(ctldev, &addr);
213                 break;
214         default:
215                 res = 0;
216                 break;
217         }
218         close(ctldev);
219         exit(res);
220 }