/* * 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. */ /* * download.c: support to the scadm download option (download service * processor firmware) */ #include #include #include #include /* 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] ")); }