xref: /freebsd/usr.sbin/mpsutil/mps_flash.c (revision fc9780fd41e7b29db04e9cb843cb5034b88ae662)
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 __RCSID("$FreeBSD$");
283e891891SBaptiste Daroussin 
293e891891SBaptiste Daroussin #include <sys/stat.h>
303e891891SBaptiste Daroussin #include <sys/param.h>
313e891891SBaptiste Daroussin #include <sys/mman.h>
32*fc9780fdSAlfredo Dal'Ava Junior #include <sys/endian.h>
333e891891SBaptiste Daroussin 
343e891891SBaptiste Daroussin #include <errno.h>
353e891891SBaptiste Daroussin #include <err.h>
363e891891SBaptiste Daroussin #include <fcntl.h>
373e891891SBaptiste Daroussin #include <stdbool.h>
383e891891SBaptiste Daroussin #include <stdio.h>
393e891891SBaptiste Daroussin #include <stdlib.h>
403e891891SBaptiste Daroussin #include <string.h>
413e891891SBaptiste Daroussin #include <unistd.h>
423e891891SBaptiste Daroussin 
433e891891SBaptiste Daroussin #include "mpsutil.h"
443e891891SBaptiste Daroussin 
453e891891SBaptiste Daroussin MPS_TABLE(top, flash);
463e891891SBaptiste Daroussin 
473e891891SBaptiste Daroussin static int
483e891891SBaptiste Daroussin flash_save(int argc, char **argv)
493e891891SBaptiste Daroussin {
503e891891SBaptiste Daroussin 	const char *firmware_file;
513e891891SBaptiste Daroussin 	unsigned char *firmware_buffer = NULL;
523e891891SBaptiste Daroussin 	int error, fd, size;
533e891891SBaptiste Daroussin 	bool bios = false;
543e891891SBaptiste Daroussin 	ssize_t written = 0, ret = 0;
553e891891SBaptiste Daroussin 
563e891891SBaptiste Daroussin 	if (argc < 2) {
573e891891SBaptiste Daroussin 		warnx("missing argument: expecting 'firmware' or bios'");
583e891891SBaptiste Daroussin 		return (EINVAL);
593e891891SBaptiste Daroussin 	}
603e891891SBaptiste Daroussin 
613e891891SBaptiste Daroussin 	if (strcmp(argv[1], "bios") == 0) {
623e891891SBaptiste Daroussin 		bios = true;
633e891891SBaptiste Daroussin 	} else if (strcmp(argv[1], "firmware") != 0) {
643e891891SBaptiste Daroussin 		warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
653e891891SBaptiste Daroussin 		    argv[1]);
663e891891SBaptiste Daroussin 	}
673e891891SBaptiste Daroussin 
683e891891SBaptiste Daroussin 	if (argc > 4) {
693e891891SBaptiste Daroussin 		warnx("save %s: extra arguments", argv[1]);
703e891891SBaptiste Daroussin 		return (EINVAL);
713e891891SBaptiste Daroussin 	}
723e891891SBaptiste Daroussin 
733e891891SBaptiste Daroussin 	firmware_file = argv[1];
743e891891SBaptiste Daroussin 	if (argc == 3) {
753e891891SBaptiste Daroussin 		firmware_file = argv[2];
763e891891SBaptiste Daroussin 	}
773e891891SBaptiste Daroussin 
783e891891SBaptiste Daroussin 	fd = mps_open(mps_unit);
793e891891SBaptiste Daroussin 	if (fd < 0) {
803e891891SBaptiste Daroussin 		error = errno;
813e891891SBaptiste Daroussin 		warn("mps_open");
823e891891SBaptiste Daroussin 		return (error);
833e891891SBaptiste Daroussin 	}
843e891891SBaptiste Daroussin 
853e891891SBaptiste Daroussin 	if ((size = mps_firmware_get(fd, &firmware_buffer, bios)) < 0) {
863e891891SBaptiste Daroussin 		warnx("Fail to save %s", argv[1]);
874ecb5141SBaptiste Daroussin 		close(fd);
883e891891SBaptiste Daroussin 		return (1);
893e891891SBaptiste Daroussin 	}
903e891891SBaptiste Daroussin 
913e891891SBaptiste Daroussin 	close(fd);
923e891891SBaptiste Daroussin 	if (size > 0) {
933e891891SBaptiste Daroussin 		fd = open(firmware_file, O_CREAT | O_TRUNC | O_RDWR, 0644);
943e891891SBaptiste Daroussin 		if (fd <0) {
953e891891SBaptiste Daroussin 			error = errno;
963e891891SBaptiste Daroussin 			warn("open");
973e891891SBaptiste Daroussin 			free(firmware_buffer);
983e891891SBaptiste Daroussin 			return (error);
993e891891SBaptiste Daroussin 		}
1003e891891SBaptiste Daroussin 		while (written != size) {
1013e891891SBaptiste Daroussin 			if ((ret = write(fd, firmware_buffer + written, size - written)) <0) {
1023e891891SBaptiste Daroussin 				error = errno;
1033e891891SBaptiste Daroussin 				warn("write");
1043e891891SBaptiste Daroussin 				free(firmware_buffer);
1054ecb5141SBaptiste Daroussin 				close(fd);
1063e891891SBaptiste Daroussin 				return (error);
1073e891891SBaptiste Daroussin 			}
1083e891891SBaptiste Daroussin 			written += ret;
1093e891891SBaptiste Daroussin 		}
1103e891891SBaptiste Daroussin 		close(fd);
1113e891891SBaptiste Daroussin 	}
1123e891891SBaptiste Daroussin 	free(firmware_buffer);
1133e891891SBaptiste Daroussin 	printf("%s successfully saved as %s\n", argv[1], firmware_file);
1143e891891SBaptiste Daroussin 	return (0);
1153e891891SBaptiste Daroussin }
1163e891891SBaptiste Daroussin 
1173e891891SBaptiste Daroussin MPS_COMMAND(flash, save, flash_save, "[firmware|bios] [file]",
1183e891891SBaptiste Daroussin     "Save firmware/bios into a file");
1193e891891SBaptiste Daroussin 
1203e891891SBaptiste Daroussin static int
1213e891891SBaptiste Daroussin flash_update(int argc, char **argv)
1223e891891SBaptiste Daroussin {
1233e891891SBaptiste Daroussin 	int error, fd;
1243e891891SBaptiste Daroussin 	unsigned char *mem = NULL;
1253e891891SBaptiste Daroussin 	struct stat st;
1263e891891SBaptiste Daroussin 	bool bios = false;
1273e891891SBaptiste Daroussin 	MPI2_FW_IMAGE_HEADER *fwheader;
1283e891891SBaptiste Daroussin 	MPI2_IOC_FACTS_REPLY *facts;
1293e891891SBaptiste Daroussin 
1303e891891SBaptiste Daroussin 	if (argc < 2) {
1313e891891SBaptiste Daroussin 		warnx("missing argument: expecting 'firmware' or bios'");
1323e891891SBaptiste Daroussin 		return (EINVAL);
1333e891891SBaptiste Daroussin 	}
1343e891891SBaptiste Daroussin 
1353e891891SBaptiste Daroussin 	if (strcmp(argv[1], "bios") == 0) {
1363e891891SBaptiste Daroussin 		bios = true;
1373e891891SBaptiste Daroussin 	} else if (strcmp(argv[1], "firmware") != 0) {
1383e891891SBaptiste Daroussin 		warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
1393e891891SBaptiste Daroussin 		    argv[1]);
1403e891891SBaptiste Daroussin 	}
1413e891891SBaptiste Daroussin 
1423e891891SBaptiste Daroussin 	if (argc > 4) {
1433e891891SBaptiste Daroussin 		warnx("update firmware: extra arguments");
1443e891891SBaptiste Daroussin 		return (EINVAL);
1453e891891SBaptiste Daroussin 	}
1463e891891SBaptiste Daroussin 
1473e891891SBaptiste Daroussin 	if (argc != 3) {
1483e891891SBaptiste Daroussin 		warnx("no firmware specified");
1493e891891SBaptiste Daroussin 		return (EINVAL);
1503e891891SBaptiste Daroussin 	}
1513e891891SBaptiste Daroussin 
1523e891891SBaptiste Daroussin 	if (stat(argv[2], &st) == -1) {
1533e891891SBaptiste Daroussin 		error = errno;
1543e891891SBaptiste Daroussin 		warn("stat");
1553e891891SBaptiste Daroussin 		return (error);
1563e891891SBaptiste Daroussin 	}
1573e891891SBaptiste Daroussin 
1583e891891SBaptiste Daroussin 	fd = open(argv[2], O_RDONLY);
1593e891891SBaptiste Daroussin 	if (fd < 0) {
1603e891891SBaptiste Daroussin 		error = errno;
1613e891891SBaptiste Daroussin 		warn("open");
1623e891891SBaptiste Daroussin 		return (error);
1633e891891SBaptiste Daroussin 	}
1643e891891SBaptiste Daroussin 
1653e891891SBaptiste Daroussin 	mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1663e891891SBaptiste Daroussin 	if (mem == MAP_FAILED) {
1673e891891SBaptiste Daroussin 		error = errno;
1683e891891SBaptiste Daroussin 		warn("mmap");
1693e891891SBaptiste Daroussin 		close(fd);
1703e891891SBaptiste Daroussin 		return (error);
1713e891891SBaptiste Daroussin 	}
1723e891891SBaptiste Daroussin 	close(fd);
1733e891891SBaptiste Daroussin 
1743e891891SBaptiste Daroussin 	fd = mps_open(mps_unit);
1753e891891SBaptiste Daroussin 	if (fd < 0) {
1763e891891SBaptiste Daroussin 		error = errno;
1773e891891SBaptiste Daroussin 		warn("mps_open");
1783e891891SBaptiste Daroussin 		munmap(mem, st.st_size);
1793e891891SBaptiste Daroussin 		return (error);
1803e891891SBaptiste Daroussin 	}
1813e891891SBaptiste Daroussin 
1823e891891SBaptiste Daroussin 	if ((facts = mps_get_iocfacts(fd)) == NULL) {
1833e891891SBaptiste Daroussin 		warnx("could not get controller IOCFacts\n");
1843e891891SBaptiste Daroussin 		munmap(mem, st.st_size);
1853e891891SBaptiste Daroussin 		close(fd);
1863e891891SBaptiste Daroussin 		return (EINVAL);
1873e891891SBaptiste Daroussin 	}
1883e891891SBaptiste Daroussin 
1893e891891SBaptiste Daroussin 	if (bios) {
1903e891891SBaptiste Daroussin 		/* Check boot record magic number */
1913e891891SBaptiste Daroussin 		if (((mem[0x01]<<8) + mem[0x00]) != 0xaa55) {
1923e891891SBaptiste Daroussin 			warnx("Invalid bios: no boot record magic number");
1933e891891SBaptiste Daroussin 			munmap(mem, st.st_size);
1943e891891SBaptiste Daroussin 			close(fd);
1954ecb5141SBaptiste Daroussin 			free(facts);
1963e891891SBaptiste Daroussin 			return (1);
1973e891891SBaptiste Daroussin 		}
1983e891891SBaptiste Daroussin 		if ((st.st_size % 512) != 0) {
1993e891891SBaptiste Daroussin 			warnx("Invalid bios: size not a multiple of 512");
2003e891891SBaptiste Daroussin 			munmap(mem, st.st_size);
2013e891891SBaptiste Daroussin 			close(fd);
2024ecb5141SBaptiste Daroussin 			free(facts);
2033e891891SBaptiste Daroussin 			return (1);
2043e891891SBaptiste Daroussin 		}
2053e891891SBaptiste Daroussin 	} else {
2063e891891SBaptiste Daroussin 		fwheader = (MPI2_FW_IMAGE_HEADER *)mem;
207*fc9780fdSAlfredo Dal'Ava Junior 		if (le16toh(fwheader->VendorID) != MPI2_MFGPAGE_VENDORID_LSI) {
2083e891891SBaptiste Daroussin 			warnx("Invalid firmware:");
2093e891891SBaptiste Daroussin 			warnx("  Expected Vendor ID: %04x",
2103e891891SBaptiste Daroussin 			    MPI2_MFGPAGE_VENDORID_LSI);
211*fc9780fdSAlfredo Dal'Ava Junior 			warnx("  Image Vendor ID: %04x", le16toh(fwheader->VendorID));
2123e891891SBaptiste Daroussin 			munmap(mem, st.st_size);
2133e891891SBaptiste Daroussin 			close(fd);
2144ecb5141SBaptiste Daroussin 			free(facts);
2153e891891SBaptiste Daroussin 			return (1);
2163e891891SBaptiste Daroussin 		}
2173e891891SBaptiste Daroussin 
218*fc9780fdSAlfredo Dal'Ava Junior 		if (le16toh(fwheader->ProductID) != facts->ProductID) {
2193e891891SBaptiste Daroussin 			warnx("Invalid image:");
2203e891891SBaptiste Daroussin 			warnx("  Expected Product ID: %04x", facts->ProductID);
221*fc9780fdSAlfredo Dal'Ava Junior 			warnx("  Image Product ID: %04x", le16toh(fwheader->ProductID));
2223e891891SBaptiste Daroussin 			munmap(mem, st.st_size);
2233e891891SBaptiste Daroussin 			close(fd);
2244ecb5141SBaptiste Daroussin 			free(facts);
2253e891891SBaptiste Daroussin 			return (1);
2263e891891SBaptiste Daroussin 		}
2273e891891SBaptiste Daroussin 	}
2283e891891SBaptiste Daroussin 
2293e891891SBaptiste Daroussin 	printf("Updating %s...\n", argv[1]);
2303e891891SBaptiste Daroussin 	if (mps_firmware_send(fd, mem, st.st_size, bios) < 0) {
2313e891891SBaptiste Daroussin 		warnx("Fail to update %s", argv[1]);
2323e891891SBaptiste Daroussin 		munmap(mem, st.st_size);
2333e891891SBaptiste Daroussin 		close(fd);
2344ecb5141SBaptiste Daroussin 		free(facts);
2353e891891SBaptiste Daroussin 		return (1);
2363e891891SBaptiste Daroussin 	}
2373e891891SBaptiste Daroussin 
2383e891891SBaptiste Daroussin 	munmap(mem, st.st_size);
2393e891891SBaptiste Daroussin 	close(fd);
2404ecb5141SBaptiste Daroussin 	free(facts);
2413e891891SBaptiste Daroussin 	printf("%s successfully updated\n", argv[1]);
2423e891891SBaptiste Daroussin 	return (0);
2433e891891SBaptiste Daroussin }
2443e891891SBaptiste Daroussin 
2453e891891SBaptiste Daroussin MPS_COMMAND(flash, update, flash_update, "[firmware|bios] file",
2463e891891SBaptiste Daroussin     "Update firmware/bios");
247