]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/mpsutil/mps_flash.c
MFC r344245:
[FreeBSD/stable/10.git] / usr.sbin / mpsutil / mps_flash.c
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                 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                                 return (error);
104                         }
105                         written += ret;
106                 }
107                 close(fd);
108         }
109         free(firmware_buffer);
110         printf("%s successfully saved as %s\n", argv[1], firmware_file);
111         return (0);
112 }
113
114 MPS_COMMAND(flash, save, flash_save, "[firmware|bios] [file]",
115     "Save firmware/bios into a file");
116
117 static int
118 flash_update(int argc, char **argv)
119 {
120         int error, fd;
121         unsigned char *mem = NULL;
122         struct stat st;
123         bool bios = false;
124         MPI2_FW_IMAGE_HEADER *fwheader;
125         MPI2_IOC_FACTS_REPLY *facts;
126
127         if (argc < 2) {
128                 warnx("missing argument: expecting 'firmware' or bios'");
129                 return (EINVAL);
130         }
131
132         if (strcmp(argv[1], "bios") == 0) {
133                 bios = true;
134         } else if (strcmp(argv[1], "firmware") != 0) {
135                 warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
136                     argv[1]);
137         }
138
139         if (argc > 4) {
140                 warnx("update firmware: extra arguments");
141                 return (EINVAL);
142         }
143
144         if (argc != 3) {
145                 warnx("no firmware specified");
146                 return (EINVAL);
147         }
148
149         if (stat(argv[2], &st) == -1) {
150                 error = errno;
151                 warn("stat");
152                 return (error);
153         }
154
155         fd = open(argv[2], O_RDONLY);
156         if (fd < 0) {
157                 error = errno;
158                 warn("open");
159                 return (error);
160         }
161
162         mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
163         if (mem == MAP_FAILED) {
164                 error = errno;
165                 warn("mmap");
166                 close(fd);
167                 return (error);
168         }
169         close(fd);
170
171         fd = mps_open(mps_unit);
172         if (fd < 0) {
173                 error = errno;
174                 warn("mps_open");
175                 munmap(mem, st.st_size);
176                 return (error);
177         }
178
179         if ((facts = mps_get_iocfacts(fd)) == NULL) {
180                 warnx("could not get controller IOCFacts\n");
181                 munmap(mem, st.st_size);
182                 close(fd);
183                 return (EINVAL);
184         }
185
186         if (bios) {
187                 /* Check boot record magic number */
188                 if (((mem[0x01]<<8) + mem[0x00]) != 0xaa55) {
189                         warnx("Invalid bios: no boot record magic number");
190                         munmap(mem, st.st_size);
191                         close(fd);
192                         return (1);
193                 }
194                 if ((st.st_size % 512) != 0) {
195                         warnx("Invalid bios: size not a multiple of 512");
196                         munmap(mem, st.st_size);
197                         close(fd);
198                         return (1);
199                 }
200         } else {
201                 fwheader = (MPI2_FW_IMAGE_HEADER *)mem;
202                 if (fwheader->VendorID != MPI2_MFGPAGE_VENDORID_LSI) {
203                         warnx("Invalid firmware:");
204                         warnx("  Expected Vendor ID: %04x",
205                             MPI2_MFGPAGE_VENDORID_LSI);
206                         warnx("  Image Vendor ID: %04x", fwheader->VendorID);
207                         munmap(mem, st.st_size);
208                         close(fd);
209                         return (1);
210                 }
211
212                 if (fwheader->ProductID != facts->ProductID) {
213                         warnx("Invalid image:");
214                         warnx("  Expected Product ID: %04x", facts->ProductID);
215                         warnx("  Image Product ID: %04x", fwheader->ProductID);
216                         munmap(mem, st.st_size);
217                         close(fd);
218                         return (1);
219                 }
220         }
221
222         printf("Updating %s...\n", argv[1]);
223         if (mps_firmware_send(fd, mem, st.st_size, bios) < 0) {
224                 warnx("Fail to update %s", argv[1]);
225                 munmap(mem, st.st_size);
226                 close(fd);
227                 return (1);
228         }
229
230         munmap(mem, st.st_size);
231         close(fd);
232         printf("%s successfully updated\n", argv[1]);
233         return (0);
234 }
235
236 MPS_COMMAND(flash, update, flash_update, "[firmware|bios] file",
237     "Update firmware/bios");