mfi_flash.c revision 215526
1139804Simp/*-
21541Srgrimes * Copyright (c) 2008, 2009 Yahoo!, Inc.
31541Srgrimes * All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 3. The names of the authors may not be used to endorse or promote
141541Srgrimes *    products derived from this software without specific prior written
151541Srgrimes *    permission.
161541Srgrimes *
171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271541Srgrimes * SUCH DAMAGE.
281541Srgrimes *
291541Srgrimes * $FreeBSD: head/usr.sbin/mfiutil/mfi_flash.c 215526 2010-11-19 15:39:59Z jhb $
301541Srgrimes */
311541Srgrimes
321541Srgrimes#include <sys/param.h>
331541Srgrimes#include <sys/errno.h>
341541Srgrimes#include <sys/stat.h>
351541Srgrimes#include <err.h>
361541Srgrimes#include <fcntl.h>
37116182Sobrien#include <stdio.h>
38116182Sobrien#include <stdlib.h>
39116182Sobrien#include <string.h>
40180610Srwatson#include <unistd.h>
41180610Srwatson#include "mfiutil.h"
421541Srgrimes
4329680Sgibbs#define	FLASH_BUF_SIZE	(64 * 1024)
44180616Srwatson
45160509Sjhbint fw_name_width, fw_version_width, fw_date_width, fw_time_width;
46160509Sjhb
4729680Sgibbsstatic void
481541Srgrimesscan_firmware(struct mfi_info_component *comp)
491541Srgrimes{
501541Srgrimes	int len;
511541Srgrimes
521541Srgrimes	len = strlen(comp->name);
531541Srgrimes	if (fw_name_width < len)
5429680Sgibbs		fw_name_width = len;
5529680Sgibbs	len = strlen(comp->version);
5660938Sjake	if (fw_version_width < len)
5729680Sgibbs		fw_version_width = len;
58160509Sjhb	len = strlen(comp->build_date);
59160509Sjhb	if (fw_date_width < len)
6029680Sgibbs		fw_date_width = len;
6129680Sgibbs	len = strlen(comp->build_time);
6292723Salfred	if (fw_time_width < len)
63160509Sjhb		fw_time_width = len;
64180616Srwatson}
65180616Srwatson
66180616Srwatsonstatic void
67180616Srwatsondisplay_firmware(struct mfi_info_component *comp)
68180616Srwatson{
6929680Sgibbs
70180616Srwatson	printf("%-*s  %-*s  %-*s  %-*s\n", fw_name_width, comp->name,
71180616Srwatson	    fw_version_width, comp->version, fw_date_width, comp->build_date,
72180616Srwatson	    fw_time_width, comp->build_time);
73180616Srwatson}
74180616Srwatson
75180616Srwatsonstatic int
76180673Srwatsondisplay_pending_firmware(int fd)
77180673Srwatson{
78180673Srwatson	struct mfi_ctrl_info info;
79180673Srwatson	struct mfi_info_component header;
80180673Srwatson	int error;
81180673Srwatson	u_int i;
82180673Srwatson
83180673Srwatson	if (mfi_ctrl_get_info(fd, &info, NULL) < 0) {
84180673Srwatson		error = errno;
85180673Srwatson		warn("Failed to get controller info");
86180673Srwatson		return (error);
87180673Srwatson	}
88180616Srwatson
89180673Srwatson	printf("mfi%d Pending Firmware Images:\n", mfi_unit);
90180673Srwatson	strcpy(header.name, "Name");
91180616Srwatson	strcpy(header.version, "Version");
92180616Srwatson	strcpy(header.build_date, "Date");
93180616Srwatson	strcpy(header.build_time, "Time");
9429680Sgibbs	scan_firmware(&header);
9529680Sgibbs	if (info.pending_image_component_count > 8)
9629680Sgibbs		info.pending_image_component_count = 8;
9751684Sn_hibma	for (i = 0; i < info.pending_image_component_count; i++)
98180616Srwatson		scan_firmware(&info.pending_image_component[i]);
9929680Sgibbs	display_firmware(&header);
100160509Sjhb	for (i = 0; i < info.pending_image_component_count; i++)
101160509Sjhb		display_firmware(&info.pending_image_component[i]);
102160509Sjhb
103160509Sjhb	return (0);
10451684Sn_hibma}
105160509Sjhb
10629680Sgibbsstatic void
10729680Sgibbsmbox_store_word(uint8_t *mbox, uint32_t val)
108180616Srwatson{
10951684Sn_hibma
110180616Srwatson	mbox[0] = val & 0xff;
111180616Srwatson	mbox[1] = val >> 8 & 0xff;
112180673Srwatson	mbox[2] = val >> 16 & 0xff;
113180616Srwatson	mbox[3] = val >> 24;
114180616Srwatson}
115180616Srwatson
116180616Srwatsonstatic int
117180616Srwatsonflash_adapter(int ac, char **av)
11829680Sgibbs{
119160509Sjhb	struct mfi_progress dummy;
12029680Sgibbs	off_t offset;
12129680Sgibbs	size_t nread;
122177253Srwatson	char *buf;
12329680Sgibbs	struct stat sb;
12429680Sgibbs	int error, fd, flash;
12529680Sgibbs	uint8_t mbox[4], status;
12629680Sgibbs
12729680Sgibbs	if (ac != 2) {
12829680Sgibbs		warnx("flash: Firmware file required");
12929680Sgibbs		return (EINVAL);
13029680Sgibbs	}
13129680Sgibbs
13229680Sgibbs	flash = open(av[1], O_RDONLY);
13329680Sgibbs	if (flash < 0) {
13429680Sgibbs		error = errno;
135160509Sjhb		warn("flash: Failed to open %s", av[1]);
136160509Sjhb		return (error);
13729680Sgibbs	}
13829680Sgibbs
13929680Sgibbs	if (fstat(flash, &sb) < 0) {
140160509Sjhb		error = errno;
14129680Sgibbs		warn("fstat(%s)", av[1]);
14229680Sgibbs		return (error);
14329680Sgibbs	}
14429680Sgibbs	if (sb.st_size % 1024 != 0 || sb.st_size > 0x7fffffff) {
14529680Sgibbs		warnx("Invalid flash file size");
146160509Sjhb		return (EINVAL);
14729680Sgibbs	}
14845739Speter
14929680Sgibbs	fd = mfi_open(mfi_unit);
15029680Sgibbs	if (fd < 0) {
15129680Sgibbs		error = errno;
15229680Sgibbs		warn("mfi_open");
15329680Sgibbs		return (error);
15429680Sgibbs	}
15529680Sgibbs
15629680Sgibbs	/* First, ask the firmware to allocate space for the flash file. */
15729680Sgibbs	mbox_store_word(mbox, sb.st_size);
15829680Sgibbs	mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_OPEN, NULL, 0, mbox, 4, &status);
159160509Sjhb	if (status != MFI_STAT_OK) {
160160509Sjhb		warnx("Failed to alloc flash memory: %s", mfi_status(status));
16129680Sgibbs		return (EIO);
16229680Sgibbs	}
16329680Sgibbs
16429680Sgibbs	/* Upload the file 64k at a time. */
16529680Sgibbs	buf = malloc(FLASH_BUF_SIZE);
16629680Sgibbs	if (buf == NULL) {
16729680Sgibbs		warnx("malloc failed");
168160509Sjhb		return (ENOMEM);
16929680Sgibbs	}
17029680Sgibbs	offset = 0;
171160509Sjhb	while (sb.st_size > 0) {
17229680Sgibbs		nread = read(flash, buf, FLASH_BUF_SIZE);
173180610Srwatson		if (nread <= 0 || nread % 1024 != 0) {
174180610Srwatson			warnx("Bad read from flash file");
175180610Srwatson			mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_CLOSE, NULL, 0,
176180610Srwatson			    NULL, 0, NULL);
177180610Srwatson			return (ENXIO);
178180610Srwatson		}
179180610Srwatson
180180610Srwatson		mbox_store_word(mbox, offset);
181180610Srwatson		mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_DOWNLOAD, buf, nread,
182180610Srwatson		    mbox, 4, &status);
183180610Srwatson		if (status != MFI_STAT_OK) {
184180610Srwatson			warnx("Flash download failed: %s", mfi_status(status));
185180610Srwatson			mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_CLOSE, NULL, 0,
186180610Srwatson			    NULL, 0, NULL);
187180610Srwatson			return (ENXIO);
188180610Srwatson		}
189180610Srwatson		sb.st_size -= nread;
190180610Srwatson		offset += nread;
191180610Srwatson	}
192180610Srwatson	close(flash);
193180610Srwatson
194180610Srwatson	/* Kick off the flash. */
195180610Srwatson	printf("WARNING: Firmware flash in progress, do not reboot machine... ");
196180610Srwatson	fflush(stdout);
197	mfi_dcmd_command(fd, MFI_DCMD_FLASH_FW_FLASH, &dummy, sizeof(dummy),
198	    NULL, 0, &status);
199	if (status != MFI_STAT_OK) {
200		printf("failed:\n\t%s\n", mfi_status(status));
201		return (ENXIO);
202	}
203	printf("finished\n");
204	error = display_pending_firmware(fd);
205
206	close(fd);
207
208	return (error);
209}
210MFI_COMMAND(top, flash, flash_adapter);
211