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
ADM_Process_download(int argc,char * argv[])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
usage()254 usage()
255 {
256 (void) fprintf(stderr, "\n%s\n\n",
257 gettext("USAGE: scadm download [boot] <file>"));
258 }
259