xref: /illumos-gate/usr/src/cmd/scadm/sparc/mpxu/common/download.c (revision 4c87aefe8930bd07275b8dd2e96ea5f24d93a52e)
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
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
256 usage()
257 {
258 	(void) fprintf(stderr, "\n%s\n\n",
259 	    gettext("USAGE: scadm download [boot] <file>"));
260 }
261