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 }