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