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 __RCSID("$FreeBSD$"); 28 29 #include <sys/stat.h> 30 #include <sys/param.h> 31 #include <sys/mman.h> 32 #include <sys/endian.h> 33 34 #include <errno.h> 35 #include <err.h> 36 #include <fcntl.h> 37 #include <stdbool.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 43 #include "mpsutil.h" 44 45 MPS_TABLE(top, flash); 46 47 static int 48 flash_save(int argc, char **argv) 49 { 50 const char *firmware_file; 51 unsigned char *firmware_buffer = NULL; 52 int error, fd, size; 53 bool bios = false; 54 ssize_t written = 0, ret = 0; 55 56 if (argc < 2) { 57 warnx("missing argument: expecting 'firmware' or bios'"); 58 return (EINVAL); 59 } 60 61 if (strcmp(argv[1], "bios") == 0) { 62 bios = true; 63 } else if (strcmp(argv[1], "firmware") != 0) { 64 warnx("Invalid argument '%s', expecting 'firmware' or 'bios'", 65 argv[1]); 66 } 67 68 if (argc > 4) { 69 warnx("save %s: extra arguments", argv[1]); 70 return (EINVAL); 71 } 72 73 firmware_file = argv[1]; 74 if (argc == 3) { 75 firmware_file = argv[2]; 76 } 77 78 fd = mps_open(mps_unit); 79 if (fd < 0) { 80 error = errno; 81 warn("mps_open"); 82 return (error); 83 } 84 85 if ((size = mps_firmware_get(fd, &firmware_buffer, bios)) < 0) { 86 warnx("Fail to save %s", argv[1]); 87 close(fd); 88 return (1); 89 } 90 91 close(fd); 92 if (size > 0) { 93 fd = open(firmware_file, O_CREAT | O_TRUNC | O_RDWR, 0644); 94 if (fd <0) { 95 error = errno; 96 warn("open"); 97 free(firmware_buffer); 98 return (error); 99 } 100 while (written != size) { 101 if ((ret = write(fd, firmware_buffer + written, size - written)) <0) { 102 error = errno; 103 warn("write"); 104 free(firmware_buffer); 105 close(fd); 106 return (error); 107 } 108 written += ret; 109 } 110 close(fd); 111 } 112 free(firmware_buffer); 113 printf("%s successfully saved as %s\n", argv[1], firmware_file); 114 return (0); 115 } 116 117 MPS_COMMAND(flash, save, flash_save, "[firmware|bios] [file]", 118 "Save firmware/bios into a file"); 119 120 static int 121 flash_update(int argc, char **argv) 122 { 123 int error, fd; 124 unsigned char *mem = NULL; 125 struct stat st; 126 bool bios = false; 127 MPI2_FW_IMAGE_HEADER *fwheader; 128 MPI2_IOC_FACTS_REPLY *facts; 129 130 if (argc < 2) { 131 warnx("missing argument: expecting 'firmware' or bios'"); 132 return (EINVAL); 133 } 134 135 if (strcmp(argv[1], "bios") == 0) { 136 bios = true; 137 } else if (strcmp(argv[1], "firmware") != 0) { 138 warnx("Invalid argument '%s', expecting 'firmware' or 'bios'", 139 argv[1]); 140 } 141 142 if (argc > 4) { 143 warnx("update firmware: extra arguments"); 144 return (EINVAL); 145 } 146 147 if (argc != 3) { 148 warnx("no firmware specified"); 149 return (EINVAL); 150 } 151 152 if (stat(argv[2], &st) == -1) { 153 error = errno; 154 warn("stat"); 155 return (error); 156 } 157 158 fd = open(argv[2], O_RDONLY); 159 if (fd < 0) { 160 error = errno; 161 warn("open"); 162 return (error); 163 } 164 165 mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 166 if (mem == MAP_FAILED) { 167 error = errno; 168 warn("mmap"); 169 close(fd); 170 return (error); 171 } 172 close(fd); 173 174 fd = mps_open(mps_unit); 175 if (fd < 0) { 176 error = errno; 177 warn("mps_open"); 178 munmap(mem, st.st_size); 179 return (error); 180 } 181 182 if ((facts = mps_get_iocfacts(fd)) == NULL) { 183 warnx("could not get controller IOCFacts\n"); 184 munmap(mem, st.st_size); 185 close(fd); 186 return (EINVAL); 187 } 188 189 if (bios) { 190 /* Check boot record magic number */ 191 if (((mem[0x01]<<8) + mem[0x00]) != 0xaa55) { 192 warnx("Invalid bios: no boot record magic number"); 193 munmap(mem, st.st_size); 194 close(fd); 195 free(facts); 196 return (1); 197 } 198 if ((st.st_size % 512) != 0) { 199 warnx("Invalid bios: size not a multiple of 512"); 200 munmap(mem, st.st_size); 201 close(fd); 202 free(facts); 203 return (1); 204 } 205 } else { 206 fwheader = (MPI2_FW_IMAGE_HEADER *)mem; 207 if (le16toh(fwheader->VendorID) != MPI2_MFGPAGE_VENDORID_LSI) { 208 warnx("Invalid firmware:"); 209 warnx(" Expected Vendor ID: %04x", 210 MPI2_MFGPAGE_VENDORID_LSI); 211 warnx(" Image Vendor ID: %04x", le16toh(fwheader->VendorID)); 212 munmap(mem, st.st_size); 213 close(fd); 214 free(facts); 215 return (1); 216 } 217 218 if (le16toh(fwheader->ProductID) != facts->ProductID) { 219 warnx("Invalid image:"); 220 warnx(" Expected Product ID: %04x", facts->ProductID); 221 warnx(" Image Product ID: %04x", le16toh(fwheader->ProductID)); 222 munmap(mem, st.st_size); 223 close(fd); 224 free(facts); 225 return (1); 226 } 227 } 228 229 printf("Updating %s...\n", argv[1]); 230 if (mps_firmware_send(fd, mem, st.st_size, bios) < 0) { 231 warnx("Fail to update %s", argv[1]); 232 munmap(mem, st.st_size); 233 close(fd); 234 free(facts); 235 return (1); 236 } 237 238 munmap(mem, st.st_size); 239 close(fd); 240 free(facts); 241 printf("%s successfully updated\n", argv[1]); 242 return (0); 243 } 244 245 MPS_COMMAND(flash, update, flash_update, "[firmware|bios] file", 246 "Update firmware/bios"); 247