xref: /dragonfly/usr.sbin/mpsutil/mps_flash.c (revision fd501800cafe382e0751b7be1342c553b3335543)
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: head/usr.sbin/mpsutil/mps_flash.c 298374 2016-04-20 21:11:49Z bapt $");
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
flash_save(int argc,char ** argv)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
flash_update(int argc,char ** argv)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