1*3e891891SBaptiste Daroussin /*- 2*3e891891SBaptiste Daroussin * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org> 3*3e891891SBaptiste Daroussin * 4*3e891891SBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 5*3e891891SBaptiste Daroussin * modification, are permitted provided that the following conditions 6*3e891891SBaptiste Daroussin * are met: 7*3e891891SBaptiste Daroussin * 1. Redistributions of source code must retain the above copyright 8*3e891891SBaptiste Daroussin * notice, this list of conditions and the following disclaimer. 9*3e891891SBaptiste Daroussin * 2. Redistributions in binary form must reproduce the above copyright 10*3e891891SBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the 11*3e891891SBaptiste Daroussin * documentation and/or other materials provided with the distribution. 12*3e891891SBaptiste Daroussin * 13*3e891891SBaptiste Daroussin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14*3e891891SBaptiste Daroussin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15*3e891891SBaptiste Daroussin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16*3e891891SBaptiste Daroussin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17*3e891891SBaptiste Daroussin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18*3e891891SBaptiste Daroussin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19*3e891891SBaptiste Daroussin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20*3e891891SBaptiste Daroussin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21*3e891891SBaptiste Daroussin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22*3e891891SBaptiste Daroussin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23*3e891891SBaptiste Daroussin * SUCH DAMAGE. 24*3e891891SBaptiste Daroussin */ 25*3e891891SBaptiste Daroussin 26*3e891891SBaptiste Daroussin #include <sys/cdefs.h> 27*3e891891SBaptiste Daroussin __RCSID("$FreeBSD$"); 28*3e891891SBaptiste Daroussin 29*3e891891SBaptiste Daroussin #include <sys/stat.h> 30*3e891891SBaptiste Daroussin #include <sys/param.h> 31*3e891891SBaptiste Daroussin #include <sys/mman.h> 32*3e891891SBaptiste Daroussin 33*3e891891SBaptiste Daroussin #include <errno.h> 34*3e891891SBaptiste Daroussin #include <err.h> 35*3e891891SBaptiste Daroussin #include <fcntl.h> 36*3e891891SBaptiste Daroussin #include <stdbool.h> 37*3e891891SBaptiste Daroussin #include <stdio.h> 38*3e891891SBaptiste Daroussin #include <stdlib.h> 39*3e891891SBaptiste Daroussin #include <string.h> 40*3e891891SBaptiste Daroussin #include <unistd.h> 41*3e891891SBaptiste Daroussin 42*3e891891SBaptiste Daroussin #include "mpsutil.h" 43*3e891891SBaptiste Daroussin 44*3e891891SBaptiste Daroussin MPS_TABLE(top, flash); 45*3e891891SBaptiste Daroussin 46*3e891891SBaptiste Daroussin static int 47*3e891891SBaptiste Daroussin flash_save(int argc, char **argv) 48*3e891891SBaptiste Daroussin { 49*3e891891SBaptiste Daroussin const char *firmware_file; 50*3e891891SBaptiste Daroussin unsigned char *firmware_buffer = NULL; 51*3e891891SBaptiste Daroussin int error, fd, size; 52*3e891891SBaptiste Daroussin bool bios = false; 53*3e891891SBaptiste Daroussin ssize_t written = 0, ret = 0; 54*3e891891SBaptiste Daroussin 55*3e891891SBaptiste Daroussin if (argc < 2) { 56*3e891891SBaptiste Daroussin warnx("missing argument: expecting 'firmware' or bios'"); 57*3e891891SBaptiste Daroussin return (EINVAL); 58*3e891891SBaptiste Daroussin } 59*3e891891SBaptiste Daroussin 60*3e891891SBaptiste Daroussin if (strcmp(argv[1], "bios") == 0) { 61*3e891891SBaptiste Daroussin bios = true; 62*3e891891SBaptiste Daroussin } else if (strcmp(argv[1], "firmware") != 0) { 63*3e891891SBaptiste Daroussin warnx("Invalid argument '%s', expecting 'firmware' or 'bios'", 64*3e891891SBaptiste Daroussin argv[1]); 65*3e891891SBaptiste Daroussin } 66*3e891891SBaptiste Daroussin 67*3e891891SBaptiste Daroussin if (argc > 4) { 68*3e891891SBaptiste Daroussin warnx("save %s: extra arguments", argv[1]); 69*3e891891SBaptiste Daroussin return (EINVAL); 70*3e891891SBaptiste Daroussin } 71*3e891891SBaptiste Daroussin 72*3e891891SBaptiste Daroussin firmware_file = argv[1]; 73*3e891891SBaptiste Daroussin if (argc == 3) { 74*3e891891SBaptiste Daroussin firmware_file = argv[2]; 75*3e891891SBaptiste Daroussin } 76*3e891891SBaptiste Daroussin 77*3e891891SBaptiste Daroussin fd = mps_open(mps_unit); 78*3e891891SBaptiste Daroussin if (fd < 0) { 79*3e891891SBaptiste Daroussin error = errno; 80*3e891891SBaptiste Daroussin warn("mps_open"); 81*3e891891SBaptiste Daroussin return (error); 82*3e891891SBaptiste Daroussin } 83*3e891891SBaptiste Daroussin 84*3e891891SBaptiste Daroussin if ((size = mps_firmware_get(fd, &firmware_buffer, bios)) < 0) { 85*3e891891SBaptiste Daroussin warnx("Fail to save %s", argv[1]); 86*3e891891SBaptiste Daroussin return (1); 87*3e891891SBaptiste Daroussin } 88*3e891891SBaptiste Daroussin 89*3e891891SBaptiste Daroussin close(fd); 90*3e891891SBaptiste Daroussin if (size > 0) { 91*3e891891SBaptiste Daroussin fd = open(firmware_file, O_CREAT | O_TRUNC | O_RDWR, 0644); 92*3e891891SBaptiste Daroussin if (fd <0) { 93*3e891891SBaptiste Daroussin error = errno; 94*3e891891SBaptiste Daroussin warn("open"); 95*3e891891SBaptiste Daroussin free(firmware_buffer); 96*3e891891SBaptiste Daroussin return (error); 97*3e891891SBaptiste Daroussin } 98*3e891891SBaptiste Daroussin while (written != size) { 99*3e891891SBaptiste Daroussin if ((ret = write(fd, firmware_buffer + written, size - written)) <0) { 100*3e891891SBaptiste Daroussin error = errno; 101*3e891891SBaptiste Daroussin warn("write"); 102*3e891891SBaptiste Daroussin free(firmware_buffer); 103*3e891891SBaptiste Daroussin return (error); 104*3e891891SBaptiste Daroussin } 105*3e891891SBaptiste Daroussin written += ret; 106*3e891891SBaptiste Daroussin } 107*3e891891SBaptiste Daroussin close(fd); 108*3e891891SBaptiste Daroussin } 109*3e891891SBaptiste Daroussin free(firmware_buffer); 110*3e891891SBaptiste Daroussin printf("%s successfully saved as %s\n", argv[1], firmware_file); 111*3e891891SBaptiste Daroussin return (0); 112*3e891891SBaptiste Daroussin } 113*3e891891SBaptiste Daroussin 114*3e891891SBaptiste Daroussin MPS_COMMAND(flash, save, flash_save, "[firmware|bios] [file]", 115*3e891891SBaptiste Daroussin "Save firmware/bios into a file"); 116*3e891891SBaptiste Daroussin 117*3e891891SBaptiste Daroussin static int 118*3e891891SBaptiste Daroussin flash_update(int argc, char **argv) 119*3e891891SBaptiste Daroussin { 120*3e891891SBaptiste Daroussin int error, fd; 121*3e891891SBaptiste Daroussin unsigned char *mem = NULL; 122*3e891891SBaptiste Daroussin struct stat st; 123*3e891891SBaptiste Daroussin bool bios = false; 124*3e891891SBaptiste Daroussin MPI2_FW_IMAGE_HEADER *fwheader; 125*3e891891SBaptiste Daroussin MPI2_IOC_FACTS_REPLY *facts; 126*3e891891SBaptiste Daroussin 127*3e891891SBaptiste Daroussin if (argc < 2) { 128*3e891891SBaptiste Daroussin warnx("missing argument: expecting 'firmware' or bios'"); 129*3e891891SBaptiste Daroussin return (EINVAL); 130*3e891891SBaptiste Daroussin } 131*3e891891SBaptiste Daroussin 132*3e891891SBaptiste Daroussin if (strcmp(argv[1], "bios") == 0) { 133*3e891891SBaptiste Daroussin bios = true; 134*3e891891SBaptiste Daroussin } else if (strcmp(argv[1], "firmware") != 0) { 135*3e891891SBaptiste Daroussin warnx("Invalid argument '%s', expecting 'firmware' or 'bios'", 136*3e891891SBaptiste Daroussin argv[1]); 137*3e891891SBaptiste Daroussin } 138*3e891891SBaptiste Daroussin 139*3e891891SBaptiste Daroussin if (argc > 4) { 140*3e891891SBaptiste Daroussin warnx("update firmware: extra arguments"); 141*3e891891SBaptiste Daroussin return (EINVAL); 142*3e891891SBaptiste Daroussin } 143*3e891891SBaptiste Daroussin 144*3e891891SBaptiste Daroussin if (argc != 3) { 145*3e891891SBaptiste Daroussin warnx("no firmware specified"); 146*3e891891SBaptiste Daroussin return (EINVAL); 147*3e891891SBaptiste Daroussin } 148*3e891891SBaptiste Daroussin 149*3e891891SBaptiste Daroussin if (stat(argv[2], &st) == -1) { 150*3e891891SBaptiste Daroussin error = errno; 151*3e891891SBaptiste Daroussin warn("stat"); 152*3e891891SBaptiste Daroussin return (error); 153*3e891891SBaptiste Daroussin } 154*3e891891SBaptiste Daroussin 155*3e891891SBaptiste Daroussin fd = open(argv[2], O_RDONLY); 156*3e891891SBaptiste Daroussin if (fd < 0) { 157*3e891891SBaptiste Daroussin error = errno; 158*3e891891SBaptiste Daroussin warn("open"); 159*3e891891SBaptiste Daroussin return (error); 160*3e891891SBaptiste Daroussin } 161*3e891891SBaptiste Daroussin 162*3e891891SBaptiste Daroussin mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 163*3e891891SBaptiste Daroussin if (mem == MAP_FAILED) { 164*3e891891SBaptiste Daroussin error = errno; 165*3e891891SBaptiste Daroussin warn("mmap"); 166*3e891891SBaptiste Daroussin close(fd); 167*3e891891SBaptiste Daroussin return (error); 168*3e891891SBaptiste Daroussin } 169*3e891891SBaptiste Daroussin close(fd); 170*3e891891SBaptiste Daroussin 171*3e891891SBaptiste Daroussin fd = mps_open(mps_unit); 172*3e891891SBaptiste Daroussin if (fd < 0) { 173*3e891891SBaptiste Daroussin error = errno; 174*3e891891SBaptiste Daroussin warn("mps_open"); 175*3e891891SBaptiste Daroussin munmap(mem, st.st_size); 176*3e891891SBaptiste Daroussin return (error); 177*3e891891SBaptiste Daroussin } 178*3e891891SBaptiste Daroussin 179*3e891891SBaptiste Daroussin if ((facts = mps_get_iocfacts(fd)) == NULL) { 180*3e891891SBaptiste Daroussin warnx("could not get controller IOCFacts\n"); 181*3e891891SBaptiste Daroussin munmap(mem, st.st_size); 182*3e891891SBaptiste Daroussin close(fd); 183*3e891891SBaptiste Daroussin return (EINVAL); 184*3e891891SBaptiste Daroussin } 185*3e891891SBaptiste Daroussin 186*3e891891SBaptiste Daroussin if (bios) { 187*3e891891SBaptiste Daroussin /* Check boot record magic number */ 188*3e891891SBaptiste Daroussin if (((mem[0x01]<<8) + mem[0x00]) != 0xaa55) { 189*3e891891SBaptiste Daroussin warnx("Invalid bios: no boot record magic number"); 190*3e891891SBaptiste Daroussin munmap(mem, st.st_size); 191*3e891891SBaptiste Daroussin close(fd); 192*3e891891SBaptiste Daroussin return (1); 193*3e891891SBaptiste Daroussin } 194*3e891891SBaptiste Daroussin if ((st.st_size % 512) != 0) { 195*3e891891SBaptiste Daroussin warnx("Invalid bios: size not a multiple of 512"); 196*3e891891SBaptiste Daroussin munmap(mem, st.st_size); 197*3e891891SBaptiste Daroussin close(fd); 198*3e891891SBaptiste Daroussin return (1); 199*3e891891SBaptiste Daroussin } 200*3e891891SBaptiste Daroussin } else { 201*3e891891SBaptiste Daroussin fwheader = (MPI2_FW_IMAGE_HEADER *)mem; 202*3e891891SBaptiste Daroussin if (fwheader->VendorID != MPI2_MFGPAGE_VENDORID_LSI) { 203*3e891891SBaptiste Daroussin warnx("Invalid firmware:"); 204*3e891891SBaptiste Daroussin warnx(" Expected Vendor ID: %04x", 205*3e891891SBaptiste Daroussin MPI2_MFGPAGE_VENDORID_LSI); 206*3e891891SBaptiste Daroussin warnx(" Image Vendor ID: %04x", fwheader->VendorID); 207*3e891891SBaptiste Daroussin munmap(mem, st.st_size); 208*3e891891SBaptiste Daroussin close(fd); 209*3e891891SBaptiste Daroussin return (1); 210*3e891891SBaptiste Daroussin } 211*3e891891SBaptiste Daroussin 212*3e891891SBaptiste Daroussin if (fwheader->ProductID != facts->ProductID) { 213*3e891891SBaptiste Daroussin warnx("Invalid image:"); 214*3e891891SBaptiste Daroussin warnx(" Expected Product ID: %04x", facts->ProductID); 215*3e891891SBaptiste Daroussin warnx(" Image Product ID: %04x", fwheader->ProductID); 216*3e891891SBaptiste Daroussin munmap(mem, st.st_size); 217*3e891891SBaptiste Daroussin close(fd); 218*3e891891SBaptiste Daroussin return (1); 219*3e891891SBaptiste Daroussin } 220*3e891891SBaptiste Daroussin } 221*3e891891SBaptiste Daroussin 222*3e891891SBaptiste Daroussin printf("Updating %s...\n", argv[1]); 223*3e891891SBaptiste Daroussin if (mps_firmware_send(fd, mem, st.st_size, bios) < 0) { 224*3e891891SBaptiste Daroussin warnx("Fail to update %s", argv[1]); 225*3e891891SBaptiste Daroussin munmap(mem, st.st_size); 226*3e891891SBaptiste Daroussin close(fd); 227*3e891891SBaptiste Daroussin return (1); 228*3e891891SBaptiste Daroussin } 229*3e891891SBaptiste Daroussin 230*3e891891SBaptiste Daroussin munmap(mem, st.st_size); 231*3e891891SBaptiste Daroussin close(fd); 232*3e891891SBaptiste Daroussin printf("%s successfully updated\n", argv[1]); 233*3e891891SBaptiste Daroussin return (0); 234*3e891891SBaptiste Daroussin } 235*3e891891SBaptiste Daroussin 236*3e891891SBaptiste Daroussin MPS_COMMAND(flash, update, flash_update, "[firmware|bios] file", 237*3e891891SBaptiste Daroussin "Update firmware/bios"); 238