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()
265 inftl->nb_blocks * sizeof(u16)); in find_boot_record()
266 return -ENOMEM; in find_boot_record()
269 inftl->VUtable = kmalloc_array(inftl->nb_blocks, sizeof(u16), in find_boot_record()
271 if (!inftl->VUtable) { in find_boot_record()
272 kfree(inftl->PUtable); in find_boot_record()
275 inftl->nb_blocks * sizeof(u16)); in find_boot_record()
276 return -ENOMEM; in find_boot_record()
280 for (i = 0; i < inftl->nb_boot_blocks; i++) in find_boot_record()
281 inftl->PUtable[i] = BLOCK_RESERVED; in find_boot_record()
283 for (; i < inftl->nb_blocks; i++) in find_boot_record()
284 inftl->PUtable[i] = BLOCK_NOTEXPLORED; in find_boot_record()
286 /* Mark this boot record (NFTL MediaHeader) block as reserved */ in find_boot_record()
287 inftl->PUtable[block] = BLOCK_RESERVED; in find_boot_record()
290 for (i = 0; i < inftl->nb_blocks; i++) { in find_boot_record()
294 for (physblock = 0; physblock < inftl->EraseSize; physblock += inftl->mbd.mtd->erasesize) { in find_boot_record()
295 if (mtd_block_isbad(inftl->mbd.mtd, in find_boot_record()
296 i * inftl->EraseSize + physblock)) in find_boot_record()
297 inftl->PUtable[i] = BLOCK_RESERVED; in find_boot_record()
301 inftl->MediaUnit = block; in find_boot_record()
306 return -1; in find_boot_record()
326 struct mtd_info *mtd = inftl->mbd.mtd; in check_free_sectors()
331 buf = kmalloc(SECTORSIZE + mtd->oobsize, GFP_KERNEL); in check_free_sectors()
333 return -1; in check_free_sectors()
335 ret = -1; in check_free_sectors()
343 if(inftl_read_oob(mtd, address, mtd->oobsize, in check_free_sectors()
346 if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0) in check_free_sectors()
364 * Return: 0 when succeed, -1 on error.
368 int INFTL_formatblock(struct INFTLrecord *inftl, int block) in INFTL_formatblock() argument
372 struct erase_info *instr = &inftl->instr; in INFTL_formatblock()
373 struct mtd_info *mtd = inftl->mbd.mtd; in INFTL_formatblock()
376 pr_debug("INFTL: INFTL_formatblock(inftl=%p,block=%d)\n", inftl, block); in INFTL_formatblock()
384 instr->addr = block * inftl->EraseSize; in INFTL_formatblock()
385 instr->len = inftl->mbd.mtd->erasesize; in INFTL_formatblock()
388 mark only the failed block in the bbt. */ in INFTL_formatblock()
389 for (physblock = 0; physblock < inftl->EraseSize; in INFTL_formatblock()
390 physblock += instr->len, instr->addr += instr->len) { in INFTL_formatblock()
393 ret = mtd_erase(inftl->mbd.mtd, instr); in INFTL_formatblock()
395 printk(KERN_WARNING "INFTL: error while formatting block %d\n", in INFTL_formatblock()
396 block); in INFTL_formatblock()
405 if (check_free_sectors(inftl, instr->addr, instr->len, 1) != 0) in INFTL_formatblock()
415 instr->addr = block * inftl->EraseSize + SECTORSIZE * 2; in INFTL_formatblock()
416 if (inftl_write_oob(mtd, instr->addr + 8, 8, &retlen, (char *)&uci) < 0) in INFTL_formatblock()
420 /* could not format, update the bad block table (caller is responsible in INFTL_formatblock()
422 mtd_block_markbad(inftl->mbd.mtd, instr->addr); in INFTL_formatblock()
423 return -1; in INFTL_formatblock()
436 unsigned int block = first_block, block1; in format_chain() local
438 printk(KERN_WARNING "INFTL: formatting chain at block %d\n", in format_chain()
442 block1 = inftl->PUtable[block]; in format_chain()
444 printk(KERN_WARNING "INFTL: formatting block %d\n", block); in format_chain()
445 if (INFTL_formatblock(inftl, block) < 0) { in format_chain()
449 inftl->PUtable[block] = BLOCK_RESERVED; in format_chain()
451 inftl->PUtable[block] = BLOCK_FREE; in format_chain()
454 /* Goto next block on the chain */ in format_chain()
455 block = block1; in format_chain()
457 if (block == BLOCK_NIL || block >= inftl->lastEUN) in format_chain()
466 pr_debug("-------------------------------------------" in INFTL_dumptables()
467 "----------------------------------\n"); in INFTL_dumptables()
469 pr_debug("VUtable[%d] ->", s->nb_blocks); in INFTL_dumptables()
470 for (i = 0; i < s->nb_blocks; i++) { in INFTL_dumptables()
473 pr_debug("%04x ", s->VUtable[i]); in INFTL_dumptables()
476 pr_debug("\n-------------------------------------------" in INFTL_dumptables()
477 "----------------------------------\n"); in INFTL_dumptables()
479 pr_debug("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks); in INFTL_dumptables()
480 for (i = 0; i <= s->lastEUN; i++) { in INFTL_dumptables()
483 pr_debug("%04x ", s->PUtable[i]); in INFTL_dumptables()
486 pr_debug("\n-------------------------------------------" in INFTL_dumptables()
487 "----------------------------------\n"); in INFTL_dumptables()
489 pr_debug("INFTL ->\n" in INFTL_dumptables()
499 s->EraseSize, s->heads, s->sectors, s->cylinders, in INFTL_dumptables()
500 s->numvunits, s->firstEUN, s->lastEUN, s->numfreeEUNs, in INFTL_dumptables()
501 s->LastFreeEUN, s->nb_blocks, s->nb_boot_blocks); in INFTL_dumptables()
503 pr_debug("\n-------------------------------------------" in INFTL_dumptables()
504 "----------------------------------\n"); in INFTL_dumptables()
509 int logical, block, i; in INFTL_dumpVUchains() local
511 pr_debug("-------------------------------------------" in INFTL_dumpVUchains()
512 "----------------------------------\n"); in INFTL_dumpVUchains()
515 for (logical = 0; logical < s->nb_blocks; logical++) { in INFTL_dumpVUchains()
516 block = s->VUtable[logical]; in INFTL_dumpVUchains()
517 if (block >= s->nb_blocks) in INFTL_dumpVUchains()
519 pr_debug(" LOGICAL %d --> %d ", logical, block); in INFTL_dumpVUchains()
520 for (i = 0; i < s->nb_blocks; i++) { in INFTL_dumpVUchains()
521 if (s->PUtable[block] == BLOCK_NIL) in INFTL_dumpVUchains()
523 block = s->PUtable[block]; in INFTL_dumpVUchains()
524 pr_debug("%d ", block); in INFTL_dumpVUchains()
529 pr_debug("-------------------------------------------" in INFTL_dumpVUchains()
530 "----------------------------------\n"); in INFTL_dumpVUchains()
535 struct mtd_info *mtd = s->mbd.mtd; in INFTL_mount()
536 unsigned int block, first_block, prev_block, last_block; in INFTL_mount() local
550 return -ENXIO; in INFTL_mount()
554 for (i = 0; i < s->nb_blocks; i++) in INFTL_mount()
555 s->VUtable[i] = BLOCK_NIL; in INFTL_mount()
557 logical_block = block = BLOCK_NIL; in INFTL_mount()
560 ANACtable = kcalloc(s->nb_blocks, sizeof(u8), GFP_KERNEL); in INFTL_mount()
564 s->nb_blocks * sizeof(u8)); in INFTL_mount()
565 return -ENOMEM; in INFTL_mount()
571 * Any block that is in any way invalid will be left in the in INFTL_mount()
576 for (first_block = s->firstEUN; first_block <= s->lastEUN; first_block++) { in INFTL_mount()
577 if (s->PUtable[first_block] != BLOCK_NOTEXPLORED) in INFTL_mount()
583 block = first_block; in INFTL_mount()
588 (s->PUtable[block] != BLOCK_NOTEXPLORED)) { in INFTL_mount()
589 /* Nothing to do here, onto next block */ in INFTL_mount()
593 if (inftl_read_oob(mtd, block * s->EraseSize + 8, in INFTL_mount()
595 inftl_read_oob(mtd, block * s->EraseSize + in INFTL_mount()
606 ANACtable[block] = h0.ANAC; in INFTL_mount()
608 /* Previous block is relative to start of Partition */ in INFTL_mount()
609 if (prev_block < s->nb_blocks) in INFTL_mount()
610 prev_block += s->firstEUN; in INFTL_mount()
613 if (s->PUtable[block] != BLOCK_NOTEXPLORED) { in INFTL_mount()
617 s->PUtable[last_block] = block; in INFTL_mount()
622 /* Check for invalid block */ in INFTL_mount()
624 printk(KERN_WARNING "INFTL: corrupt block %d " in INFTL_mount()
626 "mark 0x%x?\n", block, first_block, in INFTL_mount()
640 s->PUtable[block] = BLOCK_FREE; in INFTL_mount()
644 /* Sanity checks on block numbers */ in INFTL_mount()
645 if ((logical_block >= s->nb_blocks) || in INFTL_mount()
646 ((prev_block >= s->nb_blocks) && in INFTL_mount()
650 "block %d in chain %d?\n", in INFTL_mount()
651 block, first_block); in INFTL_mount()
667 * Current block is valid, so if we followed a virtual in INFTL_mount()
669 * block pointer in our PUtable now. Then move onto in INFTL_mount()
670 * the previous block in the chain. in INFTL_mount()
672 s->PUtable[block] = BLOCK_NIL; in INFTL_mount()
674 s->PUtable[last_block] = block; in INFTL_mount()
675 last_block = block; in INFTL_mount()
676 block = prev_block; in INFTL_mount()
679 if (block == BLOCK_NIL) in INFTL_mount()
682 /* Validate next block before following it... */ in INFTL_mount()
683 if (block > s->lastEUN) { in INFTL_mount()
685 "block %d in chain %d?\n", block, in INFTL_mount()
699 * newest block in the chain, but it is the newest we have in INFTL_mount()
703 s->VUtable[first_logical_block] = first_block; in INFTL_mount()
715 for (logical_block = 0; logical_block < s->numvunits; logical_block++) { in INFTL_mount()
716 block = s->VUtable[logical_block]; in INFTL_mount()
720 if (block >= BLOCK_RESERVED) in INFTL_mount()
723 ANAC = ANACtable[block]; in INFTL_mount()
724 for (i = 0; i < s->numvunits; i++) { in INFTL_mount()
725 if (s->PUtable[block] == BLOCK_NIL) in INFTL_mount()
727 if (s->PUtable[block] > s->lastEUN) { in INFTL_mount()
730 s->PUtable[block], logical_block); in INFTL_mount()
731 s->PUtable[block] = BLOCK_NIL; in INFTL_mount()
734 if (ANACtable[block] != ANAC) { in INFTL_mount()
738 * newest block and oldest block. in INFTL_mount()
740 s->VUtable[logical_block] = block; in INFTL_mount()
741 s->PUtable[last_block] = BLOCK_NIL; in INFTL_mount()
745 ANAC--; in INFTL_mount()
746 last_block = block; in INFTL_mount()
747 block = s->PUtable[block]; in INFTL_mount()
750 if (i >= s->nb_blocks) { in INFTL_mount()
763 * Third pass, format unreferenced blocks and init free block count. in INFTL_mount()
765 s->numfreeEUNs = 0; in INFTL_mount()
766 s->LastFreeEUN = BLOCK_NIL; in INFTL_mount()
769 for (block = s->firstEUN; block <= s->lastEUN; block++) { in INFTL_mount()
770 if (s->PUtable[block] == BLOCK_NOTEXPLORED) { in INFTL_mount()
771 printk("INFTL: unreferenced block %d, formatting it\n", in INFTL_mount()
772 block); in INFTL_mount()
773 if (INFTL_formatblock(s, block) < 0) in INFTL_mount()
774 s->PUtable[block] = BLOCK_RESERVED; in INFTL_mount()
776 s->PUtable[block] = BLOCK_FREE; in INFTL_mount()
778 if (s->PUtable[block] == BLOCK_FREE) { in INFTL_mount()
779 s->numfreeEUNs++; in INFTL_mount()
780 if (s->LastFreeEUN == BLOCK_NIL) in INFTL_mount()
781 s->LastFreeEUN = block; in INFTL_mount()