svn commit: r291002 - head/usr.sbin/mpsutil
Baptiste Daroussin
bapt at FreeBSD.org
Tue Nov 17 20:43:01 UTC 2015
Author: bapt
Date: Tue Nov 17 20:42:59 2015
New Revision: 291002
URL: https://svnweb.freebsd.org/changeset/base/291002
Log:
mpsutil/mprutil: add flash subcommand
the flash subcommand allows to save/update firmware and bios for LSI Fusion-MPT
2/3 controllers (mps(4) and mpr(4))
Tested by: allanjude
Reviewed by: wblock (manpage)
Relnotes: yes
Sponsored by: Gandi.net
Differential Revision: https://reviews.freebsd.org/D4026
Added:
head/usr.sbin/mpsutil/mps_flash.c (contents, props changed)
Modified:
head/usr.sbin/mpsutil/Makefile
head/usr.sbin/mpsutil/mps_cmd.c
head/usr.sbin/mpsutil/mpsutil.8
head/usr.sbin/mpsutil/mpsutil.h
Modified: head/usr.sbin/mpsutil/Makefile
==============================================================================
--- head/usr.sbin/mpsutil/Makefile Tue Nov 17 20:42:08 2015 (r291001)
+++ head/usr.sbin/mpsutil/Makefile Tue Nov 17 20:42:59 2015 (r291002)
@@ -1,7 +1,7 @@
# $FreeBSD$
PROG= mpsutil
-SRCS= mpsutil.c mps_cmd.c mps_show.c
+SRCS= mps_cmd.c mps_flash.c mps_show.c mpsutil.c
MAN= mpsutil.8
WARNS?= 3
Modified: head/usr.sbin/mpsutil/mps_cmd.c
==============================================================================
--- head/usr.sbin/mpsutil/mps_cmd.c Tue Nov 17 20:42:08 2015 (r291001)
+++ head/usr.sbin/mpsutil/mps_cmd.c Tue Nov 17 20:42:59 2015 (r291002)
@@ -1,4 +1,6 @@
/*-
+ * Copyright (c) 2015 Baptiste Daroussin <bapt at FreeBSD.org>
+ *
* Copyright (c) 2015 Netflix, Inc.
* All rights reserved.
* Written by: Scott Long <scottl at freebsd.org>
@@ -442,6 +444,62 @@ mps_read_extended_config_page(int fd, U8
return (buf);
}
+int
+mps_firmware_send(int fd, unsigned char *fw, uint32_t len, bool bios)
+{
+ MPI2_FW_DOWNLOAD_REQUEST req;
+ MPI2_FW_DOWNLOAD_REPLY reply;
+
+ bzero(&req, sizeof(req));
+ bzero(&reply, sizeof(reply));
+ req.Function = MPI2_FUNCTION_FW_DOWNLOAD;
+ req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
+ req.TotalImageSize = len;
+ req.MsgFlags = MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
+
+ if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ fw, len, 0)) {
+ return (-1);
+ }
+ return (0);
+}
+
+int
+mps_firmware_get(int fd, unsigned char **firmware, bool bios)
+{
+ MPI2_FW_UPLOAD_REQUEST req;
+ MPI2_FW_UPLOAD_REPLY reply;
+ int size;
+
+ *firmware = NULL;
+ bzero(&req, sizeof(req));
+ bzero(&reply, sizeof(reply));
+ req.Function = MPI2_FUNCTION_FW_UPLOAD;
+ req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
+
+ if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ NULL, 0, 0)) {
+ return (-1);
+ }
+ if (reply.ActualImageSize == 0) {
+ return (-1);
+ }
+
+ size = reply.ActualImageSize;
+ *firmware = calloc(1, sizeof(char) * size);
+ if (*firmware == NULL) {
+ warn("calloc");
+ return (-1);
+ }
+ if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ *firmware, size, 0)) {
+ free(*firmware);
+ return (-1);
+ }
+
+ return (size);
+}
+
#else
int
Added: head/usr.sbin/mpsutil/mps_flash.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/usr.sbin/mpsutil/mps_flash.c Tue Nov 17 20:42:59 2015 (r291002)
@@ -0,0 +1,237 @@
+/*-
+ * Copyright (c) 2015 Baptiste Daroussin <bapt at FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+
+#include <errno.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mpsutil.h"
+
+MPS_TABLE(top, flash);
+
+static int
+flash_save(int argc, char **argv)
+{
+ const char *firmware_file;
+ unsigned char *firmware_buffer = NULL;
+ int error, fd, size;
+ bool bios = false;
+ ssize_t written = 0, ret = 0;
+
+ if (argc < 2) {
+ warnx("missing argument: expecting 'firmware' or bios'");
+ return (EINVAL);
+ }
+
+ if (strcmp(argv[1], "bios") == 0) {
+ bios = true;
+ } else if (strcmp(argv[1], "firmware") != 0) {
+ warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
+ argv[1]);
+ }
+
+ if (argc > 4) {
+ warnx("save %s: extra arguments", argv[1]);
+ return (EINVAL);
+ }
+
+ firmware_file = argv[1];
+ if (argc == 3) {
+ firmware_file = argv[2];
+ }
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ if ((size = mps_firmware_get(fd, &firmware_buffer, bios)) < 0) {
+ warnx("Fail to save %s", argv[1]);
+ return (1);
+ }
+
+ close(fd);
+ if (size > 0) {
+ fd = open(firmware_file, O_CREAT | O_TRUNC | O_RDWR, 0644);
+ if (fd <0) {
+ error = errno;
+ warn("open");
+ free(firmware_buffer);
+ return (error);
+ }
+ while (written != size) {
+ if ((ret = write(fd, firmware_buffer + written, size - written)) <0) {
+ error = errno;
+ warn("write");
+ free(firmware_buffer);
+ return (error);
+ }
+ written += ret;
+ }
+ close(fd);
+ }
+ free(firmware_buffer);
+ printf("%s successfully saved as %s\n", argv[1], firmware_file);
+ return (0);
+}
+
+MPS_COMMAND(flash, save, flash_save, "[firmware|bios] [file]",
+ "Save firmware/bios into a file");
+
+static int
+flash_update(int argc, char **argv)
+{
+ int error, fd;
+ unsigned char *mem = NULL;
+ struct stat st;
+ bool bios = false;
+ MPI2_FW_IMAGE_HEADER *fwheader;
+ MPI2_IOC_FACTS_REPLY *facts;
+
+ if (argc < 2) {
+ warnx("missing argument: expecting 'firmware' or bios'");
+ return (EINVAL);
+ }
+
+ if (strcmp(argv[1], "bios") == 0) {
+ bios = true;
+ } else if (strcmp(argv[1], "firmware") != 0) {
+ warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
+ argv[1]);
+ }
+
+ if (argc > 4) {
+ warnx("update firmware: extra arguments");
+ return (EINVAL);
+ }
+
+ if (argc != 3) {
+ warnx("no firmware specified");
+ return (EINVAL);
+ }
+
+ if (stat(argv[2], &st) == -1) {
+ error = errno;
+ warn("stat");
+ return (error);
+ }
+
+ fd = open(argv[2], O_RDONLY);
+ if (fd < 0) {
+ error = errno;
+ warn("open");
+ return (error);
+ }
+
+ mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (mem == MAP_FAILED) {
+ error = errno;
+ warn("mmap");
+ close(fd);
+ return (error);
+ }
+ close(fd);
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ munmap(mem, st.st_size);
+ return (error);
+ }
+
+ if ((facts = mps_get_iocfacts(fd)) == NULL) {
+ warnx("could not get controller IOCFacts\n");
+ munmap(mem, st.st_size);
+ close(fd);
+ return (EINVAL);
+ }
+
+ if (bios) {
+ /* Check boot record magic number */
+ if (((mem[0x01]<<8) + mem[0x00]) != 0xaa55) {
+ warnx("Invalid bios: no boot record magic number");
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+ if ((st.st_size % 512) != 0) {
+ warnx("Invalid bios: size not a multiple of 512");
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+ } else {
+ fwheader = (MPI2_FW_IMAGE_HEADER *)mem;
+ if (fwheader->VendorID != MPI2_MFGPAGE_VENDORID_LSI) {
+ warnx("Invalid firmware:");
+ warnx(" Expected Vendor ID: %04x",
+ MPI2_MFGPAGE_VENDORID_LSI);
+ warnx(" Image Vendor ID: %04x", fwheader->VendorID);
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+
+ if (fwheader->ProductID != facts->ProductID) {
+ warnx("Invalid image:");
+ warnx(" Expected Product ID: %04x", facts->ProductID);
+ warnx(" Image Product ID: %04x", fwheader->ProductID);
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+ }
+
+ printf("Updating %s...\n", argv[1]);
+ if (mps_firmware_send(fd, mem, st.st_size, bios) < 0) {
+ warnx("Fail to update %s", argv[1]);
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+
+ munmap(mem, st.st_size);
+ close(fd);
+ printf("%s successfully updated\n", argv[1]);
+ return (0);
+}
+
+MPS_COMMAND(flash, update, flash_update, "[firmware|bios] file",
+ "Update firmware/bios");
Modified: head/usr.sbin/mpsutil/mpsutil.8
==============================================================================
--- head/usr.sbin/mpsutil/mpsutil.8 Tue Nov 17 20:42:08 2015 (r291001)
+++ head/usr.sbin/mpsutil/mpsutil.8 Tue Nov 17 20:42:59 2015 (r291002)
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 28, 2015
+.Dd November 17, 2015
.Dt MPSUTIL 8
.Os
.Sh NAME
@@ -60,6 +60,16 @@
.Nm
.Op Fl u Ar unit
.Cm show iocfacts
+.Nm
+.Op Fl u Ar unit
+.Cm flash save
+.Op Ar firmware Ns | Ns Ar bios
+.Op Ar file
+.Nm
+.Op Fl u Ar unit
+.Cm flash update
+.Op Ar firmware Ns | Ns Ar bios
+.Ar file
.Sh DESCRIPTION
The
.Nm
@@ -94,7 +104,9 @@ then unit 0 is used.
.Pp
The
.Nm
-utility currently only supports informational commands.
+utility supports several different groups of commands.
+The first group of commands provide information about the controller.
+The second group of commands are used to manager controller-wide operations.
.Pp
The informational commands include:
.Bl -tag -width indent
@@ -119,8 +131,32 @@ Displays IOC Facts messages.
.It Cm show cfgpage page Oo Ar num Oc Op Ar addr
Show IOC Facts Message
.El
+.Pp
+Controller management commands include:
+.Bl -tag -width indent
+.It Cm flash save Oo Ar firmware Ns | Ns Ar bios Oc Op Ar file
+Save the
+.Ar firmware
+or
+.Ar bios
+from the controller into a local
+.Ar file .
+If no
+.Ar file
+is specified then the file will be named
+.Pa firmware
+or
+.Pa bios .
+.It Cm flash update Oo Ar firmware Ns | Ns Ar bios Oc Ar file
+Replace the
+.Ar firmware
+or
+.Ar bios
+from the controller with the one specified via
+.Ar file .
+.El
.Sh SEE ALSO
-.Xr mpr 4
+.Xr mpr 4 ,
.Xr mps 4
.Sh HISTORY
The
Modified: head/usr.sbin/mpsutil/mpsutil.h
==============================================================================
--- head/usr.sbin/mpsutil/mpsutil.h Tue Nov 17 20:42:08 2015 (r291001)
+++ head/usr.sbin/mpsutil/mpsutil.h Tue Nov 17 20:42:59 2015 (r291002)
@@ -35,6 +35,7 @@
#include <sys/cdefs.h>
#include <sys/linker_set.h>
+#include <stdbool.h>
#include <dev/mps/mpi/mpi2_type.h>
#include <dev/mps/mpi/mpi2.h>
@@ -122,6 +123,8 @@ void *mps_read_extended_config_page(int
int mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus,
uint16_t *target);
const char *mps_ioc_status(U16 IOCStatus);
+int mps_firmware_send(int fd, unsigned char *buf, uint32_t len, bool bios);
+int mps_firmware_get(int fd, unsigned char **buf, bool bios);
static __inline void *
mps_read_man_page(int fd, U8 PageNumber, U16 *IOCStatus)
More information about the svn-src-head
mailing list