From owner-svn-src-head@freebsd.org Tue Nov 17 20:43:01 2015 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 79542A31339; Tue, 17 Nov 2015 20:43:01 +0000 (UTC) (envelope-from bapt@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 534251015; Tue, 17 Nov 2015 20:43:01 +0000 (UTC) (envelope-from bapt@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id tAHKh0Ra072222; Tue, 17 Nov 2015 20:43:00 GMT (envelope-from bapt@FreeBSD.org) Received: (from bapt@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id tAHKgxrh072208; Tue, 17 Nov 2015 20:42:59 GMT (envelope-from bapt@FreeBSD.org) Message-Id: <201511172042.tAHKgxrh072208@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: bapt set sender to bapt@FreeBSD.org using -f From: Baptiste Daroussin Date: Tue, 17 Nov 2015 20:42:59 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r291002 - head/usr.sbin/mpsutil X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 17 Nov 2015 20:43:01 -0000 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 + * * Copyright (c) 2015 Netflix, Inc. * All rights reserved. * Written by: Scott Long @@ -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 + * + * 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 +__RCSID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 #include +#include #include #include @@ -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)