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