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