Commit b76a147b722565bde046f707a5cc92df8ea29738

Authored by Phil Sutter
Committed by Scott Wood
1 parent fcecb4a52c

env_nand.c: clarify log messages when env reading fails

The single message is misleading, since there is no equivalent success
note when reading the other copy succeeds. Instead, warn if one of the
redundant copies could not be loaded and emphasise on the error when
reading both fails.

Signed-off-by: Phil Sutter <phil.sutter@viprinet.com>

Showing 1 changed file with 8 additions and 4 deletions Inline Diff

1 /* 1 /*
2 * (C) Copyright 2000-2010 2 * (C) Copyright 2000-2010
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 * 4 *
5 * (C) Copyright 2008 5 * (C) Copyright 2008
6 * Stuart Wood, Lab X Technologies <stuart.wood@labxtechnologies.com> 6 * Stuart Wood, Lab X Technologies <stuart.wood@labxtechnologies.com>
7 * 7 *
8 * (C) Copyright 2004 8 * (C) Copyright 2004
9 * Jian Zhang, Texas Instruments, jzhang@ti.com. 9 * Jian Zhang, Texas Instruments, jzhang@ti.com.
10 * 10 *
11 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com> 11 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
12 * Andreas Heppel <aheppel@sysgo.de> 12 * Andreas Heppel <aheppel@sysgo.de>
13 * 13 *
14 * See file CREDITS for list of people who contributed to this 14 * See file CREDITS for list of people who contributed to this
15 * project. 15 * project.
16 * 16 *
17 * This program is free software; you can redistribute it and/or 17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as 18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of 19 * published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version. 20 * the License, or (at your option) any later version.
21 * 21 *
22 * This program is distributed in the hope that it will be useful, 22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details. 25 * GNU General Public License for more details.
26 * 26 *
27 * You should have received a copy of the GNU General Public License 27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software 28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30 * MA 02111-1307 USA 30 * MA 02111-1307 USA
31 */ 31 */
32 32
33 #include <common.h> 33 #include <common.h>
34 #include <command.h> 34 #include <command.h>
35 #include <environment.h> 35 #include <environment.h>
36 #include <linux/stddef.h> 36 #include <linux/stddef.h>
37 #include <malloc.h> 37 #include <malloc.h>
38 #include <nand.h> 38 #include <nand.h>
39 #include <search.h> 39 #include <search.h>
40 #include <errno.h> 40 #include <errno.h>
41 41
42 #if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND) 42 #if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND)
43 #define CMD_SAVEENV 43 #define CMD_SAVEENV
44 #elif defined(CONFIG_ENV_OFFSET_REDUND) 44 #elif defined(CONFIG_ENV_OFFSET_REDUND)
45 #error CONFIG_ENV_OFFSET_REDUND must have CONFIG_CMD_SAVEENV & CONFIG_CMD_NAND 45 #error CONFIG_ENV_OFFSET_REDUND must have CONFIG_CMD_SAVEENV & CONFIG_CMD_NAND
46 #endif 46 #endif
47 47
48 #if defined(CONFIG_ENV_SIZE_REDUND) && \ 48 #if defined(CONFIG_ENV_SIZE_REDUND) && \
49 (CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE) 49 (CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE)
50 #error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE 50 #error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE
51 #endif 51 #endif
52 52
53 #ifndef CONFIG_ENV_RANGE 53 #ifndef CONFIG_ENV_RANGE
54 #define CONFIG_ENV_RANGE CONFIG_ENV_SIZE 54 #define CONFIG_ENV_RANGE CONFIG_ENV_SIZE
55 #endif 55 #endif
56 56
57 char *env_name_spec = "NAND"; 57 char *env_name_spec = "NAND";
58 58
59 #if defined(ENV_IS_EMBEDDED) 59 #if defined(ENV_IS_EMBEDDED)
60 env_t *env_ptr = &environment; 60 env_t *env_ptr = &environment;
61 #elif defined(CONFIG_NAND_ENV_DST) 61 #elif defined(CONFIG_NAND_ENV_DST)
62 env_t *env_ptr = (env_t *)CONFIG_NAND_ENV_DST; 62 env_t *env_ptr = (env_t *)CONFIG_NAND_ENV_DST;
63 #else /* ! ENV_IS_EMBEDDED */ 63 #else /* ! ENV_IS_EMBEDDED */
64 env_t *env_ptr; 64 env_t *env_ptr;
65 #endif /* ENV_IS_EMBEDDED */ 65 #endif /* ENV_IS_EMBEDDED */
66 66
67 DECLARE_GLOBAL_DATA_PTR; 67 DECLARE_GLOBAL_DATA_PTR;
68 68
69 /* 69 /*
70 * This is called before nand_init() so we can't read NAND to 70 * This is called before nand_init() so we can't read NAND to
71 * validate env data. 71 * validate env data.
72 * 72 *
73 * Mark it OK for now. env_relocate() in env_common.c will call our 73 * Mark it OK for now. env_relocate() in env_common.c will call our
74 * relocate function which does the real validation. 74 * relocate function which does the real validation.
75 * 75 *
76 * When using a NAND boot image (like sequoia_nand), the environment 76 * When using a NAND boot image (like sequoia_nand), the environment
77 * can be embedded or attached to the U-Boot image in NAND flash. 77 * can be embedded or attached to the U-Boot image in NAND flash.
78 * This way the SPL loads not only the U-Boot image from NAND but 78 * This way the SPL loads not only the U-Boot image from NAND but
79 * also the environment. 79 * also the environment.
80 */ 80 */
81 int env_init(void) 81 int env_init(void)
82 { 82 {
83 #if defined(ENV_IS_EMBEDDED) || defined(CONFIG_NAND_ENV_DST) 83 #if defined(ENV_IS_EMBEDDED) || defined(CONFIG_NAND_ENV_DST)
84 int crc1_ok = 0, crc2_ok = 0; 84 int crc1_ok = 0, crc2_ok = 0;
85 env_t *tmp_env1; 85 env_t *tmp_env1;
86 86
87 #ifdef CONFIG_ENV_OFFSET_REDUND 87 #ifdef CONFIG_ENV_OFFSET_REDUND
88 env_t *tmp_env2; 88 env_t *tmp_env2;
89 89
90 tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE); 90 tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE);
91 crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc; 91 crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc;
92 #endif 92 #endif
93 tmp_env1 = env_ptr; 93 tmp_env1 = env_ptr;
94 crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc; 94 crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc;
95 95
96 if (!crc1_ok && !crc2_ok) { 96 if (!crc1_ok && !crc2_ok) {
97 gd->env_addr = 0; 97 gd->env_addr = 0;
98 gd->env_valid = 0; 98 gd->env_valid = 0;
99 99
100 return 0; 100 return 0;
101 } else if (crc1_ok && !crc2_ok) { 101 } else if (crc1_ok && !crc2_ok) {
102 gd->env_valid = 1; 102 gd->env_valid = 1;
103 } 103 }
104 #ifdef CONFIG_ENV_OFFSET_REDUND 104 #ifdef CONFIG_ENV_OFFSET_REDUND
105 else if (!crc1_ok && crc2_ok) { 105 else if (!crc1_ok && crc2_ok) {
106 gd->env_valid = 2; 106 gd->env_valid = 2;
107 } else { 107 } else {
108 /* both ok - check serial */ 108 /* both ok - check serial */
109 if (tmp_env1->flags == 255 && tmp_env2->flags == 0) 109 if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
110 gd->env_valid = 2; 110 gd->env_valid = 2;
111 else if (tmp_env2->flags == 255 && tmp_env1->flags == 0) 111 else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
112 gd->env_valid = 1; 112 gd->env_valid = 1;
113 else if (tmp_env1->flags > tmp_env2->flags) 113 else if (tmp_env1->flags > tmp_env2->flags)
114 gd->env_valid = 1; 114 gd->env_valid = 1;
115 else if (tmp_env2->flags > tmp_env1->flags) 115 else if (tmp_env2->flags > tmp_env1->flags)
116 gd->env_valid = 2; 116 gd->env_valid = 2;
117 else /* flags are equal - almost impossible */ 117 else /* flags are equal - almost impossible */
118 gd->env_valid = 1; 118 gd->env_valid = 1;
119 } 119 }
120 120
121 if (gd->env_valid == 2) 121 if (gd->env_valid == 2)
122 env_ptr = tmp_env2; 122 env_ptr = tmp_env2;
123 else 123 else
124 #endif 124 #endif
125 if (gd->env_valid == 1) 125 if (gd->env_valid == 1)
126 env_ptr = tmp_env1; 126 env_ptr = tmp_env1;
127 127
128 gd->env_addr = (ulong)env_ptr->data; 128 gd->env_addr = (ulong)env_ptr->data;
129 129
130 #else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */ 130 #else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
131 gd->env_addr = (ulong)&default_environment[0]; 131 gd->env_addr = (ulong)&default_environment[0];
132 gd->env_valid = 1; 132 gd->env_valid = 1;
133 #endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */ 133 #endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
134 134
135 return 0; 135 return 0;
136 } 136 }
137 137
138 #ifdef CMD_SAVEENV 138 #ifdef CMD_SAVEENV
139 /* 139 /*
140 * The legacy NAND code saved the environment in the first NAND device i.e., 140 * The legacy NAND code saved the environment in the first NAND device i.e.,
141 * nand_dev_desc + 0. This is also the behaviour using the new NAND code. 141 * nand_dev_desc + 0. This is also the behaviour using the new NAND code.
142 */ 142 */
143 int writeenv(size_t offset, u_char *buf) 143 int writeenv(size_t offset, u_char *buf)
144 { 144 {
145 size_t end = offset + CONFIG_ENV_RANGE; 145 size_t end = offset + CONFIG_ENV_RANGE;
146 size_t amount_saved = 0; 146 size_t amount_saved = 0;
147 size_t blocksize, len; 147 size_t blocksize, len;
148 u_char *char_ptr; 148 u_char *char_ptr;
149 149
150 blocksize = nand_info[0].erasesize; 150 blocksize = nand_info[0].erasesize;
151 len = min(blocksize, CONFIG_ENV_SIZE); 151 len = min(blocksize, CONFIG_ENV_SIZE);
152 152
153 while (amount_saved < CONFIG_ENV_SIZE && offset < end) { 153 while (amount_saved < CONFIG_ENV_SIZE && offset < end) {
154 if (nand_block_isbad(&nand_info[0], offset)) { 154 if (nand_block_isbad(&nand_info[0], offset)) {
155 offset += blocksize; 155 offset += blocksize;
156 } else { 156 } else {
157 char_ptr = &buf[amount_saved]; 157 char_ptr = &buf[amount_saved];
158 if (nand_write(&nand_info[0], offset, &len, char_ptr)) 158 if (nand_write(&nand_info[0], offset, &len, char_ptr))
159 return 1; 159 return 1;
160 160
161 offset += blocksize; 161 offset += blocksize;
162 amount_saved += len; 162 amount_saved += len;
163 } 163 }
164 } 164 }
165 if (amount_saved != CONFIG_ENV_SIZE) 165 if (amount_saved != CONFIG_ENV_SIZE)
166 return 1; 166 return 1;
167 167
168 return 0; 168 return 0;
169 } 169 }
170 170
171 #ifdef CONFIG_ENV_OFFSET_REDUND 171 #ifdef CONFIG_ENV_OFFSET_REDUND
172 static unsigned char env_flags; 172 static unsigned char env_flags;
173 173
174 int saveenv(void) 174 int saveenv(void)
175 { 175 {
176 env_t env_new; 176 env_t env_new;
177 ssize_t len; 177 ssize_t len;
178 char *res; 178 char *res;
179 int ret = 0; 179 int ret = 0;
180 nand_erase_options_t nand_erase_options; 180 nand_erase_options_t nand_erase_options;
181 181
182 memset(&nand_erase_options, 0, sizeof(nand_erase_options)); 182 memset(&nand_erase_options, 0, sizeof(nand_erase_options));
183 nand_erase_options.length = CONFIG_ENV_RANGE; 183 nand_erase_options.length = CONFIG_ENV_RANGE;
184 184
185 if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) 185 if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
186 return 1; 186 return 1;
187 187
188 res = (char *)&env_new.data; 188 res = (char *)&env_new.data;
189 len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); 189 len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
190 if (len < 0) { 190 if (len < 0) {
191 error("Cannot export environment: errno = %d\n", errno); 191 error("Cannot export environment: errno = %d\n", errno);
192 return 1; 192 return 1;
193 } 193 }
194 env_new.crc = crc32(0, env_new.data, ENV_SIZE); 194 env_new.crc = crc32(0, env_new.data, ENV_SIZE);
195 env_new.flags = ++env_flags; /* increase the serial */ 195 env_new.flags = ++env_flags; /* increase the serial */
196 196
197 if (gd->env_valid == 1) { 197 if (gd->env_valid == 1) {
198 puts("Erasing redundant NAND...\n"); 198 puts("Erasing redundant NAND...\n");
199 nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND; 199 nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND;
200 if (nand_erase_opts(&nand_info[0], &nand_erase_options)) 200 if (nand_erase_opts(&nand_info[0], &nand_erase_options))
201 return 1; 201 return 1;
202 202
203 puts("Writing to redundant NAND... "); 203 puts("Writing to redundant NAND... ");
204 ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *)&env_new); 204 ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *)&env_new);
205 } else { 205 } else {
206 puts("Erasing NAND...\n"); 206 puts("Erasing NAND...\n");
207 nand_erase_options.offset = CONFIG_ENV_OFFSET; 207 nand_erase_options.offset = CONFIG_ENV_OFFSET;
208 if (nand_erase_opts(&nand_info[0], &nand_erase_options)) 208 if (nand_erase_opts(&nand_info[0], &nand_erase_options))
209 return 1; 209 return 1;
210 210
211 puts("Writing to NAND... "); 211 puts("Writing to NAND... ");
212 ret = writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new); 212 ret = writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new);
213 } 213 }
214 if (ret) { 214 if (ret) {
215 puts("FAILED!\n"); 215 puts("FAILED!\n");
216 return 1; 216 return 1;
217 } 217 }
218 218
219 puts("done\n"); 219 puts("done\n");
220 220
221 gd->env_valid = gd->env_valid == 2 ? 1 : 2; 221 gd->env_valid = gd->env_valid == 2 ? 1 : 2;
222 222
223 return ret; 223 return ret;
224 } 224 }
225 #else /* ! CONFIG_ENV_OFFSET_REDUND */ 225 #else /* ! CONFIG_ENV_OFFSET_REDUND */
226 int saveenv(void) 226 int saveenv(void)
227 { 227 {
228 int ret = 0; 228 int ret = 0;
229 ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1); 229 ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
230 ssize_t len; 230 ssize_t len;
231 char *res; 231 char *res;
232 nand_erase_options_t nand_erase_options; 232 nand_erase_options_t nand_erase_options;
233 233
234 memset(&nand_erase_options, 0, sizeof(nand_erase_options)); 234 memset(&nand_erase_options, 0, sizeof(nand_erase_options));
235 nand_erase_options.length = CONFIG_ENV_RANGE; 235 nand_erase_options.length = CONFIG_ENV_RANGE;
236 nand_erase_options.offset = CONFIG_ENV_OFFSET; 236 nand_erase_options.offset = CONFIG_ENV_OFFSET;
237 237
238 if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) 238 if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
239 return 1; 239 return 1;
240 240
241 res = (char *)&env_new->data; 241 res = (char *)&env_new->data;
242 len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); 242 len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
243 if (len < 0) { 243 if (len < 0) {
244 error("Cannot export environment: errno = %d\n", errno); 244 error("Cannot export environment: errno = %d\n", errno);
245 return 1; 245 return 1;
246 } 246 }
247 env_new->crc = crc32(0, env_new->data, ENV_SIZE); 247 env_new->crc = crc32(0, env_new->data, ENV_SIZE);
248 248
249 puts("Erasing Nand...\n"); 249 puts("Erasing Nand...\n");
250 if (nand_erase_opts(&nand_info[0], &nand_erase_options)) 250 if (nand_erase_opts(&nand_info[0], &nand_erase_options))
251 return 1; 251 return 1;
252 252
253 puts("Writing to Nand... "); 253 puts("Writing to Nand... ");
254 if (writeenv(CONFIG_ENV_OFFSET, (u_char *)env_new)) { 254 if (writeenv(CONFIG_ENV_OFFSET, (u_char *)env_new)) {
255 puts("FAILED!\n"); 255 puts("FAILED!\n");
256 return 1; 256 return 1;
257 } 257 }
258 258
259 puts("done\n"); 259 puts("done\n");
260 return ret; 260 return ret;
261 } 261 }
262 #endif /* CONFIG_ENV_OFFSET_REDUND */ 262 #endif /* CONFIG_ENV_OFFSET_REDUND */
263 #endif /* CMD_SAVEENV */ 263 #endif /* CMD_SAVEENV */
264 264
265 int readenv(size_t offset, u_char *buf) 265 int readenv(size_t offset, u_char *buf)
266 { 266 {
267 size_t end = offset + CONFIG_ENV_RANGE; 267 size_t end = offset + CONFIG_ENV_RANGE;
268 size_t amount_loaded = 0; 268 size_t amount_loaded = 0;
269 size_t blocksize, len; 269 size_t blocksize, len;
270 u_char *char_ptr; 270 u_char *char_ptr;
271 271
272 blocksize = nand_info[0].erasesize; 272 blocksize = nand_info[0].erasesize;
273 if (!blocksize) 273 if (!blocksize)
274 return 1; 274 return 1;
275 275
276 len = min(blocksize, CONFIG_ENV_SIZE); 276 len = min(blocksize, CONFIG_ENV_SIZE);
277 277
278 while (amount_loaded < CONFIG_ENV_SIZE && offset < end) { 278 while (amount_loaded < CONFIG_ENV_SIZE && offset < end) {
279 if (nand_block_isbad(&nand_info[0], offset)) { 279 if (nand_block_isbad(&nand_info[0], offset)) {
280 offset += blocksize; 280 offset += blocksize;
281 } else { 281 } else {
282 char_ptr = &buf[amount_loaded]; 282 char_ptr = &buf[amount_loaded];
283 if (nand_read_skip_bad(&nand_info[0], offset, 283 if (nand_read_skip_bad(&nand_info[0], offset,
284 &len, char_ptr)) 284 &len, char_ptr))
285 return 1; 285 return 1;
286 286
287 offset += blocksize; 287 offset += blocksize;
288 amount_loaded += len; 288 amount_loaded += len;
289 } 289 }
290 } 290 }
291 291
292 if (amount_loaded != CONFIG_ENV_SIZE) 292 if (amount_loaded != CONFIG_ENV_SIZE)
293 return 1; 293 return 1;
294 294
295 return 0; 295 return 0;
296 } 296 }
297 297
298 #ifdef CONFIG_ENV_OFFSET_OOB 298 #ifdef CONFIG_ENV_OFFSET_OOB
299 int get_nand_env_oob(nand_info_t *nand, unsigned long *result) 299 int get_nand_env_oob(nand_info_t *nand, unsigned long *result)
300 { 300 {
301 struct mtd_oob_ops ops; 301 struct mtd_oob_ops ops;
302 uint32_t oob_buf[ENV_OFFSET_SIZE / sizeof(uint32_t)]; 302 uint32_t oob_buf[ENV_OFFSET_SIZE / sizeof(uint32_t)];
303 int ret; 303 int ret;
304 304
305 ops.datbuf = NULL; 305 ops.datbuf = NULL;
306 ops.mode = MTD_OOB_AUTO; 306 ops.mode = MTD_OOB_AUTO;
307 ops.ooboffs = 0; 307 ops.ooboffs = 0;
308 ops.ooblen = ENV_OFFSET_SIZE; 308 ops.ooblen = ENV_OFFSET_SIZE;
309 ops.oobbuf = (void *)oob_buf; 309 ops.oobbuf = (void *)oob_buf;
310 310
311 ret = nand->read_oob(nand, ENV_OFFSET_SIZE, &ops); 311 ret = nand->read_oob(nand, ENV_OFFSET_SIZE, &ops);
312 if (ret) { 312 if (ret) {
313 printf("error reading OOB block 0\n"); 313 printf("error reading OOB block 0\n");
314 return ret; 314 return ret;
315 } 315 }
316 316
317 if (oob_buf[0] == ENV_OOB_MARKER) { 317 if (oob_buf[0] == ENV_OOB_MARKER) {
318 *result = oob_buf[1] * nand->erasesize; 318 *result = oob_buf[1] * nand->erasesize;
319 } else if (oob_buf[0] == ENV_OOB_MARKER_OLD) { 319 } else if (oob_buf[0] == ENV_OOB_MARKER_OLD) {
320 *result = oob_buf[1]; 320 *result = oob_buf[1];
321 } else { 321 } else {
322 printf("No dynamic environment marker in OOB block 0\n"); 322 printf("No dynamic environment marker in OOB block 0\n");
323 return -ENOENT; 323 return -ENOENT;
324 } 324 }
325 325
326 return 0; 326 return 0;
327 } 327 }
328 #endif 328 #endif
329 329
330 #ifdef CONFIG_ENV_OFFSET_REDUND 330 #ifdef CONFIG_ENV_OFFSET_REDUND
331 void env_relocate_spec(void) 331 void env_relocate_spec(void)
332 { 332 {
333 #if !defined(ENV_IS_EMBEDDED) 333 #if !defined(ENV_IS_EMBEDDED)
334 int read1_fail = 0, read2_fail = 0;
334 int crc1_ok = 0, crc2_ok = 0; 335 int crc1_ok = 0, crc2_ok = 0;
335 env_t *ep, *tmp_env1, *tmp_env2; 336 env_t *ep, *tmp_env1, *tmp_env2;
336 337
337 tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE); 338 tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
338 tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE); 339 tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
339 if (tmp_env1 == NULL || tmp_env2 == NULL) { 340 if (tmp_env1 == NULL || tmp_env2 == NULL) {
340 puts("Can't allocate buffers for environment\n"); 341 puts("Can't allocate buffers for environment\n");
341 set_default_env("!malloc() failed"); 342 set_default_env("!malloc() failed");
342 goto done; 343 goto done;
343 } 344 }
344 345
345 if (readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1)) 346 read1_fail = readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1);
346 puts("No Valid Environment Area found\n"); 347 read2_fail = readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2);
347 348
348 if (readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2)) 349 if (read1_fail && read2_fail)
349 puts("No Valid Redundant Environment Area found\n"); 350 puts("*** Error - No Valid Environment Area found\n");
351 else if (read1_fail || read2_fail)
352 puts("*** Warning - some problems detected "
353 "reading environment; recovered successfully\n");
350 354
351 crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc; 355 crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc;
352 crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc; 356 crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc;
353 357
354 if (!crc1_ok && !crc2_ok) { 358 if (!crc1_ok && !crc2_ok) {
355 set_default_env("!bad CRC"); 359 set_default_env("!bad CRC");
356 goto done; 360 goto done;
357 } else if (crc1_ok && !crc2_ok) { 361 } else if (crc1_ok && !crc2_ok) {
358 gd->env_valid = 1; 362 gd->env_valid = 1;
359 } else if (!crc1_ok && crc2_ok) { 363 } else if (!crc1_ok && crc2_ok) {
360 gd->env_valid = 2; 364 gd->env_valid = 2;
361 } else { 365 } else {
362 /* both ok - check serial */ 366 /* both ok - check serial */
363 if (tmp_env1->flags == 255 && tmp_env2->flags == 0) 367 if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
364 gd->env_valid = 2; 368 gd->env_valid = 2;
365 else if (tmp_env2->flags == 255 && tmp_env1->flags == 0) 369 else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
366 gd->env_valid = 1; 370 gd->env_valid = 1;
367 else if (tmp_env1->flags > tmp_env2->flags) 371 else if (tmp_env1->flags > tmp_env2->flags)
368 gd->env_valid = 1; 372 gd->env_valid = 1;
369 else if (tmp_env2->flags > tmp_env1->flags) 373 else if (tmp_env2->flags > tmp_env1->flags)
370 gd->env_valid = 2; 374 gd->env_valid = 2;
371 else /* flags are equal - almost impossible */ 375 else /* flags are equal - almost impossible */
372 gd->env_valid = 1; 376 gd->env_valid = 1;
373 } 377 }
374 378
375 free(env_ptr); 379 free(env_ptr);
376 380
377 if (gd->env_valid == 1) 381 if (gd->env_valid == 1)
378 ep = tmp_env1; 382 ep = tmp_env1;
379 else 383 else
380 ep = tmp_env2; 384 ep = tmp_env2;
381 385
382 env_flags = ep->flags; 386 env_flags = ep->flags;
383 env_import((char *)ep, 0); 387 env_import((char *)ep, 0);
384 388
385 done: 389 done:
386 free(tmp_env1); 390 free(tmp_env1);
387 free(tmp_env2); 391 free(tmp_env2);
388 392
389 #endif /* ! ENV_IS_EMBEDDED */ 393 #endif /* ! ENV_IS_EMBEDDED */
390 } 394 }
391 #else /* ! CONFIG_ENV_OFFSET_REDUND */ 395 #else /* ! CONFIG_ENV_OFFSET_REDUND */
392 /* 396 /*
393 * The legacy NAND code saved the environment in the first NAND 397 * The legacy NAND code saved the environment in the first NAND
394 * device i.e., nand_dev_desc + 0. This is also the behaviour using 398 * device i.e., nand_dev_desc + 0. This is also the behaviour using
395 * the new NAND code. 399 * the new NAND code.
396 */ 400 */
397 void env_relocate_spec(void) 401 void env_relocate_spec(void)
398 { 402 {
399 #if !defined(ENV_IS_EMBEDDED) 403 #if !defined(ENV_IS_EMBEDDED)
400 int ret; 404 int ret;
401 ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE); 405 ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
402 406
403 #if defined(CONFIG_ENV_OFFSET_OOB) 407 #if defined(CONFIG_ENV_OFFSET_OOB)
404 ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset); 408 ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);
405 /* 409 /*
406 * If unable to read environment offset from NAND OOB then fall through 410 * If unable to read environment offset from NAND OOB then fall through
407 * to the normal environment reading code below 411 * to the normal environment reading code below
408 */ 412 */
409 if (!ret) { 413 if (!ret) {
410 printf("Found Environment offset in OOB..\n"); 414 printf("Found Environment offset in OOB..\n");
411 } else { 415 } else {
412 set_default_env("!no env offset in OOB"); 416 set_default_env("!no env offset in OOB");
413 return; 417 return;
414 } 418 }
415 #endif 419 #endif
416 420
417 ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf); 421 ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);
418 if (ret) { 422 if (ret) {
419 set_default_env("!readenv() failed"); 423 set_default_env("!readenv() failed");
420 return; 424 return;
421 } 425 }
422 426
423 env_import(buf, 1); 427 env_import(buf, 1);
424 #endif /* ! ENV_IS_EMBEDDED */ 428 #endif /* ! ENV_IS_EMBEDDED */
425 } 429 }
426 #endif /* CONFIG_ENV_OFFSET_REDUND */ 430 #endif /* CONFIG_ENV_OFFSET_REDUND */
427 431