13e891891SBaptiste Daroussin /*- 23e891891SBaptiste Daroussin * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org> 33e891891SBaptiste Daroussin * 43e891891SBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 53e891891SBaptiste Daroussin * modification, are permitted provided that the following conditions 63e891891SBaptiste Daroussin * are met: 73e891891SBaptiste Daroussin * 1. Redistributions of source code must retain the above copyright 83e891891SBaptiste Daroussin * notice, this list of conditions and the following disclaimer. 93e891891SBaptiste Daroussin * 2. Redistributions in binary form must reproduce the above copyright 103e891891SBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the 113e891891SBaptiste Daroussin * documentation and/or other materials provided with the distribution. 123e891891SBaptiste Daroussin * 133e891891SBaptiste Daroussin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 143e891891SBaptiste Daroussin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 153e891891SBaptiste Daroussin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 163e891891SBaptiste Daroussin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 173e891891SBaptiste Daroussin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 183e891891SBaptiste Daroussin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 193e891891SBaptiste Daroussin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 203e891891SBaptiste Daroussin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 213e891891SBaptiste Daroussin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 223e891891SBaptiste Daroussin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 233e891891SBaptiste Daroussin * SUCH DAMAGE. 243e891891SBaptiste Daroussin */ 253e891891SBaptiste Daroussin 263e891891SBaptiste Daroussin #include <sys/cdefs.h> 273e891891SBaptiste Daroussin __RCSID("$FreeBSD$"); 283e891891SBaptiste Daroussin 293e891891SBaptiste Daroussin #include <sys/stat.h> 303e891891SBaptiste Daroussin #include <sys/param.h> 313e891891SBaptiste Daroussin #include <sys/mman.h> 32*fc9780fdSAlfredo Dal'Ava Junior #include <sys/endian.h> 333e891891SBaptiste Daroussin 343e891891SBaptiste Daroussin #include <errno.h> 353e891891SBaptiste Daroussin #include <err.h> 363e891891SBaptiste Daroussin #include <fcntl.h> 373e891891SBaptiste Daroussin #include <stdbool.h> 383e891891SBaptiste Daroussin #include <stdio.h> 393e891891SBaptiste Daroussin #include <stdlib.h> 403e891891SBaptiste Daroussin #include <string.h> 413e891891SBaptiste Daroussin #include <unistd.h> 423e891891SBaptiste Daroussin 433e891891SBaptiste Daroussin #include "mpsutil.h" 443e891891SBaptiste Daroussin 453e891891SBaptiste Daroussin MPS_TABLE(top, flash); 463e891891SBaptiste Daroussin 473e891891SBaptiste Daroussin static int 483e891891SBaptiste Daroussin flash_save(int argc, char **argv) 493e891891SBaptiste Daroussin { 503e891891SBaptiste Daroussin const char *firmware_file; 513e891891SBaptiste Daroussin unsigned char *firmware_buffer = NULL; 523e891891SBaptiste Daroussin int error, fd, size; 533e891891SBaptiste Daroussin bool bios = false; 543e891891SBaptiste Daroussin ssize_t written = 0, ret = 0; 553e891891SBaptiste Daroussin 563e891891SBaptiste Daroussin if (argc < 2) { 573e891891SBaptiste Daroussin warnx("missing argument: expecting 'firmware' or bios'"); 583e891891SBaptiste Daroussin return (EINVAL); 593e891891SBaptiste Daroussin } 603e891891SBaptiste Daroussin 613e891891SBaptiste Daroussin if (strcmp(argv[1], "bios") == 0) { 623e891891SBaptiste Daroussin bios = true; 633e891891SBaptiste Daroussin } else if (strcmp(argv[1], "firmware") != 0) { 643e891891SBaptiste Daroussin warnx("Invalid argument '%s', expecting 'firmware' or 'bios'", 653e891891SBaptiste Daroussin argv[1]); 663e891891SBaptiste Daroussin } 673e891891SBaptiste Daroussin 683e891891SBaptiste Daroussin if (argc > 4) { 693e891891SBaptiste Daroussin warnx("save %s: extra arguments", argv[1]); 703e891891SBaptiste Daroussin return (EINVAL); 713e891891SBaptiste Daroussin } 723e891891SBaptiste Daroussin 733e891891SBaptiste Daroussin firmware_file = argv[1]; 743e891891SBaptiste Daroussin if (argc == 3) { 753e891891SBaptiste Daroussin firmware_file = argv[2]; 763e891891SBaptiste Daroussin } 773e891891SBaptiste Daroussin 783e891891SBaptiste Daroussin fd = mps_open(mps_unit); 793e891891SBaptiste Daroussin if (fd < 0) { 803e891891SBaptiste Daroussin error = errno; 813e891891SBaptiste Daroussin warn("mps_open"); 823e891891SBaptiste Daroussin return (error); 833e891891SBaptiste Daroussin } 843e891891SBaptiste Daroussin 853e891891SBaptiste Daroussin if ((size = mps_firmware_get(fd, &firmware_buffer, bios)) < 0) { 863e891891SBaptiste Daroussin warnx("Fail to save %s", argv[1]); 874ecb5141SBaptiste Daroussin close(fd); 883e891891SBaptiste Daroussin return (1); 893e891891SBaptiste Daroussin } 903e891891SBaptiste Daroussin 913e891891SBaptiste Daroussin close(fd); 923e891891SBaptiste Daroussin if (size > 0) { 933e891891SBaptiste Daroussin fd = open(firmware_file, O_CREAT | O_TRUNC | O_RDWR, 0644); 943e891891SBaptiste Daroussin if (fd <0) { 953e891891SBaptiste Daroussin error = errno; 963e891891SBaptiste Daroussin warn("open"); 973e891891SBaptiste Daroussin free(firmware_buffer); 983e891891SBaptiste Daroussin return (error); 993e891891SBaptiste Daroussin } 1003e891891SBaptiste Daroussin while (written != size) { 1013e891891SBaptiste Daroussin if ((ret = write(fd, firmware_buffer + written, size - written)) <0) { 1023e891891SBaptiste Daroussin error = errno; 1033e891891SBaptiste Daroussin warn("write"); 1043e891891SBaptiste Daroussin free(firmware_buffer); 1054ecb5141SBaptiste Daroussin close(fd); 1063e891891SBaptiste Daroussin return (error); 1073e891891SBaptiste Daroussin } 1083e891891SBaptiste Daroussin written += ret; 1093e891891SBaptiste Daroussin } 1103e891891SBaptiste Daroussin close(fd); 1113e891891SBaptiste Daroussin } 1123e891891SBaptiste Daroussin free(firmware_buffer); 1133e891891SBaptiste Daroussin printf("%s successfully saved as %s\n", argv[1], firmware_file); 1143e891891SBaptiste Daroussin return (0); 1153e891891SBaptiste Daroussin } 1163e891891SBaptiste Daroussin 1173e891891SBaptiste Daroussin MPS_COMMAND(flash, save, flash_save, "[firmware|bios] [file]", 1183e891891SBaptiste Daroussin "Save firmware/bios into a file"); 1193e891891SBaptiste Daroussin 1203e891891SBaptiste Daroussin static int 1213e891891SBaptiste Daroussin flash_update(int argc, char **argv) 1223e891891SBaptiste Daroussin { 1233e891891SBaptiste Daroussin int error, fd; 1243e891891SBaptiste Daroussin unsigned char *mem = NULL; 1253e891891SBaptiste Daroussin struct stat st; 1263e891891SBaptiste Daroussin bool bios = false; 1273e891891SBaptiste Daroussin MPI2_FW_IMAGE_HEADER *fwheader; 1283e891891SBaptiste Daroussin MPI2_IOC_FACTS_REPLY *facts; 1293e891891SBaptiste Daroussin 1303e891891SBaptiste Daroussin if (argc < 2) { 1313e891891SBaptiste Daroussin warnx("missing argument: expecting 'firmware' or bios'"); 1323e891891SBaptiste Daroussin return (EINVAL); 1333e891891SBaptiste Daroussin } 1343e891891SBaptiste Daroussin 1353e891891SBaptiste Daroussin if (strcmp(argv[1], "bios") == 0) { 1363e891891SBaptiste Daroussin bios = true; 1373e891891SBaptiste Daroussin } else if (strcmp(argv[1], "firmware") != 0) { 1383e891891SBaptiste Daroussin warnx("Invalid argument '%s', expecting 'firmware' or 'bios'", 1393e891891SBaptiste Daroussin argv[1]); 1403e891891SBaptiste Daroussin } 1413e891891SBaptiste Daroussin 1423e891891SBaptiste Daroussin if (argc > 4) { 1433e891891SBaptiste Daroussin warnx("update firmware: extra arguments"); 1443e891891SBaptiste Daroussin return (EINVAL); 1453e891891SBaptiste Daroussin } 1463e891891SBaptiste Daroussin 1473e891891SBaptiste Daroussin if (argc != 3) { 1483e891891SBaptiste Daroussin warnx("no firmware specified"); 1493e891891SBaptiste Daroussin return (EINVAL); 1503e891891SBaptiste Daroussin } 1513e891891SBaptiste Daroussin 1523e891891SBaptiste Daroussin if (stat(argv[2], &st) == -1) { 1533e891891SBaptiste Daroussin error = errno; 1543e891891SBaptiste Daroussin warn("stat"); 1553e891891SBaptiste Daroussin return (error); 1563e891891SBaptiste Daroussin } 1573e891891SBaptiste Daroussin 1583e891891SBaptiste Daroussin fd = open(argv[2], O_RDONLY); 1593e891891SBaptiste Daroussin if (fd < 0) { 1603e891891SBaptiste Daroussin error = errno; 1613e891891SBaptiste Daroussin warn("open"); 1623e891891SBaptiste Daroussin return (error); 1633e891891SBaptiste Daroussin } 1643e891891SBaptiste Daroussin 1653e891891SBaptiste Daroussin mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 1663e891891SBaptiste Daroussin if (mem == MAP_FAILED) { 1673e891891SBaptiste Daroussin error = errno; 1683e891891SBaptiste Daroussin warn("mmap"); 1693e891891SBaptiste Daroussin close(fd); 1703e891891SBaptiste Daroussin return (error); 1713e891891SBaptiste Daroussin } 1723e891891SBaptiste Daroussin close(fd); 1733e891891SBaptiste Daroussin 1743e891891SBaptiste Daroussin fd = mps_open(mps_unit); 1753e891891SBaptiste Daroussin if (fd < 0) { 1763e891891SBaptiste Daroussin error = errno; 1773e891891SBaptiste Daroussin warn("mps_open"); 1783e891891SBaptiste Daroussin munmap(mem, st.st_size); 1793e891891SBaptiste Daroussin return (error); 1803e891891SBaptiste Daroussin } 1813e891891SBaptiste Daroussin 1823e891891SBaptiste Daroussin if ((facts = mps_get_iocfacts(fd)) == NULL) { 1833e891891SBaptiste Daroussin warnx("could not get controller IOCFacts\n"); 1843e891891SBaptiste Daroussin munmap(mem, st.st_size); 1853e891891SBaptiste Daroussin close(fd); 1863e891891SBaptiste Daroussin return (EINVAL); 1873e891891SBaptiste Daroussin } 1883e891891SBaptiste Daroussin 1893e891891SBaptiste Daroussin if (bios) { 1903e891891SBaptiste Daroussin /* Check boot record magic number */ 1913e891891SBaptiste Daroussin if (((mem[0x01]<<8) + mem[0x00]) != 0xaa55) { 1923e891891SBaptiste Daroussin warnx("Invalid bios: no boot record magic number"); 1933e891891SBaptiste Daroussin munmap(mem, st.st_size); 1943e891891SBaptiste Daroussin close(fd); 1954ecb5141SBaptiste Daroussin free(facts); 1963e891891SBaptiste Daroussin return (1); 1973e891891SBaptiste Daroussin } 1983e891891SBaptiste Daroussin if ((st.st_size % 512) != 0) { 1993e891891SBaptiste Daroussin warnx("Invalid bios: size not a multiple of 512"); 2003e891891SBaptiste Daroussin munmap(mem, st.st_size); 2013e891891SBaptiste Daroussin close(fd); 2024ecb5141SBaptiste Daroussin free(facts); 2033e891891SBaptiste Daroussin return (1); 2043e891891SBaptiste Daroussin } 2053e891891SBaptiste Daroussin } else { 2063e891891SBaptiste Daroussin fwheader = (MPI2_FW_IMAGE_HEADER *)mem; 207*fc9780fdSAlfredo Dal'Ava Junior if (le16toh(fwheader->VendorID) != MPI2_MFGPAGE_VENDORID_LSI) { 2083e891891SBaptiste Daroussin warnx("Invalid firmware:"); 2093e891891SBaptiste Daroussin warnx(" Expected Vendor ID: %04x", 2103e891891SBaptiste Daroussin MPI2_MFGPAGE_VENDORID_LSI); 211*fc9780fdSAlfredo Dal'Ava Junior warnx(" Image Vendor ID: %04x", le16toh(fwheader->VendorID)); 2123e891891SBaptiste Daroussin munmap(mem, st.st_size); 2133e891891SBaptiste Daroussin close(fd); 2144ecb5141SBaptiste Daroussin free(facts); 2153e891891SBaptiste Daroussin return (1); 2163e891891SBaptiste Daroussin } 2173e891891SBaptiste Daroussin 218*fc9780fdSAlfredo Dal'Ava Junior if (le16toh(fwheader->ProductID) != facts->ProductID) { 2193e891891SBaptiste Daroussin warnx("Invalid image:"); 2203e891891SBaptiste Daroussin warnx(" Expected Product ID: %04x", facts->ProductID); 221*fc9780fdSAlfredo Dal'Ava Junior warnx(" Image Product ID: %04x", le16toh(fwheader->ProductID)); 2223e891891SBaptiste Daroussin munmap(mem, st.st_size); 2233e891891SBaptiste Daroussin close(fd); 2244ecb5141SBaptiste Daroussin free(facts); 2253e891891SBaptiste Daroussin return (1); 2263e891891SBaptiste Daroussin } 2273e891891SBaptiste Daroussin } 2283e891891SBaptiste Daroussin 2293e891891SBaptiste Daroussin printf("Updating %s...\n", argv[1]); 2303e891891SBaptiste Daroussin if (mps_firmware_send(fd, mem, st.st_size, bios) < 0) { 2313e891891SBaptiste Daroussin warnx("Fail to update %s", argv[1]); 2323e891891SBaptiste Daroussin munmap(mem, st.st_size); 2333e891891SBaptiste Daroussin close(fd); 2344ecb5141SBaptiste Daroussin free(facts); 2353e891891SBaptiste Daroussin return (1); 2363e891891SBaptiste Daroussin } 2373e891891SBaptiste Daroussin 2383e891891SBaptiste Daroussin munmap(mem, st.st_size); 2393e891891SBaptiste Daroussin close(fd); 2404ecb5141SBaptiste Daroussin free(facts); 2413e891891SBaptiste Daroussin printf("%s successfully updated\n", argv[1]); 2423e891891SBaptiste Daroussin return (0); 2433e891891SBaptiste Daroussin } 2443e891891SBaptiste Daroussin 2453e891891SBaptiste Daroussin MPS_COMMAND(flash, update, flash_update, "[firmware|bios] file", 2463e891891SBaptiste Daroussin "Update firmware/bios"); 247