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