xref: /illumos-gate/usr/src/cmd/cxgbetool/cxgbetool.c (revision 9cb0a1d4446fe891a01d01e07b2e27f0177c84cd)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright (c) 2018 by Chelsio Communications, Inc.
14  */
15 
16 /*
17  * Copyright 2019 Joyent, Inc.
18  */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <stropts.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <sys/socket.h>
28 #include <strings.h>
29 #include <sys/varargs.h>
30 #include <errno.h>
31 #include <sys/byteorder.h>
32 #include <inttypes.h>
33 #include <sys/sysmacros.h>
34 
35 #include "t4nex.h"
36 #include "version.h"
37 #include "osdep.h"
38 #include "t4fw_interface.h"
39 
40 /*
41  * Firmware Device Log Dumping
42  */
43 
44 static const char * const devlog_level_strings[] = {
45 	[FW_DEVLOG_LEVEL_EMERG]		= "EMERG",
46 	[FW_DEVLOG_LEVEL_CRIT]		= "CRIT",
47 	[FW_DEVLOG_LEVEL_ERR]		= "ERR",
48 	[FW_DEVLOG_LEVEL_NOTICE]	= "NOTICE",
49 	[FW_DEVLOG_LEVEL_INFO]		= "INFO",
50 	[FW_DEVLOG_LEVEL_DEBUG]		= "DEBUG"
51 };
52 
53 static const char * const devlog_facility_strings[] = {
54 	[FW_DEVLOG_FACILITY_CORE]	= "CORE",
55 	[FW_DEVLOG_FACILITY_CF]		= "CF",
56 	[FW_DEVLOG_FACILITY_SCHED]	= "SCHED",
57 	[FW_DEVLOG_FACILITY_TIMER]	= "TIMER",
58 	[FW_DEVLOG_FACILITY_RES]	= "RES",
59 	[FW_DEVLOG_FACILITY_HW]		= "HW",
60 	[FW_DEVLOG_FACILITY_FLR]	= "FLR",
61 	[FW_DEVLOG_FACILITY_DMAQ]	= "DMAQ",
62 	[FW_DEVLOG_FACILITY_PHY]	= "PHY",
63 	[FW_DEVLOG_FACILITY_MAC]	= "MAC",
64 	[FW_DEVLOG_FACILITY_PORT]	= "PORT",
65 	[FW_DEVLOG_FACILITY_VI]		= "VI",
66 	[FW_DEVLOG_FACILITY_FILTER]	= "FILTER",
67 	[FW_DEVLOG_FACILITY_ACL]	= "ACL",
68 	[FW_DEVLOG_FACILITY_TM]		= "TM",
69 	[FW_DEVLOG_FACILITY_QFC]	= "QFC",
70 	[FW_DEVLOG_FACILITY_DCB]	= "DCB",
71 	[FW_DEVLOG_FACILITY_ETH]	= "ETH",
72 	[FW_DEVLOG_FACILITY_OFLD]	= "OFLD",
73 	[FW_DEVLOG_FACILITY_RI]		= "RI",
74 	[FW_DEVLOG_FACILITY_ISCSI]	= "ISCSI",
75 	[FW_DEVLOG_FACILITY_FCOE]	= "FCOE",
76 	[FW_DEVLOG_FACILITY_FOISCSI]	= "FOISCSI",
77 	[FW_DEVLOG_FACILITY_FOFCOE]	= "FOFCOE",
78 	[FW_DEVLOG_FACILITY_CHNET]	= "CHNET",
79 };
80 
81 static const char *progname;
82 
83 static void usage(FILE *fp)
84 {
85 	fprintf(fp, "Usage: %s <path to t4nex#> [operation]\n", progname);
86 	fprintf(fp,
87 	    "\tdevlog                              show device log\n"
88 	    "\tloadfw <FW image>                   Flash the FW image\n");
89 	exit(fp == stderr ? 1 : 0);
90 }
91 
92 __NORETURN static void
93 err(int code, const char *fmt, ...)
94 {
95 	va_list ap;
96 	int e = errno;
97 
98 	va_start(ap, fmt);
99 	fprintf(stderr, "error: ");
100 	vfprintf(stderr, fmt, ap);
101 	fprintf(stderr, ": %s\n", strerror(e));
102 	va_end(ap);
103 	exit(code);
104 }
105 
106 static int
107 doit(const char *iff_name, unsigned long cmd, void *data)
108 {
109 	int fd = 0;
110 	int rc = 0;
111 
112 	if ((fd = open(iff_name, O_RDWR)) < 0)
113 		return (-1);
114 
115 	rc = (ioctl(fd, cmd, data) < 0) ? errno : rc;
116 	close(fd);
117 	return (rc);
118 }
119 
120 static void
121 get_devlog(int argc, char *argv[], int start_arg, const char *iff_name)
122 {
123 	struct t4_devlog *devlog;
124 	struct fw_devlog_e *entry, *buf;
125 	int rc = 0, first = 0, nentries, i, j, len;
126 	uint64_t ftstamp = UINT64_MAX;
127 
128 	devlog = malloc(T4_DEVLOG_SIZE + sizeof (struct t4_devlog));
129 	if (!devlog)
130 		err(1, "%s: can't allocate devlog buffer", __func__);
131 
132 	devlog->len = T4_DEVLOG_SIZE;
133 	/* Get device log */
134 	rc = doit(iff_name, T4_IOCTL_DEVLOG, devlog);
135 	if (rc == ENOBUFS) {
136 		/*
137 		 * Default buffer size is not sufficient to hold device log.
138 		 * Driver has updated the devlog.len to indicate the expected
139 		 * size. Free the currently allocated devlog.data, allocate
140 		 * again with right size and retry.
141 		 */
142 		len = devlog->len;
143 		free(devlog);
144 
145 		if ((devlog = malloc(len + sizeof (struct t4_devlog))) == NULL)
146 			err(1, "%s: can't reallocate devlog buffer", __func__);
147 
148 		rc = doit(iff_name, T4_IOCTL_DEVLOG, devlog);
149 	}
150 	if (rc) {
151 		free(devlog);
152 		err(1, "%s: can't get device log", __func__);
153 	}
154 
155 	/* There are nentries number of entries in the buffer */
156 	nentries = (devlog->len / sizeof (struct fw_devlog_e));
157 
158 	buf = (struct fw_devlog_e *)devlog->data;
159 
160 	/* Find the first entry */
161 	for (i = 0; i < nentries; i++) {
162 		entry = &buf[i];
163 
164 		if (entry->timestamp == 0)
165 			break;
166 
167 		entry->timestamp = BE_64(entry->timestamp);
168 		entry->seqno = BE_32(entry->seqno);
169 		for (j = 0; j < 8; j++)
170 			entry->params[j] = BE_32(entry->params[j]);
171 
172 		if (entry->timestamp < ftstamp) {
173 			ftstamp = entry->timestamp;
174 			first = i;
175 		}
176 	}
177 
178 	printf("%10s  %15s  %8s  %8s  %s\n", "Seq#", "Tstamp", "Level",
179 	    "Facility", "Message");
180 
181 	i = first;
182 
183 	do {
184 		entry = &buf[i];
185 
186 		if (entry->timestamp == 0)
187 			break;
188 
189 		printf("%10d  %15llu  %8s  %8s  ", entry->seqno,
190 		    entry->timestamp,
191 		    (entry->level < ARRAY_SIZE(devlog_level_strings) ?
192 		    devlog_level_strings[entry->level] : "UNKNOWN"),
193 		    (entry->facility < ARRAY_SIZE(devlog_facility_strings) ?
194 		    devlog_facility_strings[entry->facility] : "UNKNOWN"));
195 
196 		printf((const char *)entry->fmt, entry->params[0],
197 		    entry->params[1], entry->params[2], entry->params[3],
198 		    entry->params[4], entry->params[5], entry->params[6],
199 		    entry->params[7]);
200 
201 		if (++i == nentries)
202 			i = 0;
203 
204 	} while (i != first);
205 
206 	free(devlog);
207 }
208 
209 static void
210 load_fw(int argc, char *argv[], int start_arg, const char *iff_name)
211 {
212 	const char *fname = argv[start_arg];
213 	struct t4_ldfw *fw;
214 	struct stat sb;
215 	size_t len;
216 	int fd;
217 
218 	if (argc != 4)
219 		err(1, "incorrect number of arguments.");
220 
221 	fd = open(fname, O_RDONLY);
222 	if (fd < 0)
223 		err(1, "%s: opening %s failed", __func__, fname);
224 	if (fstat(fd, &sb) < 0) {
225 		close(fd);
226 		err(1, "%s: fstat %s failed", __func__, fname);
227 	}
228 	len = (size_t)sb.st_size;
229 
230 	fw = malloc(sizeof (struct t4_ldfw) + len);
231 	if (!fw) {
232 		close(fd);
233 		err(1, "%s: %s allocate %ld bytes failed",
234 		    __func__, fname, sizeof (struct t4_ldfw) + len);
235 	}
236 
237 	if (read(fd, fw->data, len) < len) {
238 		close(fd);
239 		free(fw);
240 		err(1, "%s: %s read failed", __func__, fname);
241 	}
242 
243 	close(fd);
244 
245 	fw->len = len;
246 
247 	if (doit(iff_name, T4_IOCTL_LOAD_FW, fw)) {
248 		free(fw);
249 		err(1, "%s: IOCTL failed", __func__);
250 	} else {
251 		printf("FW flash success, reload driver/reboot to take "
252 		    "effect\n");
253 	}
254 
255 	free(fw);
256 }
257 
258 static void
259 run_cmd(int argc, char *argv[], const char *iff_name)
260 {
261 	if (strcmp(argv[2], "devlog") == 0)
262 		get_devlog(argc, argv, 3, iff_name);
263 	else if (strcmp(argv[2], "loadfw") == 0)
264 		load_fw(argc, argv, 3, iff_name);
265 	else
266 		usage(stderr);
267 }
268 
269 int
270 main(int argc, char *argv[])
271 {
272 	const char *iff_name;
273 
274 	progname = argv[0];
275 
276 	if (argc == 2) {
277 		if (strcmp(argv[1], "-h") == 0 ||
278 		    strcmp(argv[1], "--help") == 0) {
279 			usage(stdout);
280 		}
281 
282 		if (strcmp(argv[1], "-v") == 0 ||
283 		    strcmp(argv[1], "--version") == 0) {
284 			printf("cxgbetool version %s\n", DRV_VERSION);
285 			exit(0);
286 		}
287 	}
288 
289 	if (argc < 3)
290 		usage(stderr);
291 
292 	iff_name = argv[1];
293 
294 	run_cmd(argc, argv, iff_name);
295 
296 	return (0);
297 }
298