mlx5tool.c revision 331593
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: stable/11/usr.sbin/mlx5tool/mlx5tool.c 331593 2018-03-26 21:14:20Z hselasky $");
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() */
43static int
44parse_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
75static int
76mlx5tool_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;
119out:
120	if (dump != stdout)
121		fclose(dump);
122	return (res);
123}
124
125static int
126mlx5tool_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
136static int
137mlx5tool_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
147static void
148usage(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
159enum mlx5_action {
160	ACTION_DUMP_GET,
161	ACTION_DUMP_RESET,
162	ACTION_DUMP_FORCE,
163	ACTION_NONE,
164};
165
166int
167main(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