ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / mtd / nftlmount.c
1 /* 
2  * NFTL mount code with extensive checks
3  *
4  * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
5  * Copyright (C) 2000 Netgem S.A.
6  *
7  * $Id: nftlmount.c,v 1.34 2003/05/21 10:54:10 dwmw2 Exp $
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include <linux/kernel.h>
25 #include <asm/errno.h>
26 #include <linux/delay.h>
27 #include <linux/slab.h>
28 #include <linux/mtd/mtd.h>
29 #include <linux/mtd/nand.h>
30 #include <linux/mtd/nftl.h>
31
32 #define SECTORSIZE 512
33
34 char nftlmountrev[]="$Revision: 1.34 $";
35
36 /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
37  *      various device information of the NFTL partition and Bad Unit Table. Update
38  *      the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[]
39  *      is used for management of Erase Unit in other routines in nftl.c and nftlmount.c
40  */
41 static int find_boot_record(struct NFTLrecord *nftl)
42 {
43         struct nftl_uci1 h1;
44         struct nftl_oob oob;
45         unsigned int block, boot_record_count = 0;
46         size_t retlen;
47         u8 buf[SECTORSIZE];
48         struct NFTLMediaHeader *mh = &nftl->MediaHdr;
49         unsigned int i;
50
51         /* Assume logical EraseSize == physical erasesize for starting the scan. 
52            We'll sort it out later if we find a MediaHeader which says otherwise */
53         nftl->EraseSize = nftl->mbd.mtd->erasesize;
54         nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
55
56         nftl->MediaUnit = BLOCK_NIL;
57         nftl->SpareMediaUnit = BLOCK_NIL;
58
59         /* search for a valid boot record */
60         for (block = 0; block < nftl->nb_blocks; block++) {
61                 int ret;
62
63                 /* Check for ANAND header first. Then can whinge if it's found but later
64                    checks fail */
65                 if ((ret = MTD_READ(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) {
66                         static int warncount = 5;
67
68                         if (warncount) {
69                                 printk(KERN_WARNING "Block read at 0x%x of mtd%d failed: %d\n",
70                                        block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
71                                 if (!--warncount)
72                                         printk(KERN_WARNING "Further failures for this block will not be printed\n");
73                         }
74                         continue;
75                 }
76
77                 if (retlen < 6 || memcmp(buf, "ANAND", 6)) {
78                         /* ANAND\0 not found. Continue */
79 #if 0
80                         printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n", 
81                                block * nftl->EraseSize, nftl->mbd.mtd->index);
82 #endif                  
83                         continue;
84                 }
85
86                 /* To be safer with BIOS, also use erase mark as discriminant */
87                 if ((ret = MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8,
88                                 8, &retlen, (char *)&h1) < 0)) {
89                         printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n",
90                                block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
91                         continue;
92                 }
93
94 #if 0 /* Some people seem to have devices without ECC or erase marks
95          on the Media Header blocks. There are enough other sanity
96          checks in here that we can probably do without it.
97       */
98                 if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) {
99                         printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n",
100                                block * nftl->EraseSize, nftl->mbd.mtd->index, 
101                                le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1));
102                         continue;
103                 }
104
105                 /* Finally reread to check ECC */
106                 if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE,
107                                 &retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP) < 0)) {
108                         printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
109                                block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
110                         continue;
111                 }
112
113                 /* Paranoia. Check the ANAND header is still there after the ECC read */
114                 if (memcmp(buf, "ANAND", 6)) {
115                         printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but went away on reread!\n",
116                                block * nftl->EraseSize, nftl->mbd.mtd->index);
117                         printk(KERN_NOTICE "New data are: %02x %02x %02x %02x %02x %02x\n",
118                                buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
119                         continue;
120                 }
121 #endif
122                 /* OK, we like it. */
123
124                 if (boot_record_count) {
125                         /* We've already processed one. So we just check if
126                            this one is the same as the first one we found */
127                         if (memcmp(mh, buf, sizeof(struct NFTLMediaHeader))) {
128                                 printk(KERN_NOTICE "NFTL Media Headers at 0x%x and 0x%x disagree.\n",
129                                        nftl->MediaUnit * nftl->EraseSize, block * nftl->EraseSize);
130                                 /* if (debug) Print both side by side */
131                                 if (boot_record_count < 2) {
132                                         /* We haven't yet seen two real ones */
133                                         return -1;
134                                 }
135                                 continue;
136                         }
137                         if (boot_record_count == 1)
138                                 nftl->SpareMediaUnit = block;
139
140                         /* Mark this boot record (NFTL MediaHeader) block as reserved */
141                         nftl->ReplUnitTable[block] = BLOCK_RESERVED;
142
143
144                         boot_record_count++;
145                         continue;
146                 }
147
148                 /* This is the first we've seen. Copy the media header structure into place */
149                 memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
150
151                 /* Do some sanity checks on it */
152                 if (mh->UnitSizeFactor == 0) {
153                         printk(KERN_NOTICE "NFTL: UnitSizeFactor 0x00 detected. This violates the spec but we think we know what it means...\n");
154                 } else if (mh->UnitSizeFactor < 0xfc) {
155                         printk(KERN_NOTICE "Sorry, we don't support UnitSizeFactor 0x%02x\n",
156                                mh->UnitSizeFactor);
157                         return -1;
158                 } else if (mh->UnitSizeFactor != 0xff) {
159                         printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n",
160                                mh->UnitSizeFactor);
161                         nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor);
162                         nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
163                 }
164                 nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
165                 if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
166                         printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
167                         printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n", 
168                                nftl->nb_boot_blocks, nftl->nb_blocks);
169                         return -1;
170                 }
171
172                 nftl->numvunits = le32_to_cpu(mh->FormattedSize) / nftl->EraseSize;
173                 if (nftl->numvunits > (nftl->nb_blocks - nftl->nb_boot_blocks - 2)) {
174                         printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
175                         printk(KERN_NOTICE "numvunits (%d) > nb_blocks (%d) - nb_boot_blocks(%d) - 2\n",
176                                nftl->numvunits, nftl->nb_blocks, nftl->nb_boot_blocks);
177                         return -1;
178                 }
179                 
180                 nftl->mbd.size  = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
181
182                 /* If we're not using the last sectors in the device for some reason,
183                    reduce nb_blocks accordingly so we forget they're there */
184                 nftl->nb_blocks = le16_to_cpu(mh->NumEraseUnits) + le16_to_cpu(mh->FirstPhysicalEUN);
185
186                 /* XXX: will be suppressed */
187                 nftl->lastEUN = nftl->nb_blocks - 1;
188
189                 /* memory alloc */
190                 nftl->EUNtable = kmalloc(nftl->nb_blocks * sizeof(u16), GFP_KERNEL);
191                 if (!nftl->EUNtable) {
192                         printk(KERN_NOTICE "NFTL: allocation of EUNtable failed\n");
193                         return -ENOMEM;
194                 }
195
196                 nftl->ReplUnitTable = kmalloc(nftl->nb_blocks * sizeof(u16), GFP_KERNEL);
197                 if (!nftl->ReplUnitTable) {
198                         kfree(nftl->EUNtable);
199                         printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n");
200                         return -ENOMEM;
201                 }
202                 
203                 /* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */
204                 for (i = 0; i < nftl->nb_boot_blocks; i++)
205                         nftl->ReplUnitTable[i] = BLOCK_RESERVED;
206                 /* mark all remaining blocks as potentially containing data */
207                 for (; i < nftl->nb_blocks; i++) { 
208                         nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
209                 }
210
211                 /* Mark this boot record (NFTL MediaHeader) block as reserved */
212                 nftl->ReplUnitTable[block] = BLOCK_RESERVED;
213
214                 /* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */
215                 for (i = 0; i < nftl->nb_blocks; i++) {
216                         if ((i & (SECTORSIZE - 1)) == 0) {
217                                 /* read one sector for every SECTORSIZE of blocks */
218                                 if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize +
219                                                        i + SECTORSIZE, SECTORSIZE, &retlen, buf,
220                                                        (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) {
221                                         printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
222                                                ret);
223                                         kfree(nftl->ReplUnitTable);
224                                         kfree(nftl->EUNtable);
225                                         return -1;
226                                 }
227                         }
228                         /* mark the Bad Erase Unit as RESERVED in ReplUnitTable */
229                         if (buf[i & (SECTORSIZE - 1)] != 0xff)
230                                 nftl->ReplUnitTable[i] = BLOCK_RESERVED;
231                 }
232                 
233                 nftl->MediaUnit = block;
234                 boot_record_count++;
235                 
236         } /* foreach (block) */
237                 
238         return boot_record_count?0:-1;
239 }
240
241 static int memcmpb(void *a, int c, int n)
242 {
243         int i;
244         for (i = 0; i < n; i++) {
245                 if (c != ((unsigned char *)a)[i])
246                         return 1;
247         }
248         return 0;
249 }
250
251 /* check_free_sector: check if a free sector is actually FREE, i.e. All 0xff in data and oob area */
252 static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, 
253                               int check_oob)
254 {
255         int i, retlen;
256         u8 buf[SECTORSIZE];
257
258         for (i = 0; i < len; i += SECTORSIZE) {
259                 /* we want to read the sector without ECC check here since a free
260                    sector does not have ECC syndrome on it yet */
261                 if (MTD_READ(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0)
262                         return -1;
263                 if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
264                         return -1;
265
266                 if (check_oob) {
267                         if (MTD_READOOB(nftl->mbd.mtd, address, nftl->mbd.mtd->oobsize,
268                                         &retlen, buf) < 0)
269                                 return -1;
270                         if (memcmpb(buf, 0xff, nftl->mbd.mtd->oobsize) != 0)
271                                 return -1;
272                 }
273                 address += SECTORSIZE;
274         }
275
276         return 0;
277 }
278
279 /* NFTL_format: format a Erase Unit by erasing ALL Erase Zones in the Erase Unit and
280  *              Update NFTL metadata. Each erase operation is checked with check_free_sectors
281  *
282  * Return: 0 when succeed, -1 on error.
283  *
284  *  ToDo: 1. Is it neceressary to check_free_sector after erasing ?? 
285  *        2. UnitSizeFactor != 0xFF
286  */
287 int NFTL_formatblock(struct NFTLrecord *nftl, int block)
288 {
289         size_t retlen;
290         unsigned int nb_erases, erase_mark;
291         struct nftl_uci1 uci;
292         struct erase_info *instr = &nftl->instr;
293
294         /* Read the Unit Control Information #1 for Wear-Leveling */
295         if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8,
296                         8, &retlen, (char *)&uci) < 0)
297                 goto default_uci1;
298
299         erase_mark = le16_to_cpu ((uci.EraseMark | uci.EraseMark1));
300         if (erase_mark != ERASE_MARK) {
301         default_uci1:
302                 uci.EraseMark = cpu_to_le16(ERASE_MARK);
303                 uci.EraseMark1 = cpu_to_le16(ERASE_MARK);
304                 uci.WearInfo = cpu_to_le32(0);
305         }
306
307         memset(instr, 0, sizeof(struct erase_info));
308
309         /* XXX: use async erase interface, XXX: test return code */
310         instr->addr = block * nftl->EraseSize;
311         instr->len = nftl->EraseSize;
312         MTD_ERASE(nftl->mbd.mtd, instr);
313
314         if (instr->state == MTD_ERASE_FAILED) {
315                 /* could not format, FixMe: We should update the BadUnitTable 
316                    both in memory and on disk */
317                 printk("Error while formatting block %d\n", block);
318                 return -1;
319         } else {
320                 /* increase and write Wear-Leveling info */
321                 nb_erases = le32_to_cpu(uci.WearInfo);
322                 nb_erases++;
323
324                 /* wrap (almost impossible with current flashs) or free block */
325                 if (nb_erases == 0)
326                         nb_erases = 1;
327
328                 /* check the "freeness" of Erase Unit before updating metadata
329                  * FixMe:  is this check really necessary ? since we have check the
330                  *         return code after the erase operation. */
331                 if (check_free_sectors(nftl, instr->addr, nftl->EraseSize, 1) != 0)
332                         return -1;
333
334                 uci.WearInfo = le32_to_cpu(nb_erases);
335                 if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
336                                  &retlen, (char *)&uci) < 0)
337                         return -1;
338                 return 0;
339         }
340 }
341
342 /* check_sectors_in_chain: Check that each sector of a Virtual Unit Chain is correct.
343  *      Mark as 'IGNORE' each incorrect sector. This check is only done if the chain
344  *      was being folded when NFTL was interrupted.
345  *
346  *      The check_free_sectors in this function is neceressary. There is a possible
347  *      situation that after writing the Data area, the Block Control Information is
348  *      not updated according (due to power failure or something) which leaves the block
349  *      in an umconsistent state. So we have to check if a block is really FREE in this
350  *      case. */
351 static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_block)
352 {
353         unsigned int block, i, status;
354         struct nftl_bci bci;
355         int sectors_per_block, retlen;
356
357         sectors_per_block = nftl->EraseSize / SECTORSIZE;
358         block = first_block;
359         for (;;) {
360                 for (i = 0; i < sectors_per_block; i++) {
361                         if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i * SECTORSIZE,
362                                         8, &retlen, (char *)&bci) < 0)
363                                 status = SECTOR_IGNORE;
364                         else
365                                 status = bci.Status | bci.Status1;
366
367                         switch(status) {
368                         case SECTOR_FREE:
369                                 /* verify that the sector is really free. If not, mark
370                                    as ignore */
371                                 if (memcmpb(&bci, 0xff, 8) != 0 ||
372                                     check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE, 
373                                                        SECTORSIZE, 0) != 0) {
374                                         printk("Incorrect free sector %d in block %d: "
375                                                "marking it as ignored\n",
376                                                i, block);
377
378                                         /* sector not free actually : mark it as SECTOR_IGNORE  */
379                                         bci.Status = SECTOR_IGNORE;
380                                         bci.Status1 = SECTOR_IGNORE;
381                                         MTD_WRITEOOB(nftl->mbd.mtd,
382                                                      block * nftl->EraseSize + i * SECTORSIZE,
383                                                      8, &retlen, (char *)&bci);
384                                 }
385                                 break;
386                         default:
387                                 break;
388                         }
389                 }
390
391                 /* proceed to next Erase Unit on the chain */
392                 block = nftl->ReplUnitTable[block];
393                 if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
394                         printk("incorrect ReplUnitTable[] : %d\n", block);
395                 if (block == BLOCK_NIL || block >= nftl->nb_blocks)
396                         break;
397         }
398 }
399
400 /* calc_chain_lenght: Walk through a Virtual Unit Chain and estimate chain length */
401 static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block)
402 {
403         unsigned int length = 0, block = first_block;
404
405         for (;;) {
406                 length++;
407                 /* avoid infinite loops, although this is guaranted not to
408                    happen because of the previous checks */
409                 if (length >= nftl->nb_blocks) {
410                         printk("nftl: length too long %d !\n", length);
411                         break;
412                 }
413
414                 block = nftl->ReplUnitTable[block];
415                 if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
416                         printk("incorrect ReplUnitTable[] : %d\n", block);
417                 if (block == BLOCK_NIL || block >= nftl->nb_blocks)
418                         break;
419         }
420         return length;
421 }
422
423 /* format_chain: Format an invalid Virtual Unit chain. It frees all the Erase Units in a
424  *      Virtual Unit Chain, i.e. all the units are disconnected.
425  *
426  *      It is not stricly correct to begin from the first block of the chain because
427  *      if we stop the code, we may see again a valid chain if there was a first_block
428  *      flag in a block inside it. But is it really a problem ?
429  *
430  * FixMe: Figure out what the last statesment means. What if power failure when we are
431  *      in the for (;;) loop formatting blocks ??
432  */
433 static void format_chain(struct NFTLrecord *nftl, unsigned int first_block)
434 {
435         unsigned int block = first_block, block1;
436
437         printk("Formatting chain at block %d\n", first_block);
438
439         for (;;) {
440                 block1 = nftl->ReplUnitTable[block];
441
442                 printk("Formatting block %d\n", block);
443                 if (NFTL_formatblock(nftl, block) < 0) {
444                         /* cannot format !!!! Mark it as Bad Unit,
445                            FixMe: update the BadUnitTable on disk */
446                         nftl->ReplUnitTable[block] = BLOCK_RESERVED;
447                 } else {
448                         nftl->ReplUnitTable[block] = BLOCK_FREE;
449                 }
450
451                 /* goto next block on the chain */
452                 block = block1;
453
454                 if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
455                         printk("incorrect ReplUnitTable[] : %d\n", block);
456                 if (block == BLOCK_NIL || block >= nftl->nb_blocks)
457                         break;
458         }
459 }
460
461 /* check_and_mark_free_block: Verify that a block is free in the NFTL sense (valid erase mark) or
462  *      totally free (only 0xff).
463  *
464  * Definition: Free Erase Unit -- A properly erased/formatted Free Erase Unit should have meet the
465  *      following critia:
466  *      1. */
467 static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
468 {
469         struct nftl_uci1 h1;
470         unsigned int erase_mark;
471         size_t retlen;
472
473         /* check erase mark. */
474         if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, 
475                         &retlen, (char *)&h1) < 0)
476                 return -1;
477
478         erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
479         if (erase_mark != ERASE_MARK) {
480                 /* if no erase mark, the block must be totally free. This is
481                    possible in two cases : empty filsystem or interrupted erase (very unlikely) */
482                 if (check_free_sectors (nftl, block * nftl->EraseSize, nftl->EraseSize, 1) != 0)
483                         return -1;
484
485                 /* free block : write erase mark */
486                 h1.EraseMark = cpu_to_le16(ERASE_MARK);
487                 h1.EraseMark1 = cpu_to_le16(ERASE_MARK);
488                 h1.WearInfo = cpu_to_le32(0);
489                 if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, 
490                                  &retlen, (char *)&h1) < 0)
491                         return -1;
492         } else {
493 #if 0
494                 /* if erase mark present, need to skip it when doing check */
495                 for (i = 0; i < nftl->EraseSize; i += SECTORSIZE) {
496                         /* check free sector */
497                         if (check_free_sectors (nftl, block * nftl->EraseSize + i,
498                                                 SECTORSIZE, 0) != 0)
499                                 return -1;
500
501                         if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i,
502                                         16, &retlen, buf) < 0)
503                                 return -1;
504                         if (i == SECTORSIZE) {
505                                 /* skip erase mark */
506                                 if (memcmpb(buf, 0xff, 8))
507                                         return -1;
508                         } else {
509                                 if (memcmpb(buf, 0xff, 16))
510                                         return -1;
511                         }
512                 }
513 #endif
514         }
515
516         return 0;
517 }
518
519 /* get_fold_mark: Read fold mark from Unit Control Information #2, we use FOLD_MARK_IN_PROGRESS
520  *      to indicate that we are in the progression of a Virtual Unit Chain folding. If the UCI #2
521  *      is FOLD_MARK_IN_PROGRESS when mounting the NFTL, the (previous) folding process is interrupted
522  *      for some reason. A clean up/check of the VUC is neceressary in this case.
523  *
524  * WARNING: return 0 if read error
525  */
526 static int get_fold_mark(struct NFTLrecord *nftl, unsigned int block)
527 {
528         struct nftl_uci2 uci;
529         size_t retlen;
530
531         if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
532                         8, &retlen, (char *)&uci) < 0)
533                 return 0;
534
535         return le16_to_cpu((uci.FoldMark | uci.FoldMark1));
536 }
537
538 int NFTL_mount(struct NFTLrecord *s)
539 {
540         int i;
541         unsigned int first_logical_block, logical_block, rep_block, nb_erases, erase_mark;
542         unsigned int block, first_block, is_first_block;
543         int chain_length, do_format_chain;
544         struct nftl_uci0 h0;
545         struct nftl_uci1 h1;
546         size_t retlen;
547
548         /* search for NFTL MediaHeader and Spare NFTL Media Header */
549         if (find_boot_record(s) < 0) {
550                 printk("Could not find valid boot record\n");
551                 return -1;
552         }
553
554         /* init the logical to physical table */
555         for (i = 0; i < s->nb_blocks; i++) {
556                 s->EUNtable[i] = BLOCK_NIL;
557         }
558
559         /* first pass : explore each block chain */
560         first_logical_block = 0;
561         for (first_block = 0; first_block < s->nb_blocks; first_block++) {
562                 /* if the block was not already explored, we can look at it */
563                 if (s->ReplUnitTable[first_block] == BLOCK_NOTEXPLORED) {
564                         block = first_block;
565                         chain_length = 0;
566                         do_format_chain = 0;
567
568                         for (;;) {
569                                 /* read the block header. If error, we format the chain */
570                                 if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8, 
571                                                 &retlen, (char *)&h0) < 0 ||
572                                     MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8, 
573                                                 &retlen, (char *)&h1) < 0) {
574                                         s->ReplUnitTable[block] = BLOCK_NIL;
575                                         do_format_chain = 1;
576                                         break;
577                                 }
578
579                                 logical_block = le16_to_cpu ((h0.VirtUnitNum | h0.SpareVirtUnitNum));
580                                 rep_block = le16_to_cpu ((h0.ReplUnitNum | h0.SpareReplUnitNum));
581                                 nb_erases = le32_to_cpu (h1.WearInfo);
582                                 erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
583
584                                 is_first_block = !(logical_block >> 15);
585                                 logical_block = logical_block & 0x7fff;
586
587                                 /* invalid/free block test */
588                                 if (erase_mark != ERASE_MARK || logical_block >= s->nb_blocks) {
589                                         if (chain_length == 0) {
590                                                 /* if not currently in a chain, we can handle it safely */
591                                                 if (check_and_mark_free_block(s, block) < 0) {
592                                                         /* not really free: format it */
593                                                         printk("Formatting block %d\n", block);
594                                                         if (NFTL_formatblock(s, block) < 0) {
595                                                                 /* could not format: reserve the block */
596                                                                 s->ReplUnitTable[block] = BLOCK_RESERVED;
597                                                         } else {
598                                                                 s->ReplUnitTable[block] = BLOCK_FREE;
599                                                         }
600                                                 } else {
601                                                         /* free block: mark it */
602                                                         s->ReplUnitTable[block] = BLOCK_FREE;
603                                                 }
604                                                 /* directly examine the next block. */
605                                                 goto examine_ReplUnitTable;
606                                         } else {
607                                                 /* the block was in a chain : this is bad. We
608                                                    must format all the chain */
609                                                 printk("Block %d: free but referenced in chain %d\n",
610                                                        block, first_block);
611                                                 s->ReplUnitTable[block] = BLOCK_NIL;
612                                                 do_format_chain = 1;
613                                                 break;
614                                         }
615                                 }
616
617                                 /* we accept only first blocks here */
618                                 if (chain_length == 0) {
619                                         /* this block is not the first block in chain :
620                                            ignore it, it will be included in a chain
621                                            later, or marked as not explored */
622                                         if (!is_first_block)
623                                                 goto examine_ReplUnitTable;
624                                         first_logical_block = logical_block;
625                                 } else {
626                                         if (logical_block != first_logical_block) {
627                                                 printk("Block %d: incorrect logical block: %d expected: %d\n", 
628                                                        block, logical_block, first_logical_block);
629                                                 /* the chain is incorrect : we must format it,
630                                                    but we need to read it completly */
631                                                 do_format_chain = 1;
632                                         }
633                                         if (is_first_block) {
634                                                 /* we accept that a block is marked as first
635                                                    block while being last block in a chain
636                                                    only if the chain is being folded */
637                                                 if (get_fold_mark(s, block) != FOLD_MARK_IN_PROGRESS ||
638                                                     rep_block != 0xffff) {
639                                                         printk("Block %d: incorrectly marked as first block in chain\n",
640                                                                block);
641                                                         /* the chain is incorrect : we must format it,
642                                                            but we need to read it completly */
643                                                         do_format_chain = 1;
644                                                 } else {
645                                                         printk("Block %d: folding in progress - ignoring first block flag\n",
646                                                                block);
647                                                 }
648                                         }
649                                 }
650                                 chain_length++;
651                                 if (rep_block == 0xffff) {
652                                         /* no more blocks after */
653                                         s->ReplUnitTable[block] = BLOCK_NIL;
654                                         break;
655                                 } else if (rep_block >= s->nb_blocks) {
656                                         printk("Block %d: referencing invalid block %d\n", 
657                                                block, rep_block);
658                                         do_format_chain = 1;
659                                         s->ReplUnitTable[block] = BLOCK_NIL;
660                                         break;
661                                 } else if (s->ReplUnitTable[rep_block] != BLOCK_NOTEXPLORED) {
662                                         /* same problem as previous 'is_first_block' test:
663                                            we accept that the last block of a chain has
664                                            the first_block flag set if folding is in
665                                            progress. We handle here the case where the
666                                            last block appeared first */
667                                         if (s->ReplUnitTable[rep_block] == BLOCK_NIL &&
668                                             s->EUNtable[first_logical_block] == rep_block &&
669                                             get_fold_mark(s, first_block) == FOLD_MARK_IN_PROGRESS) {
670                                                 /* EUNtable[] will be set after */
671                                                 printk("Block %d: folding in progress - ignoring first block flag\n",
672                                                        rep_block);
673                                                 s->ReplUnitTable[block] = rep_block;
674                                                 s->EUNtable[first_logical_block] = BLOCK_NIL;
675                                         } else {
676                                                 printk("Block %d: referencing block %d already in another chain\n", 
677                                                        block, rep_block);
678                                                 /* XXX: should handle correctly fold in progress chains */
679                                                 do_format_chain = 1;
680                                                 s->ReplUnitTable[block] = BLOCK_NIL;
681                                         }
682                                         break;
683                                 } else {
684                                         /* this is OK */
685                                         s->ReplUnitTable[block] = rep_block;
686                                         block = rep_block;
687                                 }
688                         }
689
690                         /* the chain was completely explored. Now we can decide
691                            what to do with it */
692                         if (do_format_chain) {
693                                 /* invalid chain : format it */
694                                 format_chain(s, first_block);
695                         } else {
696                                 unsigned int first_block1, chain_to_format, chain_length1;
697                                 int fold_mark;
698                                 
699                                 /* valid chain : get foldmark */
700                                 fold_mark = get_fold_mark(s, first_block);
701                                 if (fold_mark == 0) {
702                                         /* cannot get foldmark : format the chain */
703                                         printk("Could read foldmark at block %d\n", first_block);
704                                         format_chain(s, first_block);
705                                 } else {
706                                         if (fold_mark == FOLD_MARK_IN_PROGRESS)
707                                                 check_sectors_in_chain(s, first_block);
708
709                                         /* now handle the case where we find two chains at the
710                                            same virtual address : we select the longer one,
711                                            because the shorter one is the one which was being
712                                            folded if the folding was not done in place */
713                                         first_block1 = s->EUNtable[first_logical_block];
714                                         if (first_block1 != BLOCK_NIL) {
715                                                 /* XXX: what to do if same length ? */
716                                                 chain_length1 = calc_chain_length(s, first_block1);
717                                                 printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n", 
718                                                        first_block1, chain_length1, first_block, chain_length);
719                                                 
720                                                 if (chain_length >= chain_length1) {
721                                                         chain_to_format = first_block1;
722                                                         s->EUNtable[first_logical_block] = first_block;
723                                                 } else {
724                                                         chain_to_format = first_block;
725                                                 }
726                                                 format_chain(s, chain_to_format);
727                                         } else {
728                                                 s->EUNtable[first_logical_block] = first_block;
729                                         }
730                                 }
731                         }
732                 }
733         examine_ReplUnitTable:;
734         }
735
736         /* second pass to format unreferenced blocks  and init free block count */
737         s->numfreeEUNs = 0;
738         s->LastFreeEUN = le16_to_cpu(s->MediaHdr.FirstPhysicalEUN);
739
740         for (block = 0; block < s->nb_blocks; block++) {
741                 if (s->ReplUnitTable[block] == BLOCK_NOTEXPLORED) {
742                         printk("Unreferenced block %d, formatting it\n", block);
743                         if (NFTL_formatblock(s, block) < 0)
744                                 s->ReplUnitTable[block] = BLOCK_RESERVED;
745                         else
746                                 s->ReplUnitTable[block] = BLOCK_FREE;
747                 }
748                 if (s->ReplUnitTable[block] == BLOCK_FREE) {
749                         s->numfreeEUNs++;
750                         s->LastFreeEUN = block;
751                 }
752         }
753
754         return 0;
755 }