diff -r 832efc003484 sys/dev/cxgbe/t4_ioctl.h --- a/sys/dev/cxgbe/t4_ioctl.h Thu Jun 15 21:06:03 2017 +0000 +++ b/sys/dev/cxgbe/t4_ioctl.h Fri Jun 16 17:42:06 2017 -0700 @@ -57,6 +57,7 @@ enum { T4_GET_TRACER, /* get information about a tracer */ T4_SET_TRACER, /* program a tracer */ T4_LOAD_CFG, /* copy a config file to card's flash */ + T4_DUMP_FW, /* dump firmware from card's flash */ }; struct t4_reg { @@ -346,4 +347,5 @@ struct t4_tracer { #define CHELSIO_T4_GET_TRACER _IOWR('f', T4_GET_TRACER, struct t4_tracer) #define CHELSIO_T4_SET_TRACER _IOW('f', T4_SET_TRACER, struct t4_tracer) #define CHELSIO_T4_LOAD_CFG _IOW('f', T4_LOAD_CFG, struct t4_data) +#define CHELSIO_T4_DUMP_FW _IOWR('f', T4_DUMP_FW, struct t4_data) #endif diff -r 832efc003484 sys/dev/cxgbe/t4_main.c --- a/sys/dev/cxgbe/t4_main.c Thu Jun 15 21:06:03 2017 +0000 +++ b/sys/dev/cxgbe/t4_main.c Fri Jun 16 17:42:06 2017 -0700 @@ -380,7 +380,7 @@ TUNABLE_INT("hw.cxgbe.autoneg", &t4_auto * Firmware auto-install by driver during attach (0, 1, 2 = prohibited, allowed, * encouraged respectively). */ -static unsigned int t4_fw_install = 1; +static unsigned int t4_fw_install = 0; TUNABLE_INT("hw.cxgbe.fw_install", &t4_fw_install); /* @@ -8782,6 +8782,33 @@ done: return (rc); } +static int +dump_fw(struct adapter *sc, struct t4_data *fw) +{ + int rc; + uint32_t *buf; + struct fw_hdr *hdr; + + if (fw->len == 0) { + fw->len = FLASH_FW_MAX_SIZE; + return (0); + } else if (fw->len != FLASH_FW_MAX_SIZE) + return (EFBIG); + + buf = malloc(fw->len, M_CXGBE, M_WAITOK); + if (buf == NULL) + return (ENOMEM); + + rc = -t4_read_flash(sc, FLASH_FW_START, fw->len >> 2, buf, 1); + hdr = (struct fw_hdr *)buf; + fw->len = min(512U * be16toh(hdr->len512), FLASH_FW_MAX_SIZE); + if (rc == 0) + rc = copyout(buf, fw->data, fw->len); + + free(buf, M_CXGBE); + return (rc); +} + #define MAX_READ_BUF_SIZE (128 * 1024) static int read_card_mem(struct adapter *sc, int win, struct t4_mem_range *mr) @@ -9117,6 +9144,9 @@ t4_ioctl(struct cdev *dev, unsigned long case CHELSIO_T4_LOAD_CFG: rc = load_cfg(sc, (struct t4_data *)data); break; + case CHELSIO_T4_DUMP_FW: + rc = dump_fw(sc, (struct t4_data *)data); + break; default: rc = ENOTTY; } diff -r 832efc003484 usr.sbin/cxgbetool/cxgbetool.c --- a/usr.sbin/cxgbetool/cxgbetool.c Thu Jun 15 21:06:03 2017 +0000 +++ b/usr.sbin/cxgbetool/cxgbetool.c Fri Jun 16 17:42:06 2017 -0700 @@ -90,6 +90,7 @@ usage(FILE *fp) fprintf(fp, "\tclearstats clear port statistics\n" "\tcontext show an SGE context\n" + "\tdumpfw dump the firmware\n" "\tfilter [ ] ... set a filter\n" "\tfilter delete|clear delete a filter\n" "\tfilter list list all filters\n" @@ -1880,6 +1881,39 @@ loadcfg(int argc, const char *argv[]) } static int +dumpfw(int argc, const char *argv[]) +{ + int rc, fd; + struct t4_data data = {0}; + const char *fname = argv[0]; + + if (argc != 1) { + warnx("dumpfw: incorrect number of arguments."); + return (EINVAL); + } + + rc = doit(CHELSIO_T4_DUMP_FW, &data); + if (rc != 0) + return (rc); + + printf("data.len = %d\n", data.len); + + fd = open(fname, O_CREAT | O_TRUNC | O_EXCL | O_WRONLY); + if (fd < 0) { + warn("open(%s)", fname); + return (errno); + } + + data.data = malloc(data.len); + printf("data.data = %p\n", data.data); + rc = doit(CHELSIO_T4_DUMP_FW, &data); + write(fd, data.data, data.len); + free(data.data); + close(fd); + return (rc); +} + +static int read_mem(uint32_t addr, uint32_t len, void (*output)(uint32_t *, uint32_t)) { int rc; @@ -2779,6 +2813,8 @@ run_cmd(int argc, const char *argv[]) rc = sched_queue(argc, argv); else if (!strcmp(cmd, "loadcfg")) rc = loadcfg(argc, argv); + else if (!strcmp(cmd, "dumpfw")) + rc = dumpfw(argc, argv); else { rc = EINVAL; warnx("invalid command \"%s\"", cmd);