xref: /illumos-gate/usr/src/cmd/scadm/sparc/mpxu/common/download.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
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