download.c revision 03831d35f7499c87d51205817c93e9a8d42c4bae
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* download.c: support to the scadm download option (download service
* processor firmware)
*/
#include <libintl.h>
#include <stdio.h>
#include <string.h>
#include <time.h> /* required by rsc.h */
#include "adm.h"
#include "librsc.h"
#include "smq.h"
extern smq_t ADM_bpMsgQueue;
extern smq_msg_t ADM_bpMsgBuffer[ADM_BP_BUFF_SIZE];
static void usage();
void
ADM_Process_download(int argc, char *argv[])
{
int BootRetry;
uint8_t DownloadLocation;
static bp_msg_t Message;
static struct timespec Timeout;
char *Filename;
FILE *FilePtr;
timestruc_t Delay;
int i, err;
int retry;
int bootOpt;
if ((argc != 3) && (argc != 4)) {
usage();
exit(-1);
}
if (argc == 4) {
if (strcasecmp(argv[2], "boot") != 0) {
usage();
exit(-1);
}
Filename = argv[3];
DownloadLocation = BP_DAT2_FLASH_BOOT;
bootOpt = 1;
} else { /* no [boot] option */
Filename = argv[2];
DownloadLocation = BP_DAT2_FLASH_MAIN;
bootOpt = 0;
}
if ((FilePtr = fopen(Filename, "r")) == NULL) {
(void) fprintf(stderr, "\n%s - \"%s\"\n\n",
gettext("scadm: file could not be opened"), Filename);
exit(-1);
}
/* Verify file is s-record */
if (ADM_Valid_srecord(FilePtr) != 0) {
(void) fprintf(stderr, "\n%s - \"%s\"\n\n",
gettext("scadm: file not a valid s-record"), Filename);
exit(-1);
}
/*
* Don't call rscp_start() because SC may still be in the
* boot monitor. The boot monitor will not respond to
* rscp_start()
*/
/*
* Initialize Message Queue used between ADM_Callback and
* ADM_Boot_recv(). ADM_Callback is called from seperate thread.
*/
if (smq_init(&ADM_bpMsgQueue, ADM_bpMsgBuffer,
ADM_BP_BUFF_SIZE) != 0) {
(void) fprintf(stderr, "\n%s\n\n",
gettext("scadm: ERROR, unable to setup message queue"));
exit(-1);
}
/* Initialize callback for Boot Monitor RX */
if (rscp_register_bpmsg_cb(ADM_Callback) != 0) {
(void) fprintf(stderr, "\n%s\n\n",
gettext("scadm: ERROR, callback init failed"));
exit(-1);
}
BootRetry = ADM_BOOT_RETRY;
while (BootRetry > 0) {
/*
* Initialize Message each time because this structure is reused
* during receive. Since this operation is not time critical,
* this is not a concern
*/
Message.cmd = BP_OBP_BOOTINIT;
Message.dat1 = 0;
Message.dat2 = DownloadLocation;
rscp_send_bpmsg(&Message);
/*
* Initialize Timeout each time just to be robust. Since this
* operation is not time critical, this is not a concern.
*/
Timeout.tv_nsec = 0;
Timeout.tv_sec = ADM_BOOT_INIT_TIMEOUT;
/* If we timeout, decrement BootRetry and try again */
if (ADM_Boot_recv(&Message, &Timeout) != 0) {
/* We got a timeout */
BootRetry = BootRetry - 1;
continue;
} else {
/* we got a message back, see what it is */
if ((Message.cmd != BP_RSC_BOOTACK) ||
(Message.dat1 != BP_DAT1_BOOTINIT_ACK)) {
ADM_Display_download_error(Message.cmd,
Message.dat1);
exit(-1);
}
/*
* We got a valid acknowledge, break out of loop and
* start to download s-record
*/
break;
}
}
/* See if we ever got a response */
if (BootRetry <= 0) {
(void) fprintf(stderr, "\n%s\n\n",
gettext("scadm: SC did not respond during boot "
"initialization"));
exit(-1);
}
/* Download s-record */
if (ADM_Send_file(FilePtr) != 0) {
(void) fprintf(stderr, "\n%s - \"%s\"\n\n",
gettext("scadm: Error downloading file"), Filename);
exit(-1);
}
/* wait a second for BootMonitor to catch up */
Delay.tv_nsec = 0;
Delay.tv_sec = 1;
(void) nanosleep(&Delay, NULL);
/* Send Reset boot protocol message to reboot SC */
Message.cmd = BP_OBP_RESET;
Message.dat1 = 0;
Message.dat2 = 0;
rscp_send_bpmsg(&Message);
/* Cleanup */
rscp_unregister_bpmsg_cb(ADM_Callback);
(void) smq_destroy(&ADM_bpMsgQueue);
(void) fclose(FilePtr);
(void) printf("%s\n\n", gettext("Download completed successfully"));
(void) printf("%s\n\n", gettext("Please wait for verification"));
/*
* scadm cannot tell if the SC successfully verified the
* download or not, but instead attempts to send a
* status message (up to 60 times) and assumes proper
* operation when sucessfully sent.
*
* When the boot option is used, the SC may hang after
* resetting itself (after it sucessfully downloads and
* verifies the boot file). To work around this, scadm
* will (1) do a hard reset and pause for 10 seconds
* (2) retry the sending of status messages.
*/
retry = 0;
do {
if (retry == 1) {
/* reset the SC before retrying */
if (rsc_nmi() != 0) {
(void) fprintf(stderr, "\n%s\n\n",
gettext(
"scadm: Unable to reset SC hardware"));
exit(-1);
}
/* delay while SC resets */
Delay.tv_nsec = 0;
Delay.tv_sec = ADM_BOOT_LOAD_TIMEOUT;
(void) nanosleep(&Delay, NULL);
}
for (i = 0; i < 60; i++) {
rscp_msg_t msg;
msg.type = DP_RSC_STATUS;
msg.len = 0;
msg.data = NULL;
(void) printf("%s", gettext("."));
(void) fflush(stdout);
err = rscp_send(&msg);
if (err == 0)
break;
}
if (err == 0)
break;
retry++;
} while (bootOpt && (retry < 2));
if (err == 0)
(void) printf("\n%s\n\n", gettext("Complete"));
else
(void) printf("\n%s\n\n", gettext("Error during verification"));
}
static void
usage()
{
(void) fprintf(stderr, "\n%s\n\n",
gettext("USAGE: scadm download [boot] <file>"));
}