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
43extern smq_t		ADM_bpMsgQueue;
44extern smq_msg_t	ADM_bpMsgBuffer[ADM_BP_BUFF_SIZE];
45
46static void usage();
47
48
49void
50ADM_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
255static void
256usage()
257{
258	(void) fprintf(stderr, "\n%s\n\n",
259	    gettext("USAGE: scadm download [boot] <file>"));
260}
261