1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * download.c: support to the scadm download option (download service 28 * processor firmware) 29 */ 30 31 #include <libintl.h> 32 #include <stdio.h> 33 #include <string.h> 34 #include <time.h> /* required by rsc.h */ 35 36 #include "adm.h" 37 #include "librsc.h" 38 #include "smq.h" 39 40 41 extern smq_t ADM_bpMsgQueue; 42 extern smq_msg_t ADM_bpMsgBuffer[ADM_BP_BUFF_SIZE]; 43 44 static void usage(); 45 46 47 void 48 ADM_Process_download(int argc, char *argv[]) 49 { 50 int BootRetry; 51 uint8_t DownloadLocation; 52 static bp_msg_t Message; 53 static struct timespec Timeout; 54 char *Filename; 55 FILE *FilePtr; 56 timestruc_t Delay; 57 int i, err; 58 int retry; 59 int bootOpt; 60 61 if ((argc != 3) && (argc != 4)) { 62 usage(); 63 exit(-1); 64 } 65 66 if (argc == 4) { 67 if (strcasecmp(argv[2], "boot") != 0) { 68 usage(); 69 exit(-1); 70 } 71 Filename = argv[3]; 72 DownloadLocation = BP_DAT2_FLASH_BOOT; 73 bootOpt = 1; 74 } else { /* no [boot] option */ 75 76 Filename = argv[2]; 77 DownloadLocation = BP_DAT2_FLASH_MAIN; 78 bootOpt = 0; 79 } 80 81 if ((FilePtr = fopen(Filename, "r")) == NULL) { 82 (void) fprintf(stderr, "\n%s - \"%s\"\n\n", 83 gettext("scadm: file could not be opened"), Filename); 84 exit(-1); 85 } 86 87 88 /* Verify file is s-record */ 89 if (ADM_Valid_srecord(FilePtr) != 0) { 90 (void) fprintf(stderr, "\n%s - \"%s\"\n\n", 91 gettext("scadm: file not a valid s-record"), Filename); 92 exit(-1); 93 } 94 95 /* 96 * Don't call rscp_start() because SC may still be in the 97 * boot monitor. The boot monitor will not respond to 98 * rscp_start() 99 */ 100 101 /* 102 * Initialize Message Queue used between ADM_Callback and 103 * ADM_Boot_recv(). ADM_Callback is called from seperate thread. 104 */ 105 if (smq_init(&ADM_bpMsgQueue, ADM_bpMsgBuffer, 106 ADM_BP_BUFF_SIZE) != 0) { 107 108 (void) fprintf(stderr, "\n%s\n\n", 109 gettext("scadm: ERROR, unable to setup message queue")); 110 exit(-1); 111 } 112 113 /* Initialize callback for Boot Monitor RX */ 114 if (rscp_register_bpmsg_cb(ADM_Callback) != 0) { 115 (void) fprintf(stderr, "\n%s\n\n", 116 gettext("scadm: ERROR, callback init failed")); 117 exit(-1); 118 } 119 120 BootRetry = ADM_BOOT_RETRY; 121 while (BootRetry > 0) { 122 123 /* 124 * Initialize Message each time because this structure is reused 125 * during receive. Since this operation is not time critical, 126 * this is not a concern 127 */ 128 Message.cmd = BP_OBP_BOOTINIT; 129 Message.dat1 = 0; 130 Message.dat2 = DownloadLocation; 131 rscp_send_bpmsg(&Message); 132 133 /* 134 * Initialize Timeout each time just to be robust. Since this 135 * operation is not time critical, this is not a concern. 136 */ 137 Timeout.tv_nsec = 0; 138 Timeout.tv_sec = ADM_BOOT_INIT_TIMEOUT; 139 140 /* If we timeout, decrement BootRetry and try again */ 141 if (ADM_Boot_recv(&Message, &Timeout) != 0) { 142 143 /* We got a timeout */ 144 BootRetry = BootRetry - 1; 145 continue; 146 } else { 147 148 /* we got a message back, see what it is */ 149 if ((Message.cmd != BP_RSC_BOOTACK) || 150 (Message.dat1 != BP_DAT1_BOOTINIT_ACK)) { 151 152 ADM_Display_download_error(Message.cmd, 153 Message.dat1); 154 exit(-1); 155 } 156 157 /* 158 * We got a valid acknowledge, break out of loop and 159 * start to download s-record 160 */ 161 break; 162 } 163 } 164 165 /* See if we ever got a response */ 166 if (BootRetry <= 0) { 167 (void) fprintf(stderr, "\n%s\n\n", 168 gettext("scadm: SC did not respond during boot " 169 "initialization")); 170 exit(-1); 171 } 172 173 /* Download s-record */ 174 if (ADM_Send_file(FilePtr) != 0) { 175 (void) fprintf(stderr, "\n%s - \"%s\"\n\n", 176 gettext("scadm: Error downloading file"), Filename); 177 exit(-1); 178 } 179 180 /* wait a second for BootMonitor to catch up */ 181 Delay.tv_nsec = 0; 182 Delay.tv_sec = 1; 183 (void) nanosleep(&Delay, NULL); 184 185 /* Send Reset boot protocol message to reboot SC */ 186 Message.cmd = BP_OBP_RESET; 187 Message.dat1 = 0; 188 Message.dat2 = 0; 189 rscp_send_bpmsg(&Message); 190 191 /* Cleanup */ 192 rscp_unregister_bpmsg_cb(ADM_Callback); 193 (void) smq_destroy(&ADM_bpMsgQueue); 194 (void) fclose(FilePtr); 195 196 (void) printf("%s\n\n", gettext("Download completed successfully")); 197 198 (void) printf("%s\n\n", gettext("Please wait for verification")); 199 200 /* 201 * scadm cannot tell if the SC successfully verified the 202 * download or not, but instead attempts to send a 203 * status message (up to 60 times) and assumes proper 204 * operation when sucessfully sent. 205 * 206 * When the boot option is used, the SC may hang after 207 * resetting itself (after it sucessfully downloads and 208 * verifies the boot file). To work around this, scadm 209 * will (1) do a hard reset and pause for 10 seconds 210 * (2) retry the sending of status messages. 211 */ 212 213 retry = 0; 214 do { 215 if (retry == 1) { 216 /* reset the SC before retrying */ 217 if (rsc_nmi() != 0) { 218 (void) fprintf(stderr, "\n%s\n\n", 219 gettext( 220 "scadm: Unable to reset SC hardware")); 221 exit(-1); 222 } 223 /* delay while SC resets */ 224 Delay.tv_nsec = 0; 225 Delay.tv_sec = ADM_BOOT_LOAD_TIMEOUT; 226 (void) nanosleep(&Delay, NULL); 227 } 228 229 for (i = 0; i < 60; i++) { 230 rscp_msg_t msg; 231 msg.type = DP_RSC_STATUS; 232 msg.len = 0; 233 msg.data = NULL; 234 235 (void) printf("%s", gettext(".")); 236 (void) fflush(stdout); 237 238 err = rscp_send(&msg); 239 if (err == 0) 240 break; 241 } 242 if (err == 0) 243 break; 244 retry++; 245 } while (bootOpt && (retry < 2)); 246 if (err == 0) 247 (void) printf("\n%s\n\n", gettext("Complete")); 248 else 249 (void) printf("\n%s\n\n", gettext("Error during verification")); 250 } 251 252 253 static void 254 usage() 255 { 256 (void) fprintf(stderr, "\n%s\n\n", 257 gettext("USAGE: scadm download [boot] <file>")); 258 } 259