1297590Ssbruno/*- 2297590Ssbruno * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org> 3297590Ssbruno * 4297590Ssbruno * Redistribution and use in source and binary forms, with or without 5297590Ssbruno * modification, are permitted provided that the following conditions 6297590Ssbruno * are met: 7297590Ssbruno * 1. Redistributions of source code must retain the above copyright 8297590Ssbruno * notice, this list of conditions and the following disclaimer. 9297590Ssbruno * 2. Redistributions in binary form must reproduce the above copyright 10297590Ssbruno * notice, this list of conditions and the following disclaimer in the 11297590Ssbruno * documentation and/or other materials provided with the distribution. 12297590Ssbruno * 13297590Ssbruno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14297590Ssbruno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15297590Ssbruno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16297590Ssbruno * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17297590Ssbruno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18297590Ssbruno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19297590Ssbruno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20297590Ssbruno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21297590Ssbruno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22297590Ssbruno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23297590Ssbruno * SUCH DAMAGE. 24297590Ssbruno */ 25297590Ssbruno 26297590Ssbruno#include <sys/cdefs.h> 27297590Ssbruno__RCSID("$FreeBSD$"); 28297590Ssbruno 29297590Ssbruno#include <sys/stat.h> 30297590Ssbruno#include <sys/param.h> 31297590Ssbruno#include <sys/mman.h> 32297590Ssbruno 33297590Ssbruno#include <errno.h> 34297590Ssbruno#include <err.h> 35297590Ssbruno#include <fcntl.h> 36297590Ssbruno#include <stdbool.h> 37297590Ssbruno#include <stdio.h> 38297590Ssbruno#include <stdlib.h> 39297590Ssbruno#include <string.h> 40297590Ssbruno#include <unistd.h> 41297590Ssbruno 42297590Ssbruno#include "mpsutil.h" 43297590Ssbruno 44297590SsbrunoMPS_TABLE(top, flash); 45297590Ssbruno 46297590Ssbrunostatic int 47297590Ssbrunoflash_save(int argc, char **argv) 48297590Ssbruno{ 49297590Ssbruno const char *firmware_file; 50297590Ssbruno unsigned char *firmware_buffer = NULL; 51297590Ssbruno int error, fd, size; 52297590Ssbruno bool bios = false; 53297590Ssbruno ssize_t written = 0, ret = 0; 54297590Ssbruno 55297590Ssbruno if (argc < 2) { 56297590Ssbruno warnx("missing argument: expecting 'firmware' or bios'"); 57297590Ssbruno return (EINVAL); 58297590Ssbruno } 59297590Ssbruno 60297590Ssbruno if (strcmp(argv[1], "bios") == 0) { 61297590Ssbruno bios = true; 62297590Ssbruno } else if (strcmp(argv[1], "firmware") != 0) { 63297590Ssbruno warnx("Invalid argument '%s', expecting 'firmware' or 'bios'", 64297590Ssbruno argv[1]); 65297590Ssbruno } 66297590Ssbruno 67297590Ssbruno if (argc > 4) { 68297590Ssbruno warnx("save %s: extra arguments", argv[1]); 69297590Ssbruno return (EINVAL); 70297590Ssbruno } 71297590Ssbruno 72297590Ssbruno firmware_file = argv[1]; 73297590Ssbruno if (argc == 3) { 74297590Ssbruno firmware_file = argv[2]; 75297590Ssbruno } 76297590Ssbruno 77297590Ssbruno fd = mps_open(mps_unit); 78297590Ssbruno if (fd < 0) { 79297590Ssbruno error = errno; 80297590Ssbruno warn("mps_open"); 81297590Ssbruno return (error); 82297590Ssbruno } 83297590Ssbruno 84297590Ssbruno if ((size = mps_firmware_get(fd, &firmware_buffer, bios)) < 0) { 85297590Ssbruno warnx("Fail to save %s", argv[1]); 86297590Ssbruno return (1); 87297590Ssbruno } 88297590Ssbruno 89297590Ssbruno close(fd); 90297590Ssbruno if (size > 0) { 91297590Ssbruno fd = open(firmware_file, O_CREAT | O_TRUNC | O_RDWR, 0644); 92297590Ssbruno if (fd <0) { 93297590Ssbruno error = errno; 94297590Ssbruno warn("open"); 95297590Ssbruno free(firmware_buffer); 96297590Ssbruno return (error); 97297590Ssbruno } 98297590Ssbruno while (written != size) { 99297590Ssbruno if ((ret = write(fd, firmware_buffer + written, size - written)) <0) { 100297590Ssbruno error = errno; 101297590Ssbruno warn("write"); 102297590Ssbruno free(firmware_buffer); 103297590Ssbruno return (error); 104297590Ssbruno } 105297590Ssbruno written += ret; 106297590Ssbruno } 107297590Ssbruno close(fd); 108297590Ssbruno } 109297590Ssbruno free(firmware_buffer); 110297590Ssbruno printf("%s successfully saved as %s\n", argv[1], firmware_file); 111297590Ssbruno return (0); 112297590Ssbruno} 113297590Ssbruno 114297590SsbrunoMPS_COMMAND(flash, save, flash_save, "[firmware|bios] [file]", 115297590Ssbruno "Save firmware/bios into a file"); 116297590Ssbruno 117297590Ssbrunostatic int 118297590Ssbrunoflash_update(int argc, char **argv) 119297590Ssbruno{ 120297590Ssbruno int error, fd; 121297590Ssbruno unsigned char *mem = NULL; 122297590Ssbruno struct stat st; 123297590Ssbruno bool bios = false; 124297590Ssbruno MPI2_FW_IMAGE_HEADER *fwheader; 125297590Ssbruno MPI2_IOC_FACTS_REPLY *facts; 126297590Ssbruno 127297590Ssbruno if (argc < 2) { 128297590Ssbruno warnx("missing argument: expecting 'firmware' or bios'"); 129297590Ssbruno return (EINVAL); 130297590Ssbruno } 131297590Ssbruno 132297590Ssbruno if (strcmp(argv[1], "bios") == 0) { 133297590Ssbruno bios = true; 134297590Ssbruno } else if (strcmp(argv[1], "firmware") != 0) { 135297590Ssbruno warnx("Invalid argument '%s', expecting 'firmware' or 'bios'", 136297590Ssbruno argv[1]); 137297590Ssbruno } 138297590Ssbruno 139297590Ssbruno if (argc > 4) { 140297590Ssbruno warnx("update firmware: extra arguments"); 141297590Ssbruno return (EINVAL); 142297590Ssbruno } 143297590Ssbruno 144297590Ssbruno if (argc != 3) { 145297590Ssbruno warnx("no firmware specified"); 146297590Ssbruno return (EINVAL); 147297590Ssbruno } 148297590Ssbruno 149297590Ssbruno if (stat(argv[2], &st) == -1) { 150297590Ssbruno error = errno; 151297590Ssbruno warn("stat"); 152297590Ssbruno return (error); 153297590Ssbruno } 154297590Ssbruno 155297590Ssbruno fd = open(argv[2], O_RDONLY); 156297590Ssbruno if (fd < 0) { 157297590Ssbruno error = errno; 158297590Ssbruno warn("open"); 159297590Ssbruno return (error); 160297590Ssbruno } 161297590Ssbruno 162297590Ssbruno mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 163297590Ssbruno if (mem == MAP_FAILED) { 164297590Ssbruno error = errno; 165297590Ssbruno warn("mmap"); 166297590Ssbruno close(fd); 167297590Ssbruno return (error); 168297590Ssbruno } 169297590Ssbruno close(fd); 170297590Ssbruno 171297590Ssbruno fd = mps_open(mps_unit); 172297590Ssbruno if (fd < 0) { 173297590Ssbruno error = errno; 174297590Ssbruno warn("mps_open"); 175297590Ssbruno munmap(mem, st.st_size); 176297590Ssbruno return (error); 177297590Ssbruno } 178297590Ssbruno 179297590Ssbruno if ((facts = mps_get_iocfacts(fd)) == NULL) { 180297590Ssbruno warnx("could not get controller IOCFacts\n"); 181297590Ssbruno munmap(mem, st.st_size); 182297590Ssbruno close(fd); 183297590Ssbruno return (EINVAL); 184297590Ssbruno } 185297590Ssbruno 186297590Ssbruno if (bios) { 187297590Ssbruno /* Check boot record magic number */ 188297590Ssbruno if (((mem[0x01]<<8) + mem[0x00]) != 0xaa55) { 189297590Ssbruno warnx("Invalid bios: no boot record magic number"); 190297590Ssbruno munmap(mem, st.st_size); 191297590Ssbruno close(fd); 192297590Ssbruno return (1); 193297590Ssbruno } 194297590Ssbruno if ((st.st_size % 512) != 0) { 195297590Ssbruno warnx("Invalid bios: size not a multiple of 512"); 196297590Ssbruno munmap(mem, st.st_size); 197297590Ssbruno close(fd); 198297590Ssbruno return (1); 199297590Ssbruno } 200297590Ssbruno } else { 201297590Ssbruno fwheader = (MPI2_FW_IMAGE_HEADER *)mem; 202297590Ssbruno if (fwheader->VendorID != MPI2_MFGPAGE_VENDORID_LSI) { 203297590Ssbruno warnx("Invalid firmware:"); 204297590Ssbruno warnx(" Expected Vendor ID: %04x", 205297590Ssbruno MPI2_MFGPAGE_VENDORID_LSI); 206297590Ssbruno warnx(" Image Vendor ID: %04x", fwheader->VendorID); 207297590Ssbruno munmap(mem, st.st_size); 208297590Ssbruno close(fd); 209297590Ssbruno return (1); 210297590Ssbruno } 211297590Ssbruno 212297590Ssbruno if (fwheader->ProductID != facts->ProductID) { 213297590Ssbruno warnx("Invalid image:"); 214297590Ssbruno warnx(" Expected Product ID: %04x", facts->ProductID); 215297590Ssbruno warnx(" Image Product ID: %04x", fwheader->ProductID); 216297590Ssbruno munmap(mem, st.st_size); 217297590Ssbruno close(fd); 218297590Ssbruno return (1); 219297590Ssbruno } 220297590Ssbruno } 221297590Ssbruno 222297590Ssbruno printf("Updating %s...\n", argv[1]); 223297590Ssbruno if (mps_firmware_send(fd, mem, st.st_size, bios) < 0) { 224297590Ssbruno warnx("Fail to update %s", argv[1]); 225297590Ssbruno munmap(mem, st.st_size); 226297590Ssbruno close(fd); 227297590Ssbruno return (1); 228297590Ssbruno } 229297590Ssbruno 230297590Ssbruno munmap(mem, st.st_size); 231297590Ssbruno close(fd); 232297590Ssbruno printf("%s successfully updated\n", argv[1]); 233297590Ssbruno return (0); 234297590Ssbruno} 235297590Ssbruno 236297590SsbrunoMPS_COMMAND(flash, update, flash_update, "[firmware|bios] file", 237297590Ssbruno "Update firmware/bios"); 238