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