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