Lines Matching +full:ip +full:- +full:block

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * inftlmount.c -- INFTL mount code with extensive checks.
6 * Copyright © 2002-2003, Greg Ungerer (gerg@snapgear.com)
35 unsigned int i, block; in find_boot_record() local
37 struct INFTLMediaHeader *mh = &inftl->MediaHdr; in find_boot_record()
38 struct mtd_info *mtd = inftl->mbd.mtd; in find_boot_record()
39 struct INFTLPartition *ip; in find_boot_record() local
49 inftl->EraseSize = inftl->mbd.mtd->erasesize; in find_boot_record()
50 inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize; in find_boot_record()
52 inftl->MediaUnit = BLOCK_NIL; in find_boot_record()
55 for (block = 0; block < inftl->nb_blocks; block++) { in find_boot_record()
62 ret = mtd_read(mtd, block * inftl->EraseSize, SECTORSIZE, in find_boot_record()
70 printk(KERN_WARNING "INFTL: block read at 0x%x " in find_boot_record()
72 block * inftl->EraseSize, in find_boot_record()
73 inftl->mbd.mtd->index, ret); in find_boot_record()
74 if (!--warncount) in find_boot_record()
76 "failures for this block will " in find_boot_record()
89 block * inftl->EraseSize + SECTORSIZE + 8, in find_boot_record()
94 "(err %d)\n", block * inftl->EraseSize, in find_boot_record()
95 inftl->mbd.mtd->index, ret); in find_boot_record()
107 mtd_read(mtd, block * inftl->EraseSize + 4096, SECTORSIZE, in find_boot_record()
112 return -1; in find_boot_record()
118 return -1; in find_boot_record()
121 mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks); in find_boot_record()
122 mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions); in find_boot_record()
123 mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions); in find_boot_record()
124 mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits); in find_boot_record()
125 mh->FormatFlags = le32_to_cpu(mh->FormatFlags); in find_boot_record()
126 mh->PercentUsed = le32_to_cpu(mh->PercentUsed); in find_boot_record()
128 pr_debug("INFTL: Media Header ->\n" in find_boot_record()
137 mh->bootRecordID, mh->NoOfBootImageBlocks, in find_boot_record()
138 mh->NoOfBinaryPartitions, in find_boot_record()
139 mh->NoOfBDTLPartitions, in find_boot_record()
140 mh->BlockMultiplierBits, mh->FormatFlags, in find_boot_record()
141 mh->OsakVersion, mh->PercentUsed); in find_boot_record()
143 if (mh->NoOfBDTLPartitions == 0) { in find_boot_record()
146 "must be at least 1\n", mh->NoOfBDTLPartitions); in find_boot_record()
147 return -1; in find_boot_record()
150 if ((mh->NoOfBDTLPartitions + mh->NoOfBinaryPartitions) > 4) { in find_boot_record()
153 "BDTL=%d Binary=%d\n", mh->NoOfBDTLPartitions + in find_boot_record()
154 mh->NoOfBinaryPartitions, in find_boot_record()
155 mh->NoOfBDTLPartitions, in find_boot_record()
156 mh->NoOfBinaryPartitions); in find_boot_record()
157 return -1; in find_boot_record()
160 if (mh->BlockMultiplierBits > 1) { in find_boot_record()
163 mh->BlockMultiplierBits); in find_boot_record()
164 return -1; in find_boot_record()
165 } else if (mh->BlockMultiplierBits == 1) { in find_boot_record()
168 mh->BlockMultiplierBits); in find_boot_record()
169 inftl->EraseSize = inftl->mbd.mtd->erasesize << in find_boot_record()
170 mh->BlockMultiplierBits; in find_boot_record()
171 inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize; in find_boot_record()
172 block >>= mh->BlockMultiplierBits; in find_boot_record()
177 ip = &mh->Partitions[i]; in find_boot_record()
178 ip->virtualUnits = le32_to_cpu(ip->virtualUnits); in find_boot_record()
179 ip->firstUnit = le32_to_cpu(ip->firstUnit); in find_boot_record()
180 ip->lastUnit = le32_to_cpu(ip->lastUnit); in find_boot_record()
181 ip->flags = le32_to_cpu(ip->flags); in find_boot_record()
182 ip->spareUnits = le32_to_cpu(ip->spareUnits); in find_boot_record()
183 ip->Reserved0 = le32_to_cpu(ip->Reserved0); in find_boot_record()
185 pr_debug(" PARTITION[%d] ->\n" in find_boot_record()
191 i, ip->virtualUnits, ip->firstUnit, in find_boot_record()
192 ip->lastUnit, ip->flags, in find_boot_record()
193 ip->spareUnits); in find_boot_record()
195 if (ip->Reserved0 != ip->firstUnit) { in find_boot_record()
196 struct erase_info *instr = &inftl->instr; in find_boot_record()
202 * to erase the hidden block for full in find_boot_record()
205 instr->addr = ip->Reserved0 * inftl->EraseSize; in find_boot_record()
206 instr->len = inftl->EraseSize; in find_boot_record()
209 if ((ip->lastUnit - ip->firstUnit + 1) < ip->virtualUnits) { in find_boot_record()
213 "virtualUnits %d\n", i, ip->lastUnit, in find_boot_record()
214 ip->firstUnit, ip->Reserved0); in find_boot_record()
215 return -1; in find_boot_record()
217 if (ip->Reserved1 != 0) { in find_boot_record()
221 i, ip->Reserved1); in find_boot_record()
222 return -1; in find_boot_record()
225 if (ip->flags & INFTL_BDTL) in find_boot_record()
233 return -1; in find_boot_record()
236 inftl->nb_boot_blocks = ip->firstUnit; in find_boot_record()
237 inftl->numvunits = ip->virtualUnits; in find_boot_record()
238 if (inftl->numvunits > (inftl->nb_blocks - in find_boot_record()
239 inftl->nb_boot_blocks - 2)) { in find_boot_record()
242 "(%d) - nb_boot_blocks(%d) - 2\n", in find_boot_record()
243 inftl->numvunits, inftl->nb_blocks, in find_boot_record()
244 inftl->nb_boot_blocks); in find_boot_record()
245 return -1; in find_boot_record()
248 inftl->mbd.size = inftl->numvunits * in find_boot_record()
249 (inftl->EraseSize / SECTORSIZE); in find_boot_record()
252 * Block count is set to last used EUN (we won't need to keep in find_boot_record()
253 * any meta-data past that point). in find_boot_record()
255 inftl->firstEUN = ip->firstUnit; in find_boot_record()
256 inftl->lastEUN = ip->lastUnit; in find_boot_record()
257 inftl->nb_blocks = ip->lastUnit + 1; in find_boot_record()
260 inftl->PUtable = kmalloc_array(inftl->nb_blocks, sizeof(u16), in find_boot_record()
262 if (!inftl->PUtable) in find_boot_record()
263 return -ENOMEM; in find_boot_record()
265 inftl->VUtable = kmalloc_array(inftl->nb_blocks, sizeof(u16), in find_boot_record()
267 if (!inftl->VUtable) { in find_boot_record()
268 kfree(inftl->PUtable); in find_boot_record()
269 return -ENOMEM; in find_boot_record()
273 for (i = 0; i < inftl->nb_boot_blocks; i++) in find_boot_record()
274 inftl->PUtable[i] = BLOCK_RESERVED; in find_boot_record()
276 for (; i < inftl->nb_blocks; i++) in find_boot_record()
277 inftl->PUtable[i] = BLOCK_NOTEXPLORED; in find_boot_record()
279 /* Mark this boot record (NFTL MediaHeader) block as reserved */ in find_boot_record()
280 inftl->PUtable[block] = BLOCK_RESERVED; in find_boot_record()
283 for (i = 0; i < inftl->nb_blocks; i++) { in find_boot_record()
287 for (physblock = 0; physblock < inftl->EraseSize; physblock += inftl->mbd.mtd->erasesize) { in find_boot_record()
288 if (mtd_block_isbad(inftl->mbd.mtd, in find_boot_record()
289 i * inftl->EraseSize + physblock)) in find_boot_record()
290 inftl->PUtable[i] = BLOCK_RESERVED; in find_boot_record()
294 inftl->MediaUnit = block; in find_boot_record()
299 return -1; in find_boot_record()
319 struct mtd_info *mtd = inftl->mbd.mtd; in check_free_sectors()
324 buf = kmalloc(SECTORSIZE + mtd->oobsize, GFP_KERNEL); in check_free_sectors()
326 return -ENOMEM; in check_free_sectors()
328 ret = -1; in check_free_sectors()
336 if(inftl_read_oob(mtd, address, mtd->oobsize, in check_free_sectors()
339 if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0) in check_free_sectors()
357 * Return: 0 when succeed, -1 on error.
361 int INFTL_formatblock(struct INFTLrecord *inftl, int block) in INFTL_formatblock() argument
365 struct erase_info *instr = &inftl->instr; in INFTL_formatblock()
366 struct mtd_info *mtd = inftl->mbd.mtd; in INFTL_formatblock()
369 pr_debug("INFTL: INFTL_formatblock(inftl=%p,block=%d)\n", inftl, block); in INFTL_formatblock()
377 instr->addr = block * inftl->EraseSize; in INFTL_formatblock()
378 instr->len = inftl->mbd.mtd->erasesize; in INFTL_formatblock()
381 mark only the failed block in the bbt. */ in INFTL_formatblock()
382 for (physblock = 0; physblock < inftl->EraseSize; in INFTL_formatblock()
383 physblock += instr->len, instr->addr += instr->len) { in INFTL_formatblock()
386 ret = mtd_erase(inftl->mbd.mtd, instr); in INFTL_formatblock()
388 printk(KERN_WARNING "INFTL: error while formatting block %d\n", in INFTL_formatblock()
389 block); in INFTL_formatblock()
398 if (check_free_sectors(inftl, instr->addr, instr->len, 1) != 0) in INFTL_formatblock()
408 instr->addr = block * inftl->EraseSize + SECTORSIZE * 2; in INFTL_formatblock()
409 if (inftl_write_oob(mtd, instr->addr + 8, 8, &retlen, (char *)&uci) < 0) in INFTL_formatblock()
413 /* could not format, update the bad block table (caller is responsible in INFTL_formatblock()
415 mtd_block_markbad(inftl->mbd.mtd, instr->addr); in INFTL_formatblock()
416 return -1; in INFTL_formatblock()
429 unsigned int block = first_block, block1; in format_chain() local
431 printk(KERN_WARNING "INFTL: formatting chain at block %d\n", in format_chain()
435 block1 = inftl->PUtable[block]; in format_chain()
437 printk(KERN_WARNING "INFTL: formatting block %d\n", block); in format_chain()
438 if (INFTL_formatblock(inftl, block) < 0) { in format_chain()
442 inftl->PUtable[block] = BLOCK_RESERVED; in format_chain()
444 inftl->PUtable[block] = BLOCK_FREE; in format_chain()
447 /* Goto next block on the chain */ in format_chain()
448 block = block1; in format_chain()
450 if (block == BLOCK_NIL || block >= inftl->lastEUN) in format_chain()
459 pr_debug("-------------------------------------------" in INFTL_dumptables()
460 "----------------------------------\n"); in INFTL_dumptables()
462 pr_debug("VUtable[%d] ->", s->nb_blocks); in INFTL_dumptables()
463 for (i = 0; i < s->nb_blocks; i++) { in INFTL_dumptables()
466 pr_debug("%04x ", s->VUtable[i]); in INFTL_dumptables()
469 pr_debug("\n-------------------------------------------" in INFTL_dumptables()
470 "----------------------------------\n"); in INFTL_dumptables()
472 pr_debug("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks); in INFTL_dumptables()
473 for (i = 0; i <= s->lastEUN; i++) { in INFTL_dumptables()
476 pr_debug("%04x ", s->PUtable[i]); in INFTL_dumptables()
479 pr_debug("\n-------------------------------------------" in INFTL_dumptables()
480 "----------------------------------\n"); in INFTL_dumptables()
482 pr_debug("INFTL ->\n" in INFTL_dumptables()
492 s->EraseSize, s->heads, s->sectors, s->cylinders, in INFTL_dumptables()
493 s->numvunits, s->firstEUN, s->lastEUN, s->numfreeEUNs, in INFTL_dumptables()
494 s->LastFreeEUN, s->nb_blocks, s->nb_boot_blocks); in INFTL_dumptables()
496 pr_debug("\n-------------------------------------------" in INFTL_dumptables()
497 "----------------------------------\n"); in INFTL_dumptables()
502 int logical, block, i; in INFTL_dumpVUchains() local
504 pr_debug("-------------------------------------------" in INFTL_dumpVUchains()
505 "----------------------------------\n"); in INFTL_dumpVUchains()
508 for (logical = 0; logical < s->nb_blocks; logical++) { in INFTL_dumpVUchains()
509 block = s->VUtable[logical]; in INFTL_dumpVUchains()
510 if (block >= s->nb_blocks) in INFTL_dumpVUchains()
512 pr_debug(" LOGICAL %d --> %d ", logical, block); in INFTL_dumpVUchains()
513 for (i = 0; i < s->nb_blocks; i++) { in INFTL_dumpVUchains()
514 if (s->PUtable[block] == BLOCK_NIL) in INFTL_dumpVUchains()
516 block = s->PUtable[block]; in INFTL_dumpVUchains()
517 pr_debug("%d ", block); in INFTL_dumpVUchains()
522 pr_debug("-------------------------------------------" in INFTL_dumpVUchains()
523 "----------------------------------\n"); in INFTL_dumpVUchains()
528 struct mtd_info *mtd = s->mbd.mtd; in INFTL_mount()
529 unsigned int block, first_block, prev_block, last_block; in INFTL_mount() local
543 return -ENXIO; in INFTL_mount()
547 for (i = 0; i < s->nb_blocks; i++) in INFTL_mount()
548 s->VUtable[i] = BLOCK_NIL; in INFTL_mount()
550 logical_block = block = BLOCK_NIL; in INFTL_mount()
553 ANACtable = kcalloc(s->nb_blocks, sizeof(u8), GFP_KERNEL); in INFTL_mount()
555 return -ENOMEM; in INFTL_mount()
560 * Any block that is in any way invalid will be left in the in INFTL_mount()
565 for (first_block = s->firstEUN; first_block <= s->lastEUN; first_block++) { in INFTL_mount()
566 if (s->PUtable[first_block] != BLOCK_NOTEXPLORED) in INFTL_mount()
572 block = first_block; in INFTL_mount()
577 (s->PUtable[block] != BLOCK_NOTEXPLORED)) { in INFTL_mount()
578 /* Nothing to do here, onto next block */ in INFTL_mount()
582 if (inftl_read_oob(mtd, block * s->EraseSize + 8, in INFTL_mount()
584 inftl_read_oob(mtd, block * s->EraseSize + in INFTL_mount()
595 ANACtable[block] = h0.ANAC; in INFTL_mount()
597 /* Previous block is relative to start of Partition */ in INFTL_mount()
598 if (prev_block < s->nb_blocks) in INFTL_mount()
599 prev_block += s->firstEUN; in INFTL_mount()
602 if (s->PUtable[block] != BLOCK_NOTEXPLORED) { in INFTL_mount()
606 s->PUtable[last_block] = block; in INFTL_mount()
611 /* Check for invalid block */ in INFTL_mount()
613 printk(KERN_WARNING "INFTL: corrupt block %d " in INFTL_mount()
615 "mark 0x%x?\n", block, first_block, in INFTL_mount()
629 s->PUtable[block] = BLOCK_FREE; in INFTL_mount()
633 /* Sanity checks on block numbers */ in INFTL_mount()
634 if ((logical_block >= s->nb_blocks) || in INFTL_mount()
635 ((prev_block >= s->nb_blocks) && in INFTL_mount()
639 "block %d in chain %d?\n", in INFTL_mount()
640 block, first_block); in INFTL_mount()
656 * Current block is valid, so if we followed a virtual in INFTL_mount()
658 * block pointer in our PUtable now. Then move onto in INFTL_mount()
659 * the previous block in the chain. in INFTL_mount()
661 s->PUtable[block] = BLOCK_NIL; in INFTL_mount()
663 s->PUtable[last_block] = block; in INFTL_mount()
664 last_block = block; in INFTL_mount()
665 block = prev_block; in INFTL_mount()
668 if (block == BLOCK_NIL) in INFTL_mount()
671 /* Validate next block before following it... */ in INFTL_mount()
672 if (block > s->lastEUN) { in INFTL_mount()
674 "block %d in chain %d?\n", block, in INFTL_mount()
688 * newest block in the chain, but it is the newest we have in INFTL_mount()
692 s->VUtable[first_logical_block] = first_block; in INFTL_mount()
704 for (logical_block = 0; logical_block < s->numvunits; logical_block++) { in INFTL_mount()
705 block = s->VUtable[logical_block]; in INFTL_mount()
709 if (block >= BLOCK_RESERVED) in INFTL_mount()
712 ANAC = ANACtable[block]; in INFTL_mount()
713 for (i = 0; i < s->numvunits; i++) { in INFTL_mount()
714 if (s->PUtable[block] == BLOCK_NIL) in INFTL_mount()
716 if (s->PUtable[block] > s->lastEUN) { in INFTL_mount()
719 s->PUtable[block], logical_block); in INFTL_mount()
720 s->PUtable[block] = BLOCK_NIL; in INFTL_mount()
723 if (ANACtable[block] != ANAC) { in INFTL_mount()
727 * newest block and oldest block. in INFTL_mount()
729 s->VUtable[logical_block] = block; in INFTL_mount()
730 s->PUtable[last_block] = BLOCK_NIL; in INFTL_mount()
734 ANAC--; in INFTL_mount()
735 last_block = block; in INFTL_mount()
736 block = s->PUtable[block]; in INFTL_mount()
739 if (i >= s->nb_blocks) { in INFTL_mount()
752 * Third pass, format unreferenced blocks and init free block count. in INFTL_mount()
754 s->numfreeEUNs = 0; in INFTL_mount()
755 s->LastFreeEUN = BLOCK_NIL; in INFTL_mount()
758 for (block = s->firstEUN; block <= s->lastEUN; block++) { in INFTL_mount()
759 if (s->PUtable[block] == BLOCK_NOTEXPLORED) { in INFTL_mount()
760 printk("INFTL: unreferenced block %d, formatting it\n", in INFTL_mount()
761 block); in INFTL_mount()
762 if (INFTL_formatblock(s, block) < 0) in INFTL_mount()
763 s->PUtable[block] = BLOCK_RESERVED; in INFTL_mount()
765 s->PUtable[block] = BLOCK_FREE; in INFTL_mount()
767 if (s->PUtable[block] == BLOCK_FREE) { in INFTL_mount()
768 s->numfreeEUNs++; in INFTL_mount()
769 if (s->LastFreeEUN == BLOCK_NIL) in INFTL_mount()
770 s->LastFreeEUN = block; in INFTL_mount()