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