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