mfi_flash.c revision 330449
1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 2008, 2009 Yahoo!, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The names of the authors may not be used to endorse or promote
16 *    products derived from this software without specific prior written
17 *    permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD: stable/11/usr.sbin/mfiutil/mfi_flash.c 330449 2018-03-05 07:26:05Z eadler $
32 */
33
34#include <sys/param.h>
35#include <sys/errno.h>
36#include <sys/stat.h>
37#include <err.h>
38#include <fcntl.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43#include "mfiutil.h"
44
45#define	FLASH_BUF_SIZE	(64 * 1024)
46
47static int
48display_pending_firmware(int fd)
49{
50	struct mfi_ctrl_info info;
51	struct mfi_info_component header;
52	int error;
53	u_int i;
54
55	if (mfi_ctrl_get_info(fd, &info, NULL) < 0) {
56		error = errno;
57		warn("Failed to get controller info");
58		return (error);
59	}
60
61	printf("mfi%d Pending Firmware Images:\n", mfi_unit);
62	strcpy(header.name, "Name");
63	strcpy(header.version, "Version");
64	strcpy(header.build_date, "Date");
65	strcpy(header.build_time, "Time");
66	scan_firmware(&header);
67	if (info.pending_image_component_count > 8)
68		info.pending_image_component_count = 8;
69	for (i = 0; i < info.pending_image_component_count; i++)
70		scan_firmware(&info.pending_image_component[i]);
71	display_firmware(&header, "");
72	for (i = 0; i < info.pending_image_component_count; i++)
73		display_firmware(&info.pending_image_component[i], "");
74
75	return (0);
76}
77
78static void
79mbox_store_word(uint8_t *mbox, uint32_t val)
80{
81
82	mbox[0] = val & 0xff;
83	mbox[1] = val >> 8 & 0xff;
84	mbox[2] = val >> 16 & 0xff;
85	mbox[3] = val >> 24;
86}
87
88static int
89flash_adapter(int ac, char **av)
90{
91	struct mfi_progress dummy;
92	off_t offset;
93	size_t nread;
94	char *buf;
95	struct stat sb;
96	int error, fd, flash;
97	uint8_t mbox[4], status;
98
99	if (ac != 2) {
100		warnx("flash: Firmware file required");
101		return (EINVAL);
102	}
103
104	flash = open(av[1], O_RDONLY);
105	if (flash < 0) {
106		error = errno;
107		warn("flash: Failed to open %s", av[1]);
108		return (error);
109	}
110
111	buf = NULL;
112	fd = -1;
113
114	if (fstat(flash, &sb) < 0) {
115		error = errno;
116		warn("fstat(%s)", av[1]);
117		goto error;
118	}
119	if (sb.st_size % 1024 != 0 || sb.st_size > 0x7fffffff) {
120		warnx("Invalid flash file size");
121		error = EINVAL;
122		goto error;
123	}
124
125	fd = mfi_open(mfi_unit, O_RDWR);
126	if (fd < 0) {
127		error = errno;
128		warn("mfi_open");
129		goto error;
130	}
131
132	/* First, ask the firmware to allocate space for the flash file. */
133	mbox_store_word(mbox, sb.st_size);
134	mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_OPEN, NULL, 0, mbox, 4, &status);
135	if (status != MFI_STAT_OK) {
136		warnx("Failed to alloc flash memory: %s", mfi_status(status));
137		error = EIO;
138		goto error;
139	}
140
141	/* Upload the file 64k at a time. */
142	buf = malloc(FLASH_BUF_SIZE);
143	if (buf == NULL) {
144		warnx("malloc failed");
145		error = ENOMEM;
146		goto error;
147	}
148	offset = 0;
149	while (sb.st_size > 0) {
150		nread = read(flash, buf, FLASH_BUF_SIZE);
151		if (nread <= 0 || nread % 1024 != 0) {
152			warnx("Bad read from flash file");
153			mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_CLOSE, NULL, 0,
154			    NULL, 0, NULL);
155			error = ENXIO;
156			goto error;
157		}
158
159		mbox_store_word(mbox, offset);
160		mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_DOWNLOAD, buf, nread,
161		    mbox, 4, &status);
162		if (status != MFI_STAT_OK) {
163			warnx("Flash download failed: %s", mfi_status(status));
164			mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_CLOSE, NULL, 0,
165			    NULL, 0, NULL);
166			error = ENXIO;
167			goto error;
168		}
169		sb.st_size -= nread;
170		offset += nread;
171	}
172
173	/* Kick off the flash. */
174	printf("WARNING: Firmware flash in progress, do not reboot machine... ");
175	fflush(stdout);
176	mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_FLASH, &dummy, sizeof(dummy),
177	    NULL, 0, &status);
178	if (status != MFI_STAT_OK) {
179		printf("failed:\n\t%s\n", mfi_status(status));
180		error = ENXIO;
181		goto error;
182	}
183	printf("finished\n");
184	error = display_pending_firmware(fd);
185
186error:
187	free(buf);
188	if (fd >= 0)
189		close(fd);
190	close(flash);
191
192	return (error);
193}
194MFI_COMMAND(top, flash, flash_adapter);
195