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