xref: /freebsd/usr.sbin/mlx5tool/mlx5tool.c (revision 0957b409)
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 }
225