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