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