1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
|
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include "MappedNandFlash.h"
#include <utility/trace.h>
#include <utility/assert.h>
#include <utility/math.h>
#include <string.h>
//------------------------------------------------------------------------------
// Internal definitions
//------------------------------------------------------------------------------
/// Casts
#define MANAGED(mapped) ((struct ManagedNandFlash *) mapped)
#define ECC(mapped) ((struct EccNandFlash *) mapped)
#define RAW(mapped) ((struct RawNandFlash *) mapped)
#define MODEL(mapped) ((struct NandFlashModel *) mapped)
/// Logical block mapping pattern
#define PATTERN(i) ((i << 1) & 0x73)
//------------------------------------------------------------------------------
// Internal functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Scans a mapped nandflash to find an existing logical block mapping. If a
/// block contains the mapping, its index is stored in the provided variable (if
/// pointer is not 0).
/// Returns 0 if mapping has been found; otherwise returns
/// NandCommon_ERROR_NOMAPPING if no mapping exists, or another
/// NandCommon_ERROR_xxx code.
/// \param mapped Pointer to a MappedNandFlash instance.
/// \param logicalMappingBlock Pointer to a variable for storing the block
/// number.
//------------------------------------------------------------------------------
static unsigned char FindLogicalMappingBlock(
const struct MappedNandFlash *mapped,
signed short *logicalMappingBlock)
{
unsigned short block;
unsigned char found;
unsigned short numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(mapped));
unsigned char error;
unsigned char data[NandCommon_MAXPAGEDATASIZE];
unsigned int i;
TRACE_INFO("FindLogicalMappingBlock()~%d\n\r", numBlocks);
// Search each LIVE block
found = 0;
block = 0;
while (!found && (block < numBlocks)) {
// Check that block is LIVE
if (MANAGED(mapped)->blockStatuses[block].status == NandBlockStatus_LIVE) {
// Read block
TRACE_INFO("Checking LIVE block #%d\n\r", block);
error = ManagedNandFlash_ReadPage(MANAGED(mapped), block, 0, data, 0);
if (!error) {
// Compare data with logical mapping pattern
i = 0;
found = 1;
while ((i < pageDataSize) && found) {
if (data[i] != PATTERN(i)) {
found = 0;
}
i++;
}
// If this is the mapping, stop looking
if (found) {
TRACE_WARNING_WP("-I- Logical mapping in block #%d\n\r",
block);
if (logicalMappingBlock) {
*logicalMappingBlock = block;
}
return 0;
}
}
else if (error != NandCommon_ERROR_WRONGSTATUS) {
TRACE_ERROR(
"FindLogicalMappingBlock: Failed to scan block #%d\n\r",
block);
return error;
}
}
block++;
}
TRACE_WARNING("No logical mapping found in device\n\r");
return NandCommon_ERROR_NOMAPPING;
}
//------------------------------------------------------------------------------
/// Loads the logical mapping contained in the given physical block.
/// Returns 0 if successful; otherwise, returns a NandCommon_ERROR code.
/// \param mapped Pointer to a MappedNandFlash instance.
/// \param physicalBlock Physical block number.
//------------------------------------------------------------------------------
static unsigned char LoadLogicalMapping(
struct MappedNandFlash *mapped,
unsigned short physicalBlock)
{
unsigned char error;
unsigned char data[NandCommon_MAXPAGEDATASIZE];
unsigned short pageDataSize =
NandFlashModel_GetPageDataSize(MODEL(mapped));
unsigned short numBlocks =
ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
unsigned int remainingSize;
unsigned char *currentBuffer;
unsigned short currentPage;
unsigned int readSize;
unsigned int i;
unsigned char status;
signed short logicalBlock;
//signed short firstBlock, lastBlock;
TRACE_INFO("LoadLogicalMapping(B#%d)\n\r", physicalBlock);
// Load mapping from pages #1 - #XXX of block
currentBuffer = (unsigned char *) mapped->logicalMapping;
remainingSize = sizeof(mapped->logicalMapping);
currentPage = 1;
while (remainingSize > 0) {
// Read page
readSize = min(remainingSize, pageDataSize);
error = ManagedNandFlash_ReadPage(MANAGED(mapped),
physicalBlock,
currentPage,
data,
0);
if (error) {
TRACE_ERROR(
"LoadLogicalMapping: Failed to load mapping\n\r");
return error;
}
// Copy page info
memcpy(currentBuffer, data, readSize);
currentBuffer += readSize;
remainingSize -= readSize;
currentPage++;
}
// Store mapping block index
mapped->logicalMappingBlock = physicalBlock;
// Power-loss recovery
for (i=0; i < numBlocks; i++) {
// Check that this is not the logical mapping block
if (i != physicalBlock) {
status = mapped->managed.blockStatuses[i].status;
logicalBlock = MappedNandFlash_PhysicalToLogical(mapped, i);
// Block is LIVE
if (status == NandBlockStatus_LIVE) {
// Block is not mapped -> release it
if (logicalBlock == -1) {
TRACE_WARNING_WP("-I- Release unmapped LIVE #%d\n\r",
i);
ManagedNandFlash_ReleaseBlock(MANAGED(mapped), i);
}
}
// Block is DIRTY
else if (status == NandBlockStatus_DIRTY) {
// Block is mapped -> fake it as live
if (logicalBlock != -1) {
TRACE_WARNING_WP("-I- Mark mapped DIRTY #%d -> LIVE\n\r",
i);
mapped->managed.blockStatuses[i].status =
NandBlockStatus_LIVE;
}
}
// Block is FREE or BAD
else {
// Block is mapped -> remove it from mapping
if (logicalBlock != -1) {
TRACE_WARNING_WP("-I- Unmap FREE or BAD #%d\n\r", i);
mapped->logicalMapping[logicalBlock] = -1;
}
}
}
}
TRACE_WARNING_WP("-I- Mapping loaded from block #%d\n\r", physicalBlock);
return 0;
}
//------------------------------------------------------------------------------
// Exported functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Initializes a MappedNandFlash instance. Scans the device to look for and
/// existing logical block mapping; otherwise starts from scratch (no block
/// mapped).
/// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xxx code.
/// \param mapped Pointer to a MappedNandFlash instance.
/// \param model Pointer to the underlying nand chip model. Can be 0.
/// \param commandAddress Address at which commands are sent.
/// \param addressAddress Address at which addresses are sent.
/// \param dataAddress Address at which data is sent.
/// \param pinChipEnable Pin controlling the CE signal of the NandFlash.
/// \param pinReadyBusy Pin used to monitor the ready/busy signal of the Nand.
/// \param baseBlock Basic physical block address of mapped area.
/// \param sizeInBlocks Number of blocks that is mapped.
//------------------------------------------------------------------------------
unsigned char MappedNandFlash_Initialize(
struct MappedNandFlash *mapped,
const struct NandFlashModel *model,
unsigned int commandAddress,
unsigned int addressAddress,
unsigned int dataAddress,
const Pin pinChipEnable,
const Pin pinReadyBusy,
unsigned short baseBlock,
unsigned short sizeInBlocks)
{
unsigned char error;
unsigned short numBlocks;
unsigned short block;
signed short logicalMappingBlock = 0;
TRACE_INFO("MappedNandFlash_Initialize()\n\r");
// Initialize ManagedNandFlash
error = ManagedNandFlash_Initialize(MANAGED(mapped),
model,
commandAddress,
addressAddress,
dataAddress,
pinChipEnable,
pinReadyBusy,
baseBlock,
sizeInBlocks);
if (error) {
return error;
}
// Scan to find logical mapping
mapped->mappingModified = 0;
error = FindLogicalMappingBlock(mapped, &logicalMappingBlock);
if (!error) {
// Extract mapping from block
mapped->logicalMappingBlock = logicalMappingBlock;
return LoadLogicalMapping(mapped, logicalMappingBlock);
}
else if (error == NandCommon_ERROR_NOMAPPING) {
// Start with no block mapped
mapped->logicalMappingBlock = -1;
numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
for (block=0; block < numBlocks; block++) {
mapped->logicalMapping[block] = -1;
}
}
else {
TRACE_ERROR("MappedNandFlash_Initialize: Initialize device\n\r");
return error;
}
return 0;
}
//------------------------------------------------------------------------------
/// Reads the data and/or spare area of a page in a mapped logical block.
/// Returns 0 if successful; otherwise, returns NandCommon_ERROR_BLOCKNOTMAPPED
/// if the block is not mapped, or a NandCommon_ERROR_xxx code.
/// \param mapped Pointer to a MappedNandFlash instance.
/// \param block Number of logical block to read page from.
/// \param page Number of page to read inside given block.
/// \param data Data area buffer, can be 0.
/// \param spare Spare area buffer, can be 0.
//------------------------------------------------------------------------------
unsigned char MappedNandFlash_ReadPage(
const struct MappedNandFlash *mapped,
unsigned short block,
unsigned short page,
void *data,
void *spare)
{
signed short physicalBlock;
TRACE_INFO("MappedNandFlash_ReadPage(LB#%d:P#%d)\n\r", block, page);
// Check if block is mapped
physicalBlock = mapped->logicalMapping[block];
if (physicalBlock == -1) {
TRACE_INFO( "MappedNandFlash_ReadPage: Block %d not mapped\n\r", block);
return NandCommon_ERROR_BLOCKNOTMAPPED;
}
// Read page from corresponding physical block
return ManagedNandFlash_ReadPage(MANAGED(mapped),
physicalBlock,
page,
data,
spare);
}
//------------------------------------------------------------------------------
/// Writes the data and/or spare area of a page in the given mapped logical
/// block.
/// Returns 0 if successful; otherwise, returns NandCommon_ERROR_BLOCKNOTMAPPED
/// (indicating the block is not logically mapped) or another NandCommon_ERROR
/// code.
/// \param mapped Pointer to a MappedNandFlash instance.
/// \param block Number of logical block to write on.
/// \param page Number of page to write inside given block.
/// \param data Data area buffer, can be 0.
/// \param spare Spare area buffer, can be 0.
//------------------------------------------------------------------------------
unsigned char MappedNandFlash_WritePage(
const struct MappedNandFlash *mapped,
unsigned short block,
unsigned short page,
void *data,
void *spare)
{
signed short physicalBlock;
TRACE_INFO("MappedNandFlash_WritePage(LB#%d:P#%d)\n\r", block, page);
// Check if block is mapped
physicalBlock = mapped->logicalMapping[block];
if (physicalBlock == -1) {
TRACE_ERROR("MappedNandFlash_WritePage: Block must be mapped\n\r");
return NandCommon_ERROR_BLOCKNOTMAPPED;
}
// Write page on physical block
return ManagedNandFlash_WritePage(MANAGED(mapped),
physicalBlock,
page,
data,
spare);
}
//------------------------------------------------------------------------------
/// Maps a logical block number to an actual physical block. This allocates
/// the physical block (meaning it must be FREE), and releases the previous
/// block being replaced (if any).
/// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xxx code.
/// \param mapped Pointer to a MappedNandFlash instance.
/// \param logicalBlock Logical block number to map.
/// \param physicalBlock Physical block to map to the logical one.
//------------------------------------------------------------------------------
unsigned char MappedNandFlash_Map(
struct MappedNandFlash *mapped,
unsigned short logicalBlock,
unsigned short physicalBlock)
{
unsigned char error;
signed short oldPhysicalBlock;
TRACE_INFO("MappedNandFlash_Map(LB#%d -> PB#%d)\n\r",
logicalBlock, physicalBlock);
ASSERT(
logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)),
"MappedNandFlash_Map: logicalBlock out-of-range\n\r");
ASSERT(
physicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)),
"MappedNandFlash_Map: physicalBlock out-of-range\n\r");
// Allocate physical block
error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock);
if (error) {
return error;
}
// Release currently mapped block (if any)
oldPhysicalBlock = mapped->logicalMapping[logicalBlock];
if (oldPhysicalBlock != -1) {
error =
ManagedNandFlash_ReleaseBlock(MANAGED(mapped), oldPhysicalBlock);
if (error) {
return error;
}
}
// Set mapping
mapped->logicalMapping[logicalBlock] = physicalBlock;
mapped->mappingModified = 1;
return 0;
}
//------------------------------------------------------------------------------
/// Unmaps a logical block by releasing the corresponding physical block (if
/// any).
/// Returns 0 if successful; otherwise returns a NandCommon_ERROR code.
/// \param mapped Pointer to a MappedNandFlash instance.
/// \param logicalBlock Number of logical block to unmap.
//------------------------------------------------------------------------------
unsigned char MappedNandFlash_Unmap(
struct MappedNandFlash *mapped,
unsigned short logicalBlock)
{
signed short physicalBlock = mapped->logicalMapping[logicalBlock];
unsigned char error;
TRACE_INFO("MappedNandFlash_Unmap(LB#%d)\n\r", logicalBlock);
ASSERT(
logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)),
"MappedNandFlash_Unmap: logicalBlock out-of-range\n\r");
if (physicalBlock != -1) {
error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped), physicalBlock);
if (error) {
return error;
}
}
mapped->logicalMapping[logicalBlock] = -1;
mapped->mappingModified = 1;
return 0;
}
//------------------------------------------------------------------------------
/// Returns the physical block mapped with the given logical block, or -1 if it
/// is not mapped.
/// \param mapped Pointer to a MappedNandFlash instance.
/// \param logicalBlock Logical block number.
//------------------------------------------------------------------------------
signed short MappedNandFlash_LogicalToPhysical(
const struct MappedNandFlash *mapped,
unsigned short logicalBlock)
{
ASSERT(
logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)),
"MappedNandFlash_LogicalToPhysical: logicalBlock out-of-range\n\r");
return mapped->logicalMapping[logicalBlock];
}
//------------------------------------------------------------------------------
/// Returns the logical block which is mapped to given physical block, or -1 if
/// the latter is not mapped.
/// \param mapped Pointer to a MappedNandFlash instance.
/// \param physicalBlock Physical block number.
//------------------------------------------------------------------------------
signed short MappedNandFlash_PhysicalToLogical(
const struct MappedNandFlash *mapped,
unsigned short physicalBlock)
{
unsigned short numBlocks =
ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
signed short logicalBlock;
ASSERT(
physicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)),
"MappedNandFlash_PhysicalToLogical: physicalBlock out-of-range\n\r");
// Search the mapping for the desired physical block
for (logicalBlock=0; logicalBlock < numBlocks; logicalBlock++) {
if (mapped->logicalMapping[logicalBlock] == physicalBlock) {
return logicalBlock;
}
}
return -1;
}
//------------------------------------------------------------------------------
/// Saves the logical mapping on a FREE, unmapped physical block. Allocates the
/// new block, releases the previous one (if any) and save the mapping.
/// Returns 0 if successful; otherwise, returns NandCommon_ERROR_WRONGSTATUS
/// if the block is not LIVE, or a NandCommon_ERROR code.
/// \param mapped Pointer to a MappedNandFlash instance.
/// \param physicalBlock Physical block number.
//------------------------------------------------------------------------------
unsigned char MappedNandFlash_SaveLogicalMapping(
struct MappedNandFlash *mapped,
unsigned short physicalBlock)
{
unsigned char error;
unsigned char data[NandCommon_MAXPAGEDATASIZE];
unsigned short pageDataSize =
NandFlashModel_GetPageDataSize(MODEL(mapped));
//unsigned short numBlocks =
// ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
unsigned int i;
unsigned int remainingSize;
unsigned char *currentBuffer;
unsigned short currentPage;
unsigned int writeSize;
signed short previousPhysicalBlock;
TRACE_INFO("MappedNandFlash_SaveLogicalMapping(B#%d)\n\r", physicalBlock);
// If mapping has not been modified, do nothing
if (!mapped->mappingModified) {
return 0;
}
// Allocate new block
error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock);
if (error) {
return error;
}
// Save mapping
previousPhysicalBlock = mapped->logicalMappingBlock;
mapped->logicalMappingBlock = physicalBlock;
// Save actual mapping in pages #1-#XXX
currentBuffer = (unsigned char *) mapped->logicalMapping;
remainingSize = sizeof(mapped->logicalMapping);
currentPage = 1;
while (remainingSize > 0) {
writeSize = min(remainingSize, pageDataSize);
memset(data, 0xFF, pageDataSize);
memcpy(data, currentBuffer, writeSize);
error = ManagedNandFlash_WritePage(MANAGED(mapped),
physicalBlock,
currentPage,
data,
0);
if (error) {
TRACE_ERROR(
"MappedNandFlash_SaveLogicalMapping: Failed to write mapping\n\r");
return error;
}
currentBuffer += writeSize;
remainingSize -= writeSize;
currentPage++;
}
// Mark page #0 of block with a distinguishible pattern, so the mapping can
// be retrieved at startup
for (i=0; i < pageDataSize; i++) {
data[i] = PATTERN(i);
}
error = ManagedNandFlash_WritePage(MANAGED(mapped),
physicalBlock, 0,
data, 0);
if (error) {
TRACE_ERROR(
"MappedNandFlash_SaveLogicalMapping: Failed to write pattern\n\r");
return error;
}
// Mapping is not modified anymore
mapped->mappingModified = 0;
// Release previous block (if any)
if (previousPhysicalBlock != -1) {
TRACE_DEBUG("Previous physical block was #%d\n\r",
previousPhysicalBlock);
error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped),
previousPhysicalBlock);
if (error) {
return error;
}
}
TRACE_INFO("Mapping saved on block #%d\n\r", physicalBlock);
return 0;
}
//------------------------------------------------------------------------------
/// Erase all blocks in the mapped area of nand flash.
/// \param managed Pointer to a MappedNandFlash instance.
/// \param level Erase level.
//------------------------------------------------------------------------------
unsigned char MappedNandFlash_EraseAll(
struct MappedNandFlash *mapped,
unsigned char level)
{
unsigned int block;
ManagedNandFlash_EraseAll(MANAGED(mapped), level);
// Reset to no block mapped
if (level > NandEraseDIRTY) {
mapped->logicalMappingBlock = -1;
mapped->mappingModified = 0;
for (block=0;
block < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
block++) {
mapped->logicalMapping[block] = -1;
}
}
return 0;
}
|