bsd-family-tree: Small sync with FreeBSD.
[dragonfly.git] / usr.sbin / mpsutil / mps_flash.c
blob0710c76238cfe7eca17f5d4de07ee6b408a5394d
1 /*-
2 * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
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.
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.
26 #include <sys/cdefs.h>
27 __RCSID("$FreeBSD: head/usr.sbin/mpsutil/mps_flash.c 298374 2016-04-20 21:11:49Z bapt $");
29 #include <sys/stat.h>
30 #include <sys/param.h>
31 #include <sys/mman.h>
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>
42 #include "mpsutil.h"
44 MPS_TABLE(top, flash);
46 static int
47 flash_save(int argc, char **argv)
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;
55 if (argc < 2) {
56 warnx("missing argument: expecting 'firmware' or bios'");
57 return (EINVAL);
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]);
67 if (argc > 4) {
68 warnx("save %s: extra arguments", argv[1]);
69 return (EINVAL);
72 firmware_file = argv[1];
73 if (argc == 3) {
74 firmware_file = argv[2];
77 fd = mps_open(mps_unit);
78 if (fd < 0) {
79 error = errno;
80 warn("mps_open");
81 return (error);
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);
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);
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);
107 written += ret;
109 close(fd);
111 free(firmware_buffer);
112 printf("%s successfully saved as %s\n", argv[1], firmware_file);
113 return (0);
116 MPS_COMMAND(flash, save, flash_save, "[firmware|bios] [file]",
117 "Save firmware/bios into a file");
119 static int
120 flash_update(int argc, char **argv)
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;
129 if (argc < 2) {
130 warnx("missing argument: expecting 'firmware' or bios'");
131 return (EINVAL);
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]);
141 if (argc > 4) {
142 warnx("update firmware: extra arguments");
143 return (EINVAL);
146 if (argc != 3) {
147 warnx("no firmware specified");
148 return (EINVAL);
151 if (stat(argv[2], &st) == -1) {
152 error = errno;
153 warn("stat");
154 return (error);
157 fd = open(argv[2], O_RDONLY);
158 if (fd < 0) {
159 error = errno;
160 warn("open");
161 return (error);
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);
171 close(fd);
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);
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);
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);
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);
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);
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);
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);
237 munmap(mem, st.st_size);
238 close(fd);
239 free(facts);
240 printf("%s successfully updated\n", argv[1]);
241 return (0);
244 MPS_COMMAND(flash, update, flash_update, "[firmware|bios] file",
245 "Update firmware/bios");