xref: /freebsd/usr.sbin/mpsutil/mps_flash.c (revision 3e8918911e5c71aca9310fa190a85c7351da31af)
1*3e891891SBaptiste Daroussin /*-
2*3e891891SBaptiste Daroussin  * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
3*3e891891SBaptiste Daroussin  *
4*3e891891SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
5*3e891891SBaptiste Daroussin  * modification, are permitted provided that the following conditions
6*3e891891SBaptiste Daroussin  * are met:
7*3e891891SBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
8*3e891891SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer.
9*3e891891SBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
10*3e891891SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
11*3e891891SBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
12*3e891891SBaptiste Daroussin  *
13*3e891891SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14*3e891891SBaptiste Daroussin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15*3e891891SBaptiste Daroussin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16*3e891891SBaptiste Daroussin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17*3e891891SBaptiste Daroussin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18*3e891891SBaptiste Daroussin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19*3e891891SBaptiste Daroussin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20*3e891891SBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21*3e891891SBaptiste Daroussin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22*3e891891SBaptiste Daroussin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23*3e891891SBaptiste Daroussin  * SUCH DAMAGE.
24*3e891891SBaptiste Daroussin  */
25*3e891891SBaptiste Daroussin 
26*3e891891SBaptiste Daroussin #include <sys/cdefs.h>
27*3e891891SBaptiste Daroussin __RCSID("$FreeBSD$");
28*3e891891SBaptiste Daroussin 
29*3e891891SBaptiste Daroussin #include <sys/stat.h>
30*3e891891SBaptiste Daroussin #include <sys/param.h>
31*3e891891SBaptiste Daroussin #include <sys/mman.h>
32*3e891891SBaptiste Daroussin 
33*3e891891SBaptiste Daroussin #include <errno.h>
34*3e891891SBaptiste Daroussin #include <err.h>
35*3e891891SBaptiste Daroussin #include <fcntl.h>
36*3e891891SBaptiste Daroussin #include <stdbool.h>
37*3e891891SBaptiste Daroussin #include <stdio.h>
38*3e891891SBaptiste Daroussin #include <stdlib.h>
39*3e891891SBaptiste Daroussin #include <string.h>
40*3e891891SBaptiste Daroussin #include <unistd.h>
41*3e891891SBaptiste Daroussin 
42*3e891891SBaptiste Daroussin #include "mpsutil.h"
43*3e891891SBaptiste Daroussin 
44*3e891891SBaptiste Daroussin MPS_TABLE(top, flash);
45*3e891891SBaptiste Daroussin 
46*3e891891SBaptiste Daroussin static int
47*3e891891SBaptiste Daroussin flash_save(int argc, char **argv)
48*3e891891SBaptiste Daroussin {
49*3e891891SBaptiste Daroussin 	const char *firmware_file;
50*3e891891SBaptiste Daroussin 	unsigned char *firmware_buffer = NULL;
51*3e891891SBaptiste Daroussin 	int error, fd, size;
52*3e891891SBaptiste Daroussin 	bool bios = false;
53*3e891891SBaptiste Daroussin 	ssize_t written = 0, ret = 0;
54*3e891891SBaptiste Daroussin 
55*3e891891SBaptiste Daroussin 	if (argc < 2) {
56*3e891891SBaptiste Daroussin 		warnx("missing argument: expecting 'firmware' or bios'");
57*3e891891SBaptiste Daroussin 		return (EINVAL);
58*3e891891SBaptiste Daroussin 	}
59*3e891891SBaptiste Daroussin 
60*3e891891SBaptiste Daroussin 	if (strcmp(argv[1], "bios") == 0) {
61*3e891891SBaptiste Daroussin 		bios = true;
62*3e891891SBaptiste Daroussin 	} else if (strcmp(argv[1], "firmware") != 0) {
63*3e891891SBaptiste Daroussin 		warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
64*3e891891SBaptiste Daroussin 		    argv[1]);
65*3e891891SBaptiste Daroussin 	}
66*3e891891SBaptiste Daroussin 
67*3e891891SBaptiste Daroussin 	if (argc > 4) {
68*3e891891SBaptiste Daroussin 		warnx("save %s: extra arguments", argv[1]);
69*3e891891SBaptiste Daroussin 		return (EINVAL);
70*3e891891SBaptiste Daroussin 	}
71*3e891891SBaptiste Daroussin 
72*3e891891SBaptiste Daroussin 	firmware_file = argv[1];
73*3e891891SBaptiste Daroussin 	if (argc == 3) {
74*3e891891SBaptiste Daroussin 		firmware_file = argv[2];
75*3e891891SBaptiste Daroussin 	}
76*3e891891SBaptiste Daroussin 
77*3e891891SBaptiste Daroussin 	fd = mps_open(mps_unit);
78*3e891891SBaptiste Daroussin 	if (fd < 0) {
79*3e891891SBaptiste Daroussin 		error = errno;
80*3e891891SBaptiste Daroussin 		warn("mps_open");
81*3e891891SBaptiste Daroussin 		return (error);
82*3e891891SBaptiste Daroussin 	}
83*3e891891SBaptiste Daroussin 
84*3e891891SBaptiste Daroussin 	if ((size = mps_firmware_get(fd, &firmware_buffer, bios)) < 0) {
85*3e891891SBaptiste Daroussin 		warnx("Fail to save %s", argv[1]);
86*3e891891SBaptiste Daroussin 		return (1);
87*3e891891SBaptiste Daroussin 	}
88*3e891891SBaptiste Daroussin 
89*3e891891SBaptiste Daroussin 	close(fd);
90*3e891891SBaptiste Daroussin 	if (size > 0) {
91*3e891891SBaptiste Daroussin 		fd = open(firmware_file, O_CREAT | O_TRUNC | O_RDWR, 0644);
92*3e891891SBaptiste Daroussin 		if (fd <0) {
93*3e891891SBaptiste Daroussin 			error = errno;
94*3e891891SBaptiste Daroussin 			warn("open");
95*3e891891SBaptiste Daroussin 			free(firmware_buffer);
96*3e891891SBaptiste Daroussin 			return (error);
97*3e891891SBaptiste Daroussin 		}
98*3e891891SBaptiste Daroussin 		while (written != size) {
99*3e891891SBaptiste Daroussin 			if ((ret = write(fd, firmware_buffer + written, size - written)) <0) {
100*3e891891SBaptiste Daroussin 				error = errno;
101*3e891891SBaptiste Daroussin 				warn("write");
102*3e891891SBaptiste Daroussin 				free(firmware_buffer);
103*3e891891SBaptiste Daroussin 				return (error);
104*3e891891SBaptiste Daroussin 			}
105*3e891891SBaptiste Daroussin 			written += ret;
106*3e891891SBaptiste Daroussin 		}
107*3e891891SBaptiste Daroussin 		close(fd);
108*3e891891SBaptiste Daroussin 	}
109*3e891891SBaptiste Daroussin 	free(firmware_buffer);
110*3e891891SBaptiste Daroussin 	printf("%s successfully saved as %s\n", argv[1], firmware_file);
111*3e891891SBaptiste Daroussin 	return (0);
112*3e891891SBaptiste Daroussin }
113*3e891891SBaptiste Daroussin 
114*3e891891SBaptiste Daroussin MPS_COMMAND(flash, save, flash_save, "[firmware|bios] [file]",
115*3e891891SBaptiste Daroussin     "Save firmware/bios into a file");
116*3e891891SBaptiste Daroussin 
117*3e891891SBaptiste Daroussin static int
118*3e891891SBaptiste Daroussin flash_update(int argc, char **argv)
119*3e891891SBaptiste Daroussin {
120*3e891891SBaptiste Daroussin 	int error, fd;
121*3e891891SBaptiste Daroussin 	unsigned char *mem = NULL;
122*3e891891SBaptiste Daroussin 	struct stat st;
123*3e891891SBaptiste Daroussin 	bool bios = false;
124*3e891891SBaptiste Daroussin 	MPI2_FW_IMAGE_HEADER *fwheader;
125*3e891891SBaptiste Daroussin 	MPI2_IOC_FACTS_REPLY *facts;
126*3e891891SBaptiste Daroussin 
127*3e891891SBaptiste Daroussin 	if (argc < 2) {
128*3e891891SBaptiste Daroussin 		warnx("missing argument: expecting 'firmware' or bios'");
129*3e891891SBaptiste Daroussin 		return (EINVAL);
130*3e891891SBaptiste Daroussin 	}
131*3e891891SBaptiste Daroussin 
132*3e891891SBaptiste Daroussin 	if (strcmp(argv[1], "bios") == 0) {
133*3e891891SBaptiste Daroussin 		bios = true;
134*3e891891SBaptiste Daroussin 	} else if (strcmp(argv[1], "firmware") != 0) {
135*3e891891SBaptiste Daroussin 		warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
136*3e891891SBaptiste Daroussin 		    argv[1]);
137*3e891891SBaptiste Daroussin 	}
138*3e891891SBaptiste Daroussin 
139*3e891891SBaptiste Daroussin 	if (argc > 4) {
140*3e891891SBaptiste Daroussin 		warnx("update firmware: extra arguments");
141*3e891891SBaptiste Daroussin 		return (EINVAL);
142*3e891891SBaptiste Daroussin 	}
143*3e891891SBaptiste Daroussin 
144*3e891891SBaptiste Daroussin 	if (argc != 3) {
145*3e891891SBaptiste Daroussin 		warnx("no firmware specified");
146*3e891891SBaptiste Daroussin 		return (EINVAL);
147*3e891891SBaptiste Daroussin 	}
148*3e891891SBaptiste Daroussin 
149*3e891891SBaptiste Daroussin 	if (stat(argv[2], &st) == -1) {
150*3e891891SBaptiste Daroussin 		error = errno;
151*3e891891SBaptiste Daroussin 		warn("stat");
152*3e891891SBaptiste Daroussin 		return (error);
153*3e891891SBaptiste Daroussin 	}
154*3e891891SBaptiste Daroussin 
155*3e891891SBaptiste Daroussin 	fd = open(argv[2], O_RDONLY);
156*3e891891SBaptiste Daroussin 	if (fd < 0) {
157*3e891891SBaptiste Daroussin 		error = errno;
158*3e891891SBaptiste Daroussin 		warn("open");
159*3e891891SBaptiste Daroussin 		return (error);
160*3e891891SBaptiste Daroussin 	}
161*3e891891SBaptiste Daroussin 
162*3e891891SBaptiste Daroussin 	mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
163*3e891891SBaptiste Daroussin 	if (mem == MAP_FAILED) {
164*3e891891SBaptiste Daroussin 		error = errno;
165*3e891891SBaptiste Daroussin 		warn("mmap");
166*3e891891SBaptiste Daroussin 		close(fd);
167*3e891891SBaptiste Daroussin 		return (error);
168*3e891891SBaptiste Daroussin 	}
169*3e891891SBaptiste Daroussin 	close(fd);
170*3e891891SBaptiste Daroussin 
171*3e891891SBaptiste Daroussin 	fd = mps_open(mps_unit);
172*3e891891SBaptiste Daroussin 	if (fd < 0) {
173*3e891891SBaptiste Daroussin 		error = errno;
174*3e891891SBaptiste Daroussin 		warn("mps_open");
175*3e891891SBaptiste Daroussin 		munmap(mem, st.st_size);
176*3e891891SBaptiste Daroussin 		return (error);
177*3e891891SBaptiste Daroussin 	}
178*3e891891SBaptiste Daroussin 
179*3e891891SBaptiste Daroussin 	if ((facts = mps_get_iocfacts(fd)) == NULL) {
180*3e891891SBaptiste Daroussin 		warnx("could not get controller IOCFacts\n");
181*3e891891SBaptiste Daroussin 		munmap(mem, st.st_size);
182*3e891891SBaptiste Daroussin 		close(fd);
183*3e891891SBaptiste Daroussin 		return (EINVAL);
184*3e891891SBaptiste Daroussin 	}
185*3e891891SBaptiste Daroussin 
186*3e891891SBaptiste Daroussin 	if (bios) {
187*3e891891SBaptiste Daroussin 		/* Check boot record magic number */
188*3e891891SBaptiste Daroussin 		if (((mem[0x01]<<8) + mem[0x00]) != 0xaa55) {
189*3e891891SBaptiste Daroussin 			warnx("Invalid bios: no boot record magic number");
190*3e891891SBaptiste Daroussin 			munmap(mem, st.st_size);
191*3e891891SBaptiste Daroussin 			close(fd);
192*3e891891SBaptiste Daroussin 			return (1);
193*3e891891SBaptiste Daroussin 		}
194*3e891891SBaptiste Daroussin 		if ((st.st_size % 512) != 0) {
195*3e891891SBaptiste Daroussin 			warnx("Invalid bios: size not a multiple of 512");
196*3e891891SBaptiste Daroussin 			munmap(mem, st.st_size);
197*3e891891SBaptiste Daroussin 			close(fd);
198*3e891891SBaptiste Daroussin 			return (1);
199*3e891891SBaptiste Daroussin 		}
200*3e891891SBaptiste Daroussin 	} else {
201*3e891891SBaptiste Daroussin 		fwheader = (MPI2_FW_IMAGE_HEADER *)mem;
202*3e891891SBaptiste Daroussin 		if (fwheader->VendorID != MPI2_MFGPAGE_VENDORID_LSI) {
203*3e891891SBaptiste Daroussin 			warnx("Invalid firmware:");
204*3e891891SBaptiste Daroussin 			warnx("  Expected Vendor ID: %04x",
205*3e891891SBaptiste Daroussin 			    MPI2_MFGPAGE_VENDORID_LSI);
206*3e891891SBaptiste Daroussin 			warnx("  Image Vendor ID: %04x", fwheader->VendorID);
207*3e891891SBaptiste Daroussin 			munmap(mem, st.st_size);
208*3e891891SBaptiste Daroussin 			close(fd);
209*3e891891SBaptiste Daroussin 			return (1);
210*3e891891SBaptiste Daroussin 		}
211*3e891891SBaptiste Daroussin 
212*3e891891SBaptiste Daroussin 		if (fwheader->ProductID != facts->ProductID) {
213*3e891891SBaptiste Daroussin 			warnx("Invalid image:");
214*3e891891SBaptiste Daroussin 			warnx("  Expected Product ID: %04x", facts->ProductID);
215*3e891891SBaptiste Daroussin 			warnx("  Image Product ID: %04x", fwheader->ProductID);
216*3e891891SBaptiste Daroussin 			munmap(mem, st.st_size);
217*3e891891SBaptiste Daroussin 			close(fd);
218*3e891891SBaptiste Daroussin 			return (1);
219*3e891891SBaptiste Daroussin 		}
220*3e891891SBaptiste Daroussin 	}
221*3e891891SBaptiste Daroussin 
222*3e891891SBaptiste Daroussin 	printf("Updating %s...\n", argv[1]);
223*3e891891SBaptiste Daroussin 	if (mps_firmware_send(fd, mem, st.st_size, bios) < 0) {
224*3e891891SBaptiste Daroussin 		warnx("Fail to update %s", argv[1]);
225*3e891891SBaptiste Daroussin 		munmap(mem, st.st_size);
226*3e891891SBaptiste Daroussin 		close(fd);
227*3e891891SBaptiste Daroussin 		return (1);
228*3e891891SBaptiste Daroussin 	}
229*3e891891SBaptiste Daroussin 
230*3e891891SBaptiste Daroussin 	munmap(mem, st.st_size);
231*3e891891SBaptiste Daroussin 	close(fd);
232*3e891891SBaptiste Daroussin 	printf("%s successfully updated\n", argv[1]);
233*3e891891SBaptiste Daroussin 	return (0);
234*3e891891SBaptiste Daroussin }
235*3e891891SBaptiste Daroussin 
236*3e891891SBaptiste Daroussin MPS_COMMAND(flash, update, flash_update, "[firmware|bios] file",
237*3e891891SBaptiste Daroussin     "Update firmware/bios");
238