0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <asm/errno.h>
0012 #include <linux/delay.h>
0013 #include <linux/slab.h>
0014 #include <linux/mtd/mtd.h>
0015 #include <linux/mtd/rawnand.h>
0016 #include <linux/mtd/nftl.h>
0017
0018 #define SECTORSIZE 512
0019
0020
0021
0022
0023
0024
0025 static int find_boot_record(struct NFTLrecord *nftl)
0026 {
0027 struct nftl_uci1 h1;
0028 unsigned int block, boot_record_count = 0;
0029 size_t retlen;
0030 u8 buf[SECTORSIZE];
0031 struct NFTLMediaHeader *mh = &nftl->MediaHdr;
0032 struct mtd_info *mtd = nftl->mbd.mtd;
0033 unsigned int i;
0034
0035
0036
0037
0038
0039
0040
0041 nftl->EraseSize = nftl->mbd.mtd->erasesize;
0042 nftl->nb_blocks = (u32)nftl->mbd.mtd->size / nftl->EraseSize;
0043
0044 nftl->MediaUnit = BLOCK_NIL;
0045 nftl->SpareMediaUnit = BLOCK_NIL;
0046
0047
0048 for (block = 0; block < nftl->nb_blocks; block++) {
0049 int ret;
0050
0051
0052
0053 ret = mtd_read(mtd, block * nftl->EraseSize, SECTORSIZE,
0054 &retlen, buf);
0055
0056
0057 if (retlen != SECTORSIZE) {
0058 static int warncount = 5;
0059
0060 if (warncount) {
0061 printk(KERN_WARNING "Block read at 0x%x of mtd%d failed: %d\n",
0062 block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
0063 if (!--warncount)
0064 printk(KERN_WARNING "Further failures for this block will not be printed\n");
0065 }
0066 continue;
0067 }
0068
0069 if (retlen < 6 || memcmp(buf, "ANAND", 6)) {
0070
0071 #if 0
0072 printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n",
0073 block * nftl->EraseSize, nftl->mbd.mtd->index);
0074 #endif
0075 continue;
0076 }
0077
0078
0079 ret = nftl_read_oob(mtd, block * nftl->EraseSize +
0080 SECTORSIZE + 8, 8, &retlen,
0081 (char *)&h1);
0082 if (ret < 0) {
0083 printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n",
0084 block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
0085 continue;
0086 }
0087
0088 #if 0
0089
0090
0091
0092 if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) {
0093 printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n",
0094 block * nftl->EraseSize, nftl->mbd.mtd->index,
0095 le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1));
0096 continue;
0097 }
0098
0099
0100 ret = mtd->read(mtd, block * nftl->EraseSize, SECTORSIZE,
0101 &retlen, buf);
0102 if (ret < 0) {
0103 printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
0104 block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
0105 continue;
0106 }
0107
0108
0109 if (memcmp(buf, "ANAND", 6)) {
0110 printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but went away on reread!\n",
0111 block * nftl->EraseSize, nftl->mbd.mtd->index);
0112 printk(KERN_NOTICE "New data are: %6ph\n", buf);
0113 continue;
0114 }
0115 #endif
0116
0117
0118 if (boot_record_count) {
0119
0120
0121 if (memcmp(mh, buf, sizeof(struct NFTLMediaHeader))) {
0122 printk(KERN_NOTICE "NFTL Media Headers at 0x%x and 0x%x disagree.\n",
0123 nftl->MediaUnit * nftl->EraseSize, block * nftl->EraseSize);
0124
0125 if (boot_record_count < 2) {
0126
0127 return -1;
0128 }
0129 continue;
0130 }
0131 if (boot_record_count == 1)
0132 nftl->SpareMediaUnit = block;
0133
0134
0135 nftl->ReplUnitTable[block] = BLOCK_RESERVED;
0136
0137
0138 boot_record_count++;
0139 continue;
0140 }
0141
0142
0143 memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
0144
0145
0146 #if 0
0147 The new DiskOnChip driver scans the MediaHeader itself, and presents a virtual
0148 erasesize based on UnitSizeFactor. So the erasesize we read from the mtd
0149 device is already correct.
0150 if (mh->UnitSizeFactor == 0) {
0151 printk(KERN_NOTICE "NFTL: UnitSizeFactor 0x00 detected. This violates the spec but we think we know what it means...\n");
0152 } else if (mh->UnitSizeFactor < 0xfc) {
0153 printk(KERN_NOTICE "Sorry, we don't support UnitSizeFactor 0x%02x\n",
0154 mh->UnitSizeFactor);
0155 return -1;
0156 } else if (mh->UnitSizeFactor != 0xff) {
0157 printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n",
0158 mh->UnitSizeFactor);
0159 nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor);
0160 nftl->nb_blocks = (u32)nftl->mbd.mtd->size / nftl->EraseSize;
0161 }
0162 #endif
0163 nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
0164 if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
0165 printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
0166 printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n",
0167 nftl->nb_boot_blocks, nftl->nb_blocks);
0168 return -1;
0169 }
0170
0171 nftl->numvunits = le32_to_cpu(mh->FormattedSize) / nftl->EraseSize;
0172 if (nftl->numvunits > (nftl->nb_blocks - nftl->nb_boot_blocks - 2)) {
0173 printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
0174 printk(KERN_NOTICE "numvunits (%d) > nb_blocks (%d) - nb_boot_blocks(%d) - 2\n",
0175 nftl->numvunits, nftl->nb_blocks, nftl->nb_boot_blocks);
0176 return -1;
0177 }
0178
0179 nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
0180
0181
0182
0183 nftl->nb_blocks = le16_to_cpu(mh->NumEraseUnits) + le16_to_cpu(mh->FirstPhysicalEUN);
0184
0185
0186 nftl->lastEUN = nftl->nb_blocks - 1;
0187
0188
0189 nftl->EUNtable = kmalloc_array(nftl->nb_blocks, sizeof(u16),
0190 GFP_KERNEL);
0191 if (!nftl->EUNtable)
0192 return -ENOMEM;
0193
0194 nftl->ReplUnitTable = kmalloc_array(nftl->nb_blocks,
0195 sizeof(u16),
0196 GFP_KERNEL);
0197 if (!nftl->ReplUnitTable) {
0198 kfree(nftl->EUNtable);
0199 return -ENOMEM;
0200 }
0201
0202
0203 for (i = 0; i < nftl->nb_boot_blocks; i++)
0204 nftl->ReplUnitTable[i] = BLOCK_RESERVED;
0205
0206 for (; i < nftl->nb_blocks; i++) {
0207 nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
0208 }
0209
0210
0211 nftl->ReplUnitTable[block] = BLOCK_RESERVED;
0212
0213
0214 for (i = 0; i < nftl->nb_blocks; i++) {
0215 #if 0
0216 The new DiskOnChip driver already scanned the bad block table. Just query it.
0217 if ((i & (SECTORSIZE - 1)) == 0) {
0218
0219 ret = mtd->read(nftl->mbd.mtd,
0220 block * nftl->EraseSize + i +
0221 SECTORSIZE, SECTORSIZE,
0222 &retlen, buf);
0223 if (ret < 0) {
0224 printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
0225 ret);
0226 kfree(nftl->ReplUnitTable);
0227 kfree(nftl->EUNtable);
0228 return -1;
0229 }
0230 }
0231
0232 if (buf[i & (SECTORSIZE - 1)] != 0xff)
0233 nftl->ReplUnitTable[i] = BLOCK_RESERVED;
0234 #endif
0235 if (mtd_block_isbad(nftl->mbd.mtd,
0236 i * nftl->EraseSize))
0237 nftl->ReplUnitTable[i] = BLOCK_RESERVED;
0238 }
0239
0240 nftl->MediaUnit = block;
0241 boot_record_count++;
0242
0243 }
0244
0245 return boot_record_count?0:-1;
0246 }
0247
0248 static int memcmpb(void *a, int c, int n)
0249 {
0250 int i;
0251 for (i = 0; i < n; i++) {
0252 if (c != ((unsigned char *)a)[i])
0253 return 1;
0254 }
0255 return 0;
0256 }
0257
0258
0259 static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len,
0260 int check_oob)
0261 {
0262 struct mtd_info *mtd = nftl->mbd.mtd;
0263 size_t retlen;
0264 int i, ret;
0265 u8 *buf;
0266
0267 buf = kmalloc(SECTORSIZE + mtd->oobsize, GFP_KERNEL);
0268 if (!buf)
0269 return -ENOMEM;
0270
0271 ret = -1;
0272 for (i = 0; i < len; i += SECTORSIZE) {
0273 if (mtd_read(mtd, address, SECTORSIZE, &retlen, buf))
0274 goto out;
0275 if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
0276 goto out;
0277
0278 if (check_oob) {
0279 if(nftl_read_oob(mtd, address, mtd->oobsize,
0280 &retlen, &buf[SECTORSIZE]) < 0)
0281 goto out;
0282 if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)
0283 goto out;
0284 }
0285 address += SECTORSIZE;
0286 }
0287
0288 ret = 0;
0289
0290 out:
0291 kfree(buf);
0292 return ret;
0293 }
0294
0295
0296
0297
0298
0299
0300
0301
0302 int NFTL_formatblock(struct NFTLrecord *nftl, int block)
0303 {
0304 size_t retlen;
0305 unsigned int nb_erases, erase_mark;
0306 struct nftl_uci1 uci;
0307 struct erase_info *instr = &nftl->instr;
0308 struct mtd_info *mtd = nftl->mbd.mtd;
0309
0310
0311 if (nftl_read_oob(mtd, block * nftl->EraseSize + SECTORSIZE + 8,
0312 8, &retlen, (char *)&uci) < 0)
0313 goto default_uci1;
0314
0315 erase_mark = le16_to_cpu ((uci.EraseMark | uci.EraseMark1));
0316 if (erase_mark != ERASE_MARK) {
0317 default_uci1:
0318 uci.EraseMark = cpu_to_le16(ERASE_MARK);
0319 uci.EraseMark1 = cpu_to_le16(ERASE_MARK);
0320 uci.WearInfo = cpu_to_le32(0);
0321 }
0322
0323 memset(instr, 0, sizeof(struct erase_info));
0324
0325
0326 instr->addr = block * nftl->EraseSize;
0327 instr->len = nftl->EraseSize;
0328 if (mtd_erase(mtd, instr)) {
0329 printk("Error while formatting block %d\n", block);
0330 goto fail;
0331 }
0332
0333
0334 nb_erases = le32_to_cpu(uci.WearInfo);
0335 nb_erases++;
0336
0337
0338 if (nb_erases == 0)
0339 nb_erases = 1;
0340
0341
0342
0343
0344
0345 if (check_free_sectors(nftl, instr->addr, nftl->EraseSize, 1) != 0)
0346 goto fail;
0347
0348 uci.WearInfo = le32_to_cpu(nb_erases);
0349 if (nftl_write_oob(mtd, block * nftl->EraseSize + SECTORSIZE +
0350 8, 8, &retlen, (char *)&uci) < 0)
0351 goto fail;
0352 return 0;
0353 fail:
0354
0355
0356 mtd_block_markbad(nftl->mbd.mtd, instr->addr);
0357 return -1;
0358 }
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369 static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_block)
0370 {
0371 struct mtd_info *mtd = nftl->mbd.mtd;
0372 unsigned int block, i, status;
0373 struct nftl_bci bci;
0374 int sectors_per_block;
0375 size_t retlen;
0376
0377 sectors_per_block = nftl->EraseSize / SECTORSIZE;
0378 block = first_block;
0379 for (;;) {
0380 for (i = 0; i < sectors_per_block; i++) {
0381 if (nftl_read_oob(mtd,
0382 block * nftl->EraseSize + i * SECTORSIZE,
0383 8, &retlen, (char *)&bci) < 0)
0384 status = SECTOR_IGNORE;
0385 else
0386 status = bci.Status | bci.Status1;
0387
0388 switch(status) {
0389 case SECTOR_FREE:
0390
0391
0392 if (memcmpb(&bci, 0xff, 8) != 0 ||
0393 check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE,
0394 SECTORSIZE, 0) != 0) {
0395 printk("Incorrect free sector %d in block %d: "
0396 "marking it as ignored\n",
0397 i, block);
0398
0399
0400 bci.Status = SECTOR_IGNORE;
0401 bci.Status1 = SECTOR_IGNORE;
0402 nftl_write_oob(mtd, block *
0403 nftl->EraseSize +
0404 i * SECTORSIZE, 8,
0405 &retlen, (char *)&bci);
0406 }
0407 break;
0408 default:
0409 break;
0410 }
0411 }
0412
0413
0414 block = nftl->ReplUnitTable[block];
0415 if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
0416 printk("incorrect ReplUnitTable[] : %d\n", block);
0417 if (block == BLOCK_NIL || block >= nftl->nb_blocks)
0418 break;
0419 }
0420 }
0421
0422
0423 static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block)
0424 {
0425 unsigned int length = 0, block = first_block;
0426
0427 for (;;) {
0428 length++;
0429
0430
0431 if (length >= nftl->nb_blocks) {
0432 printk("nftl: length too long %d !\n", length);
0433 break;
0434 }
0435
0436 block = nftl->ReplUnitTable[block];
0437 if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
0438 printk("incorrect ReplUnitTable[] : %d\n", block);
0439 if (block == BLOCK_NIL || block >= nftl->nb_blocks)
0440 break;
0441 }
0442 return length;
0443 }
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455 static void format_chain(struct NFTLrecord *nftl, unsigned int first_block)
0456 {
0457 unsigned int block = first_block, block1;
0458
0459 printk("Formatting chain at block %d\n", first_block);
0460
0461 for (;;) {
0462 block1 = nftl->ReplUnitTable[block];
0463
0464 printk("Formatting block %d\n", block);
0465 if (NFTL_formatblock(nftl, block) < 0) {
0466
0467 nftl->ReplUnitTable[block] = BLOCK_RESERVED;
0468 } else {
0469 nftl->ReplUnitTable[block] = BLOCK_FREE;
0470 }
0471
0472
0473 block = block1;
0474
0475 if (!(block == BLOCK_NIL || block < nftl->nb_blocks))
0476 printk("incorrect ReplUnitTable[] : %d\n", block);
0477 if (block == BLOCK_NIL || block >= nftl->nb_blocks)
0478 break;
0479 }
0480 }
0481
0482
0483
0484
0485
0486
0487
0488 static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
0489 {
0490 struct mtd_info *mtd = nftl->mbd.mtd;
0491 struct nftl_uci1 h1;
0492 unsigned int erase_mark;
0493 size_t retlen;
0494
0495
0496 if (nftl_read_oob(mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
0497 &retlen, (char *)&h1) < 0)
0498 return -1;
0499
0500 erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
0501 if (erase_mark != ERASE_MARK) {
0502
0503
0504 if (check_free_sectors (nftl, block * nftl->EraseSize, nftl->EraseSize, 1) != 0)
0505 return -1;
0506
0507
0508 h1.EraseMark = cpu_to_le16(ERASE_MARK);
0509 h1.EraseMark1 = cpu_to_le16(ERASE_MARK);
0510 h1.WearInfo = cpu_to_le32(0);
0511 if (nftl_write_oob(mtd,
0512 block * nftl->EraseSize + SECTORSIZE + 8, 8,
0513 &retlen, (char *)&h1) < 0)
0514 return -1;
0515 } else {
0516 #if 0
0517
0518 for (i = 0; i < nftl->EraseSize; i += SECTORSIZE) {
0519
0520 if (check_free_sectors (nftl, block * nftl->EraseSize + i,
0521 SECTORSIZE, 0) != 0)
0522 return -1;
0523
0524 if (nftl_read_oob(mtd, block * nftl->EraseSize + i,
0525 16, &retlen, buf) < 0)
0526 return -1;
0527 if (i == SECTORSIZE) {
0528
0529 if (memcmpb(buf, 0xff, 8))
0530 return -1;
0531 } else {
0532 if (memcmpb(buf, 0xff, 16))
0533 return -1;
0534 }
0535 }
0536 #endif
0537 }
0538
0539 return 0;
0540 }
0541
0542
0543
0544
0545
0546
0547
0548
0549 static int get_fold_mark(struct NFTLrecord *nftl, unsigned int block)
0550 {
0551 struct mtd_info *mtd = nftl->mbd.mtd;
0552 struct nftl_uci2 uci;
0553 size_t retlen;
0554
0555 if (nftl_read_oob(mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
0556 8, &retlen, (char *)&uci) < 0)
0557 return 0;
0558
0559 return le16_to_cpu((uci.FoldMark | uci.FoldMark1));
0560 }
0561
0562 int NFTL_mount(struct NFTLrecord *s)
0563 {
0564 int i;
0565 unsigned int first_logical_block, logical_block, rep_block, erase_mark;
0566 unsigned int block, first_block, is_first_block;
0567 int chain_length, do_format_chain;
0568 struct nftl_uci0 h0;
0569 struct nftl_uci1 h1;
0570 struct mtd_info *mtd = s->mbd.mtd;
0571 size_t retlen;
0572
0573
0574 if (find_boot_record(s) < 0) {
0575 printk("Could not find valid boot record\n");
0576 return -1;
0577 }
0578
0579
0580 for (i = 0; i < s->nb_blocks; i++) {
0581 s->EUNtable[i] = BLOCK_NIL;
0582 }
0583
0584
0585 first_logical_block = 0;
0586 for (first_block = 0; first_block < s->nb_blocks; first_block++) {
0587
0588 if (s->ReplUnitTable[first_block] == BLOCK_NOTEXPLORED) {
0589 block = first_block;
0590 chain_length = 0;
0591 do_format_chain = 0;
0592
0593 for (;;) {
0594
0595 if (nftl_read_oob(mtd,
0596 block * s->EraseSize + 8, 8,
0597 &retlen, (char *)&h0) < 0 ||
0598 nftl_read_oob(mtd,
0599 block * s->EraseSize +
0600 SECTORSIZE + 8, 8,
0601 &retlen, (char *)&h1) < 0) {
0602 s->ReplUnitTable[block] = BLOCK_NIL;
0603 do_format_chain = 1;
0604 break;
0605 }
0606
0607 logical_block = le16_to_cpu ((h0.VirtUnitNum | h0.SpareVirtUnitNum));
0608 rep_block = le16_to_cpu ((h0.ReplUnitNum | h0.SpareReplUnitNum));
0609 erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1));
0610
0611 is_first_block = !(logical_block >> 15);
0612 logical_block = logical_block & 0x7fff;
0613
0614
0615 if (erase_mark != ERASE_MARK || logical_block >= s->nb_blocks) {
0616 if (chain_length == 0) {
0617
0618 if (check_and_mark_free_block(s, block) < 0) {
0619
0620 printk("Formatting block %d\n", block);
0621 if (NFTL_formatblock(s, block) < 0) {
0622
0623 s->ReplUnitTable[block] = BLOCK_RESERVED;
0624 } else {
0625 s->ReplUnitTable[block] = BLOCK_FREE;
0626 }
0627 } else {
0628
0629 s->ReplUnitTable[block] = BLOCK_FREE;
0630 }
0631
0632 goto examine_ReplUnitTable;
0633 } else {
0634
0635
0636 printk("Block %d: free but referenced in chain %d\n",
0637 block, first_block);
0638 s->ReplUnitTable[block] = BLOCK_NIL;
0639 do_format_chain = 1;
0640 break;
0641 }
0642 }
0643
0644
0645 if (chain_length == 0) {
0646
0647
0648
0649 if (!is_first_block)
0650 goto examine_ReplUnitTable;
0651 first_logical_block = logical_block;
0652 } else {
0653 if (logical_block != first_logical_block) {
0654 printk("Block %d: incorrect logical block: %d expected: %d\n",
0655 block, logical_block, first_logical_block);
0656
0657
0658 do_format_chain = 1;
0659 }
0660 if (is_first_block) {
0661
0662
0663
0664 if (get_fold_mark(s, block) != FOLD_MARK_IN_PROGRESS ||
0665 rep_block != 0xffff) {
0666 printk("Block %d: incorrectly marked as first block in chain\n",
0667 block);
0668
0669
0670 do_format_chain = 1;
0671 } else {
0672 printk("Block %d: folding in progress - ignoring first block flag\n",
0673 block);
0674 }
0675 }
0676 }
0677 chain_length++;
0678 if (rep_block == 0xffff) {
0679
0680 s->ReplUnitTable[block] = BLOCK_NIL;
0681 break;
0682 } else if (rep_block >= s->nb_blocks) {
0683 printk("Block %d: referencing invalid block %d\n",
0684 block, rep_block);
0685 do_format_chain = 1;
0686 s->ReplUnitTable[block] = BLOCK_NIL;
0687 break;
0688 } else if (s->ReplUnitTable[rep_block] != BLOCK_NOTEXPLORED) {
0689
0690
0691
0692
0693
0694 if (s->ReplUnitTable[rep_block] == BLOCK_NIL &&
0695 s->EUNtable[first_logical_block] == rep_block &&
0696 get_fold_mark(s, first_block) == FOLD_MARK_IN_PROGRESS) {
0697
0698 printk("Block %d: folding in progress - ignoring first block flag\n",
0699 rep_block);
0700 s->ReplUnitTable[block] = rep_block;
0701 s->EUNtable[first_logical_block] = BLOCK_NIL;
0702 } else {
0703 printk("Block %d: referencing block %d already in another chain\n",
0704 block, rep_block);
0705
0706 do_format_chain = 1;
0707 s->ReplUnitTable[block] = BLOCK_NIL;
0708 }
0709 break;
0710 } else {
0711
0712 s->ReplUnitTable[block] = rep_block;
0713 block = rep_block;
0714 }
0715 }
0716
0717
0718
0719 if (do_format_chain) {
0720
0721 format_chain(s, first_block);
0722 } else {
0723 unsigned int first_block1, chain_to_format, chain_length1;
0724 int fold_mark;
0725
0726
0727 fold_mark = get_fold_mark(s, first_block);
0728 if (fold_mark == 0) {
0729
0730 printk("Could read foldmark at block %d\n", first_block);
0731 format_chain(s, first_block);
0732 } else {
0733 if (fold_mark == FOLD_MARK_IN_PROGRESS)
0734 check_sectors_in_chain(s, first_block);
0735
0736
0737
0738
0739
0740 first_block1 = s->EUNtable[first_logical_block];
0741 if (first_block1 != BLOCK_NIL) {
0742
0743 chain_length1 = calc_chain_length(s, first_block1);
0744 printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n",
0745 first_block1, chain_length1, first_block, chain_length);
0746
0747 if (chain_length >= chain_length1) {
0748 chain_to_format = first_block1;
0749 s->EUNtable[first_logical_block] = first_block;
0750 } else {
0751 chain_to_format = first_block;
0752 }
0753 format_chain(s, chain_to_format);
0754 } else {
0755 s->EUNtable[first_logical_block] = first_block;
0756 }
0757 }
0758 }
0759 }
0760 examine_ReplUnitTable:;
0761 }
0762
0763
0764 s->numfreeEUNs = 0;
0765 s->LastFreeEUN = le16_to_cpu(s->MediaHdr.FirstPhysicalEUN);
0766
0767 for (block = 0; block < s->nb_blocks; block++) {
0768 if (s->ReplUnitTable[block] == BLOCK_NOTEXPLORED) {
0769 printk("Unreferenced block %d, formatting it\n", block);
0770 if (NFTL_formatblock(s, block) < 0)
0771 s->ReplUnitTable[block] = BLOCK_RESERVED;
0772 else
0773 s->ReplUnitTable[block] = BLOCK_FREE;
0774 }
0775 if (s->ReplUnitTable[block] == BLOCK_FREE) {
0776 s->numfreeEUNs++;
0777 s->LastFreeEUN = block;
0778 }
0779 }
0780
0781 return 0;
0782 }