mfi_flash.c revision 225736
150476Speter/*-
247831Sfoxfair * Copyright (c) 2008, 2009 Yahoo!, Inc.
347831Sfoxfair * All rights reserved.
447831Sfoxfair *
547831Sfoxfair * Redistribution and use in source and binary forms, with or without
6174990Sache * modification, are permitted provided that the following conditions
7290150Sdelphij * are met:
8290150Sdelphij * 1. Redistributions of source code must retain the above copyright
9290150Sdelphij *    notice, this list of conditions and the following disclaimer.
10290150Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
11290150Sdelphij *    notice, this list of conditions and the following disclaimer in the
12290150Sdelphij *    documentation and/or other materials provided with the distribution.
13290150Sdelphij * 3. The names of the authors may not be used to endorse or promote
14290150Sdelphij *    products derived from this software without specific prior written
15290150Sdelphij *    permission.
16290150Sdelphij *
17290150Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18290150Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1947831Sfoxfair * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20174990Sache * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2147831Sfoxfair * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2247831Sfoxfair * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2347831Sfoxfair * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2447831Sfoxfair * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2547831Sfoxfair * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2647831Sfoxfair * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2747831Sfoxfair * SUCH DAMAGE.
2847831Sfoxfair *
2947831Sfoxfair * $FreeBSD: stable/9/usr.sbin/mfiutil/mfi_flash.c 222899 2011-06-09 19:52:28Z bz $
3047831Sfoxfair */
3147831Sfoxfair
3247831Sfoxfair#include <sys/param.h>
3347831Sfoxfair#include <sys/errno.h>
3447831Sfoxfair#include <sys/stat.h>
3547831Sfoxfair#include <err.h>
3647831Sfoxfair#include <fcntl.h>
3774606Sache#include <stdio.h>
3874606Sache#include <stdlib.h>
3974606Sache#include <string.h>
4074606Sache#include <unistd.h>
4174606Sache#include "mfiutil.h"
4274606Sache
4374606Sache#define	FLASH_BUF_SIZE	(64 * 1024)
4474606Sache
4547831Sfoxfairint fw_name_width, fw_version_width, fw_date_width, fw_time_width;
4647831Sfoxfair
4747831Sfoxfairstatic void
4847831Sfoxfairscan_firmware(struct mfi_info_component *comp)
4947831Sfoxfair{
5047831Sfoxfair	int len;
5147831Sfoxfair
5247831Sfoxfair	len = strlen(comp->name);
5347831Sfoxfair	if (fw_name_width < len)
5447831Sfoxfair		fw_name_width = len;
5547831Sfoxfair	len = strlen(comp->version);
5647831Sfoxfair	if (fw_version_width < len)
5747831Sfoxfair		fw_version_width = len;
5847831Sfoxfair	len = strlen(comp->build_date);
5947831Sfoxfair	if (fw_date_width < len)
6047831Sfoxfair		fw_date_width = len;
6174570Sache	len = strlen(comp->build_time);
6247831Sfoxfair	if (fw_time_width < len)
6347831Sfoxfair		fw_time_width = len;
6447831Sfoxfair}
6554090Sache
6647831Sfoxfairstatic void
6747831Sfoxfairdisplay_firmware(struct mfi_info_component *comp)
6847831Sfoxfair{
6947831Sfoxfair
7047831Sfoxfair	printf("%-*s  %-*s  %-*s  %-*s\n", fw_name_width, comp->name,
7147831Sfoxfair	    fw_version_width, comp->version, fw_date_width, comp->build_date,
7247831Sfoxfair	    fw_time_width, comp->build_time);
7347831Sfoxfair}
7447831Sfoxfair
7547831Sfoxfairstatic int
7647831Sfoxfairdisplay_pending_firmware(int fd)
77290150Sdelphij{
7853943Sache	struct mfi_ctrl_info info;
79174990Sache	struct mfi_info_component header;
8053943Sache	int error;
8153943Sache	u_int i;
8253943Sache
8353943Sache	if (mfi_ctrl_get_info(fd, &info, NULL) < 0) {
8453943Sache		error = errno;
8553943Sache		warn("Failed to get controller info");
8653943Sache		return (error);
8753943Sache	}
8853943Sache
8953943Sache	printf("mfi%d Pending Firmware Images:\n", mfi_unit);
9053943Sache	strcpy(header.name, "Name");
9153943Sache	strcpy(header.version, "Version");
9253943Sache	strcpy(header.build_date, "Date");
9353943Sache	strcpy(header.build_time, "Time");
9474413Sache	scan_firmware(&header);
9553943Sache	if (info.pending_image_component_count > 8)
9674413Sache		info.pending_image_component_count = 8;
9753961Sache	for (i = 0; i < info.pending_image_component_count; i++)
9874413Sache		scan_firmware(&info.pending_image_component[i]);
9953961Sache	display_firmware(&header);
10074413Sache	for (i = 0; i < info.pending_image_component_count; i++)
10174413Sache		display_firmware(&info.pending_image_component[i]);
102
103	return (0);
104}
105
106static void
107mbox_store_word(uint8_t *mbox, uint32_t val)
108{
109
110	mbox[0] = val & 0xff;
111	mbox[1] = val >> 8 & 0xff;
112	mbox[2] = val >> 16 & 0xff;
113	mbox[3] = val >> 24;
114}
115
116static int
117flash_adapter(int ac, char **av)
118{
119	struct mfi_progress dummy;
120	off_t offset;
121	size_t nread;
122	char *buf;
123	struct stat sb;
124	int error, fd, flash;
125	uint8_t mbox[4], status;
126
127	if (ac != 2) {
128		warnx("flash: Firmware file required");
129		return (EINVAL);
130	}
131
132	flash = open(av[1], O_RDONLY);
133	if (flash < 0) {
134		error = errno;
135		warn("flash: Failed to open %s", av[1]);
136		return (error);
137	}
138
139	buf = NULL;
140	fd = -1;
141
142	if (fstat(flash, &sb) < 0) {
143		error = errno;
144		warn("fstat(%s)", av[1]);
145		goto error;
146	}
147	if (sb.st_size % 1024 != 0 || sb.st_size > 0x7fffffff) {
148		warnx("Invalid flash file size");
149		error = EINVAL;
150		goto error;
151	}
152
153	fd = mfi_open(mfi_unit);
154	if (fd < 0) {
155		error = errno;
156		warn("mfi_open");
157		goto error;
158	}
159
160	/* First, ask the firmware to allocate space for the flash file. */
161	mbox_store_word(mbox, sb.st_size);
162	mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_OPEN, NULL, 0, mbox, 4, &status);
163	if (status != MFI_STAT_OK) {
164		warnx("Failed to alloc flash memory: %s", mfi_status(status));
165		error = EIO;
166		goto error;
167	}
168
169	/* Upload the file 64k at a time. */
170	buf = malloc(FLASH_BUF_SIZE);
171	if (buf == NULL) {
172		warnx("malloc failed");
173		error = ENOMEM;
174		goto error;
175	}
176	offset = 0;
177	while (sb.st_size > 0) {
178		nread = read(flash, buf, FLASH_BUF_SIZE);
179		if (nread <= 0 || nread % 1024 != 0) {
180			warnx("Bad read from flash file");
181			mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_CLOSE, NULL, 0,
182			    NULL, 0, NULL);
183			error = ENXIO;
184			goto error;
185		}
186
187		mbox_store_word(mbox, offset);
188		mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_DOWNLOAD, buf, nread,
189		    mbox, 4, &status);
190		if (status != MFI_STAT_OK) {
191			warnx("Flash download failed: %s", mfi_status(status));
192			mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_CLOSE, NULL, 0,
193			    NULL, 0, NULL);
194			error = ENXIO;
195			goto error;
196		}
197		sb.st_size -= nread;
198		offset += nread;
199	}
200
201	/* Kick off the flash. */
202	printf("WARNING: Firmware flash in progress, do not reboot machine... ");
203	fflush(stdout);
204	mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_FLASH, &dummy, sizeof(dummy),
205	    NULL, 0, &status);
206	if (status != MFI_STAT_OK) {
207		printf("failed:\n\t%s\n", mfi_status(status));
208		error = ENXIO;
209		goto error;
210	}
211	printf("finished\n");
212	error = display_pending_firmware(fd);
213
214error:
215	free(buf);
216	if (fd >= 0)
217		close(fd);
218	close(flash);
219
220	return (error);
221}
222MFI_COMMAND(top, flash, flash_adapter);
223