1 /*- 2 * Copyright (c) 2018, Mellanox Technologies, Ltd. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include <sys/param.h> 30 #include <sys/ioctl.h> 31 #include <dev/mlx5/mlx5io.h> 32 #include <ctype.h> 33 #include <err.h> 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <paths.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 42 /* stolen from pciconf.c: parsesel() */ 43 static int 44 parse_pci_addr(const char *addrstr, struct mlx5_fwdump_addr *addr) 45 { 46 char *eppos; 47 unsigned long selarr[4]; 48 int i; 49 50 if (addrstr == NULL) { 51 warnx("no pci address specified"); 52 return (1); 53 } 54 if (strncmp(addrstr, "pci", 3) == 0) { 55 addrstr += 3; 56 i = 0; 57 while (isdigit(*addrstr) && i < 4) { 58 selarr[i++] = strtoul(addrstr, &eppos, 10); 59 addrstr = eppos; 60 if (*addrstr == ':') 61 addrstr++; 62 } 63 if (i > 0 && *addrstr == '\0') { 64 addr->func = (i > 2) ? selarr[--i] : 0; 65 addr->slot = (i > 0) ? selarr[--i] : 0; 66 addr->bus = (i > 0) ? selarr[--i] : 0; 67 addr->domain = (i > 0) ? selarr[--i] : 0; 68 return (0); 69 } 70 } 71 warnx("invalid pci address %s", addrstr); 72 return (1); 73 } 74 75 static int 76 mlx5tool_save_dump(int ctldev, const struct mlx5_fwdump_addr *addr, 77 const char *dumpname) 78 { 79 struct mlx5_fwdump_get fdg; 80 struct mlx5_fwdump_reg *rege; 81 FILE *dump; 82 size_t cnt; 83 int error, res; 84 85 if (dumpname == NULL) 86 dump = stdout; 87 else 88 dump = fopen(dumpname, "w"); 89 if (dump == NULL) { 90 warn("open %s", dumpname); 91 return (1); 92 } 93 res = 1; 94 memset(&fdg, 0, sizeof(fdg)); 95 fdg.devaddr = *addr; 96 error = ioctl(ctldev, MLX5_FWDUMP_GET, &fdg); 97 if (error != 0) { 98 warn("MLX5_FWDUMP_GET dumpsize"); 99 goto out; 100 } 101 rege = calloc(fdg.reg_filled, sizeof(*rege)); 102 if (rege == NULL) { 103 warn("alloc rege"); 104 goto out; 105 } 106 fdg.buf = rege; 107 fdg.reg_cnt = fdg.reg_filled; 108 error = ioctl(ctldev, MLX5_FWDUMP_GET, &fdg); 109 if (error != 0) { 110 if (errno == ENOENT) 111 warnx("no dump recorded"); 112 else 113 warn("MLX5_FWDUMP_GET dump fetch"); 114 goto out; 115 } 116 for (cnt = 0; cnt < fdg.reg_cnt; cnt++, rege++) 117 fprintf(dump, "0x%08x\t0x%08x\n", rege->addr, rege->val); 118 res = 0; 119 out: 120 if (dump != stdout) 121 fclose(dump); 122 return (res); 123 } 124 125 static int 126 mlx5tool_dump_reset(int ctldev, const struct mlx5_fwdump_addr *addr) 127 { 128 129 if (ioctl(ctldev, MLX5_FWDUMP_RESET, addr) == -1) { 130 warn("MLX5_FWDUMP_RESET"); 131 return (1); 132 } 133 return (0); 134 } 135 136 static int 137 mlx5tool_dump_force(int ctldev, const struct mlx5_fwdump_addr *addr) 138 { 139 140 if (ioctl(ctldev, MLX5_FWDUMP_FORCE, addr) == -1) { 141 warn("MLX5_FWDUMP_FORCE"); 142 return (1); 143 } 144 return (0); 145 } 146 147 static void 148 usage(void) 149 { 150 151 fprintf(stderr, 152 "Usage: mlx5tool -d pci<d:b:s:f> [-w -o dump.file | -r | -e]\n"); 153 fprintf(stderr, "\t-w - write firmware dump to the specified file\n"); 154 fprintf(stderr, "\t-r - reset dump\n"); 155 fprintf(stderr, "\t-e - force dump\n"); 156 exit(1); 157 } 158 159 enum mlx5_action { 160 ACTION_DUMP_GET, 161 ACTION_DUMP_RESET, 162 ACTION_DUMP_FORCE, 163 ACTION_NONE, 164 }; 165 166 int 167 main(int argc, char *argv[]) 168 { 169 struct mlx5_fwdump_addr addr; 170 char *dumpname; 171 char *addrstr; 172 int c, ctldev, res; 173 enum mlx5_action act; 174 175 act = ACTION_NONE; 176 addrstr = NULL; 177 dumpname = NULL; 178 while ((c = getopt(argc, argv, "d:eho:rw")) != -1) { 179 switch (c) { 180 case 'd': 181 addrstr = optarg; 182 break; 183 case 'w': 184 act = ACTION_DUMP_GET; 185 break; 186 case 'e': 187 act= ACTION_DUMP_FORCE; 188 break; 189 case 'o': 190 dumpname = optarg; 191 break; 192 case 'r': 193 act = ACTION_DUMP_RESET; 194 break; 195 case 'h': 196 default: 197 usage(); 198 } 199 } 200 if (act == ACTION_NONE || (dumpname != NULL && act != ACTION_DUMP_GET)) 201 usage(); 202 if (parse_pci_addr(addrstr, &addr) != 0) 203 exit(1); 204 205 ctldev = open(MLX5_DEV_PATH, O_RDWR); 206 if (ctldev == -1) 207 err(1, "open "MLX5_DEV_PATH); 208 switch (act) { 209 case ACTION_DUMP_GET: 210 res = mlx5tool_save_dump(ctldev, &addr, dumpname); 211 break; 212 case ACTION_DUMP_RESET: 213 res = mlx5tool_dump_reset(ctldev, &addr); 214 break; 215 case ACTION_DUMP_FORCE: 216 res = mlx5tool_dump_force(ctldev, &addr); 217 break; 218 default: 219 res = 0; 220 break; 221 } 222 close(ctldev); 223 exit(res); 224 } 225