xref: /freebsd/usr.sbin/mpsutil/mps_flash.c (revision da5432ed)
13e891891SBaptiste Daroussin /*-
23e891891SBaptiste Daroussin  * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
33e891891SBaptiste Daroussin  *
43e891891SBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
53e891891SBaptiste Daroussin  * modification, are permitted provided that the following conditions
63e891891SBaptiste Daroussin  * are met:
73e891891SBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
83e891891SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer.
93e891891SBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
103e891891SBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
113e891891SBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
123e891891SBaptiste Daroussin  *
133e891891SBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
143e891891SBaptiste Daroussin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
153e891891SBaptiste Daroussin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
163e891891SBaptiste Daroussin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
173e891891SBaptiste Daroussin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
183e891891SBaptiste Daroussin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
193e891891SBaptiste Daroussin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
203e891891SBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
213e891891SBaptiste Daroussin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
223e891891SBaptiste Daroussin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
233e891891SBaptiste Daroussin  * SUCH DAMAGE.
243e891891SBaptiste Daroussin  */
253e891891SBaptiste Daroussin 
263e891891SBaptiste Daroussin #include <sys/cdefs.h>
273e891891SBaptiste Daroussin #include <sys/stat.h>
283e891891SBaptiste Daroussin #include <sys/param.h>
293e891891SBaptiste Daroussin #include <sys/mman.h>
30fc9780fdSAlfredo Dal'Ava Junior #include <sys/endian.h>
313e891891SBaptiste Daroussin 
323e891891SBaptiste Daroussin #include <errno.h>
333e891891SBaptiste Daroussin #include <err.h>
343e891891SBaptiste Daroussin #include <fcntl.h>
353e891891SBaptiste Daroussin #include <stdbool.h>
363e891891SBaptiste Daroussin #include <stdio.h>
373e891891SBaptiste Daroussin #include <stdlib.h>
383e891891SBaptiste Daroussin #include <string.h>
393e891891SBaptiste Daroussin #include <unistd.h>
403e891891SBaptiste Daroussin 
413e891891SBaptiste Daroussin #include "mpsutil.h"
423e891891SBaptiste Daroussin 
433e891891SBaptiste Daroussin MPS_TABLE(top, flash);
443e891891SBaptiste Daroussin 
453e891891SBaptiste Daroussin static int
flash_save(int argc,char ** argv)463e891891SBaptiste Daroussin flash_save(int argc, char **argv)
473e891891SBaptiste Daroussin {
483e891891SBaptiste Daroussin 	const char *firmware_file;
493e891891SBaptiste Daroussin 	unsigned char *firmware_buffer = NULL;
503e891891SBaptiste Daroussin 	int error, fd, size;
513e891891SBaptiste Daroussin 	bool bios = false;
523e891891SBaptiste Daroussin 	ssize_t written = 0, ret = 0;
533e891891SBaptiste Daroussin 
543e891891SBaptiste Daroussin 	if (argc < 2) {
553e891891SBaptiste Daroussin 		warnx("missing argument: expecting 'firmware' or bios'");
563e891891SBaptiste Daroussin 		return (EINVAL);
573e891891SBaptiste Daroussin 	}
583e891891SBaptiste Daroussin 
593e891891SBaptiste Daroussin 	if (strcmp(argv[1], "bios") == 0) {
603e891891SBaptiste Daroussin 		bios = true;
613e891891SBaptiste Daroussin 	} else if (strcmp(argv[1], "firmware") != 0) {
623e891891SBaptiste Daroussin 		warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
633e891891SBaptiste Daroussin 		    argv[1]);
643e891891SBaptiste Daroussin 	}
653e891891SBaptiste Daroussin 
663e891891SBaptiste Daroussin 	if (argc > 4) {
673e891891SBaptiste Daroussin 		warnx("save %s: extra arguments", argv[1]);
683e891891SBaptiste Daroussin 		return (EINVAL);
693e891891SBaptiste Daroussin 	}
703e891891SBaptiste Daroussin 
713e891891SBaptiste Daroussin 	firmware_file = argv[1];
723e891891SBaptiste Daroussin 	if (argc == 3) {
733e891891SBaptiste Daroussin 		firmware_file = argv[2];
743e891891SBaptiste Daroussin 	}
753e891891SBaptiste Daroussin 
763e891891SBaptiste Daroussin 	fd = mps_open(mps_unit);
773e891891SBaptiste Daroussin 	if (fd < 0) {
783e891891SBaptiste Daroussin 		error = errno;
793e891891SBaptiste Daroussin 		warn("mps_open");
803e891891SBaptiste Daroussin 		return (error);
813e891891SBaptiste Daroussin 	}
823e891891SBaptiste Daroussin 
833e891891SBaptiste Daroussin 	if ((size = mps_firmware_get(fd, &firmware_buffer, bios)) < 0) {
843e891891SBaptiste Daroussin 		warnx("Fail to save %s", argv[1]);
854ecb5141SBaptiste Daroussin 		close(fd);
863e891891SBaptiste Daroussin 		return (1);
873e891891SBaptiste Daroussin 	}
883e891891SBaptiste Daroussin 
893e891891SBaptiste Daroussin 	close(fd);
903e891891SBaptiste Daroussin 	if (size > 0) {
913e891891SBaptiste Daroussin 		fd = open(firmware_file, O_CREAT | O_TRUNC | O_RDWR, 0644);
923e891891SBaptiste Daroussin 		if (fd <0) {
933e891891SBaptiste Daroussin 			error = errno;
943e891891SBaptiste Daroussin 			warn("open");
953e891891SBaptiste Daroussin 			free(firmware_buffer);
963e891891SBaptiste Daroussin 			return (error);
973e891891SBaptiste Daroussin 		}
983e891891SBaptiste Daroussin 		while (written != size) {
993e891891SBaptiste Daroussin 			if ((ret = write(fd, firmware_buffer + written, size - written)) <0) {
1003e891891SBaptiste Daroussin 				error = errno;
1013e891891SBaptiste Daroussin 				warn("write");
1023e891891SBaptiste Daroussin 				free(firmware_buffer);
1034ecb5141SBaptiste Daroussin 				close(fd);
1043e891891SBaptiste Daroussin 				return (error);
1053e891891SBaptiste Daroussin 			}
1063e891891SBaptiste Daroussin 			written += ret;
1073e891891SBaptiste Daroussin 		}
1083e891891SBaptiste Daroussin 		close(fd);
1093e891891SBaptiste Daroussin 	}
1103e891891SBaptiste Daroussin 	free(firmware_buffer);
1113e891891SBaptiste Daroussin 	printf("%s successfully saved as %s\n", argv[1], firmware_file);
1123e891891SBaptiste Daroussin 	return (0);
1133e891891SBaptiste Daroussin }
1143e891891SBaptiste Daroussin 
1153e891891SBaptiste Daroussin MPS_COMMAND(flash, save, flash_save, "[firmware|bios] [file]",
1163e891891SBaptiste Daroussin     "Save firmware/bios into a file");
1173e891891SBaptiste Daroussin 
1183e891891SBaptiste Daroussin static int
flash_update(int argc,char ** argv)1193e891891SBaptiste Daroussin flash_update(int argc, char **argv)
1203e891891SBaptiste Daroussin {
1213e891891SBaptiste Daroussin 	int error, fd;
1223e891891SBaptiste Daroussin 	unsigned char *mem = NULL;
1233e891891SBaptiste Daroussin 	struct stat st;
1243e891891SBaptiste Daroussin 	bool bios = false;
1253e891891SBaptiste Daroussin 	MPI2_FW_IMAGE_HEADER *fwheader;
1263e891891SBaptiste Daroussin 	MPI2_IOC_FACTS_REPLY *facts;
1273e891891SBaptiste Daroussin 
1283e891891SBaptiste Daroussin 	if (argc < 2) {
1293e891891SBaptiste Daroussin 		warnx("missing argument: expecting 'firmware' or bios'");
1303e891891SBaptiste Daroussin 		return (EINVAL);
1313e891891SBaptiste Daroussin 	}
1323e891891SBaptiste Daroussin 
1333e891891SBaptiste Daroussin 	if (strcmp(argv[1], "bios") == 0) {
1343e891891SBaptiste Daroussin 		bios = true;
1353e891891SBaptiste Daroussin 	} else if (strcmp(argv[1], "firmware") != 0) {
1363e891891SBaptiste Daroussin 		warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
1373e891891SBaptiste Daroussin 		    argv[1]);
1383e891891SBaptiste Daroussin 	}
1393e891891SBaptiste Daroussin 
1403e891891SBaptiste Daroussin 	if (argc > 4) {
1413e891891SBaptiste Daroussin 		warnx("update firmware: extra arguments");
1423e891891SBaptiste Daroussin 		return (EINVAL);
1433e891891SBaptiste Daroussin 	}
1443e891891SBaptiste Daroussin 
1453e891891SBaptiste Daroussin 	if (argc != 3) {
1463e891891SBaptiste Daroussin 		warnx("no firmware specified");
1473e891891SBaptiste Daroussin 		return (EINVAL);
1483e891891SBaptiste Daroussin 	}
1493e891891SBaptiste Daroussin 
1503e891891SBaptiste Daroussin 	if (stat(argv[2], &st) == -1) {
1513e891891SBaptiste Daroussin 		error = errno;
1523e891891SBaptiste Daroussin 		warn("stat");
1533e891891SBaptiste Daroussin 		return (error);
1543e891891SBaptiste Daroussin 	}
1553e891891SBaptiste Daroussin 
1563e891891SBaptiste Daroussin 	fd = open(argv[2], O_RDONLY);
1573e891891SBaptiste Daroussin 	if (fd < 0) {
1583e891891SBaptiste Daroussin 		error = errno;
1593e891891SBaptiste Daroussin 		warn("open");
1603e891891SBaptiste Daroussin 		return (error);
1613e891891SBaptiste Daroussin 	}
1623e891891SBaptiste Daroussin 
1633e891891SBaptiste Daroussin 	mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1643e891891SBaptiste Daroussin 	if (mem == MAP_FAILED) {
1653e891891SBaptiste Daroussin 		error = errno;
1663e891891SBaptiste Daroussin 		warn("mmap");
1673e891891SBaptiste Daroussin 		close(fd);
1683e891891SBaptiste Daroussin 		return (error);
1693e891891SBaptiste Daroussin 	}
1703e891891SBaptiste Daroussin 	close(fd);
1713e891891SBaptiste Daroussin 
1723e891891SBaptiste Daroussin 	fd = mps_open(mps_unit);
1733e891891SBaptiste Daroussin 	if (fd < 0) {
1743e891891SBaptiste Daroussin 		error = errno;
1753e891891SBaptiste Daroussin 		warn("mps_open");
1763e891891SBaptiste Daroussin 		munmap(mem, st.st_size);
1773e891891SBaptiste Daroussin 		return (error);
1783e891891SBaptiste Daroussin 	}
1793e891891SBaptiste Daroussin 
1803e891891SBaptiste Daroussin 	if ((facts = mps_get_iocfacts(fd)) == NULL) {
1813e891891SBaptiste Daroussin 		warnx("could not get controller IOCFacts\n");
1823e891891SBaptiste Daroussin 		munmap(mem, st.st_size);
1833e891891SBaptiste Daroussin 		close(fd);
1843e891891SBaptiste Daroussin 		return (EINVAL);
1853e891891SBaptiste Daroussin 	}
1863e891891SBaptiste Daroussin 
1873e891891SBaptiste Daroussin 	if (bios) {
1883e891891SBaptiste Daroussin 		/* Check boot record magic number */
1893e891891SBaptiste Daroussin 		if (((mem[0x01]<<8) + mem[0x00]) != 0xaa55) {
1903e891891SBaptiste Daroussin 			warnx("Invalid bios: no boot record magic number");
1913e891891SBaptiste Daroussin 			munmap(mem, st.st_size);
1923e891891SBaptiste Daroussin 			close(fd);
1934ecb5141SBaptiste Daroussin 			free(facts);
1943e891891SBaptiste Daroussin 			return (1);
1953e891891SBaptiste Daroussin 		}
1963e891891SBaptiste Daroussin 		if ((st.st_size % 512) != 0) {
1973e891891SBaptiste Daroussin 			warnx("Invalid bios: size not a multiple of 512");
1983e891891SBaptiste Daroussin 			munmap(mem, st.st_size);
1993e891891SBaptiste Daroussin 			close(fd);
2004ecb5141SBaptiste Daroussin 			free(facts);
2013e891891SBaptiste Daroussin 			return (1);
2023e891891SBaptiste Daroussin 		}
2033e891891SBaptiste Daroussin 	} else {
2043e891891SBaptiste Daroussin 		fwheader = (MPI2_FW_IMAGE_HEADER *)mem;
205fc9780fdSAlfredo Dal'Ava Junior 		if (le16toh(fwheader->VendorID) != MPI2_MFGPAGE_VENDORID_LSI) {
2063e891891SBaptiste Daroussin 			warnx("Invalid firmware:");
2073e891891SBaptiste Daroussin 			warnx("  Expected Vendor ID: %04x",
2083e891891SBaptiste Daroussin 			    MPI2_MFGPAGE_VENDORID_LSI);
209fc9780fdSAlfredo Dal'Ava Junior 			warnx("  Image Vendor ID: %04x", le16toh(fwheader->VendorID));
2103e891891SBaptiste Daroussin 			munmap(mem, st.st_size);
2113e891891SBaptiste Daroussin 			close(fd);
2124ecb5141SBaptiste Daroussin 			free(facts);
2133e891891SBaptiste Daroussin 			return (1);
2143e891891SBaptiste Daroussin 		}
2153e891891SBaptiste Daroussin 
216fc9780fdSAlfredo Dal'Ava Junior 		if (le16toh(fwheader->ProductID) != facts->ProductID) {
2173e891891SBaptiste Daroussin 			warnx("Invalid image:");
2183e891891SBaptiste Daroussin 			warnx("  Expected Product ID: %04x", facts->ProductID);
219fc9780fdSAlfredo Dal'Ava Junior 			warnx("  Image Product ID: %04x", le16toh(fwheader->ProductID));
2203e891891SBaptiste Daroussin 			munmap(mem, st.st_size);
2213e891891SBaptiste Daroussin 			close(fd);
2224ecb5141SBaptiste Daroussin 			free(facts);
2233e891891SBaptiste Daroussin 			return (1);
2243e891891SBaptiste Daroussin 		}
2253e891891SBaptiste Daroussin 	}
2263e891891SBaptiste Daroussin 
2273e891891SBaptiste Daroussin 	printf("Updating %s...\n", argv[1]);
2283e891891SBaptiste Daroussin 	if (mps_firmware_send(fd, mem, st.st_size, bios) < 0) {
2293e891891SBaptiste Daroussin 		warnx("Fail to update %s", argv[1]);
2303e891891SBaptiste Daroussin 		munmap(mem, st.st_size);
2313e891891SBaptiste Daroussin 		close(fd);
2324ecb5141SBaptiste Daroussin 		free(facts);
2333e891891SBaptiste Daroussin 		return (1);
2343e891891SBaptiste Daroussin 	}
2353e891891SBaptiste Daroussin 
2363e891891SBaptiste Daroussin 	munmap(mem, st.st_size);
2373e891891SBaptiste Daroussin 	close(fd);
2384ecb5141SBaptiste Daroussin 	free(facts);
2393e891891SBaptiste Daroussin 	printf("%s successfully updated\n", argv[1]);
2403e891891SBaptiste Daroussin 	return (0);
2413e891891SBaptiste Daroussin }
2423e891891SBaptiste Daroussin 
2433e891891SBaptiste Daroussin MPS_COMMAND(flash, update, flash_update, "[firmware|bios] file",
2443e891891SBaptiste Daroussin     "Update firmware/bios");
245