Lines Matching +full:nand +full:- +full:oob +full:- +full:sector +full:- +full:size
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)
34 //struct inftl_oob oob; in find_boot_record()
37 struct INFTLMediaHeader *mh = &inftl->MediaHdr; in find_boot_record()
38 struct mtd_info *mtd = inftl->mbd.mtd; in find_boot_record()
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()
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()
89 block * inftl->EraseSize + SECTORSIZE + 8, in find_boot_record()
93 "0x%x in mtd%d, but OOB data read failed " 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()
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()
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()
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()
313 * check_free_sector: check if a free sector is actually FREE,
314 * i.e. All 0xff in data and oob area.
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.
365 struct erase_info *instr = &inftl->instr; in INFTL_formatblock()
366 struct mtd_info *mtd = inftl->mbd.mtd; in INFTL_formatblock()
377 instr->addr = block * inftl->EraseSize; in INFTL_formatblock()
378 instr->len = inftl->mbd.mtd->erasesize; in INFTL_formatblock()
379 /* Erase one physical eraseblock at a time, even though the NAND api 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()
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()
415 mtd_block_markbad(inftl->mbd.mtd, instr->addr); in INFTL_formatblock()
416 return -1; in INFTL_formatblock()
435 block1 = inftl->PUtable[block]; in format_chain()
442 inftl->PUtable[block] = BLOCK_RESERVED; in format_chain()
444 inftl->PUtable[block] = BLOCK_FREE; 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()
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()
522 pr_debug("-------------------------------------------" in INFTL_dumpVUchains()
523 "----------------------------------\n"); in INFTL_dumpVUchains()
528 struct mtd_info *mtd = s->mbd.mtd; in INFTL_mount()
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()
553 ANACtable = kcalloc(s->nb_blocks, sizeof(u8), GFP_KERNEL); in INFTL_mount()
555 return -ENOMEM; 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()
577 (s->PUtable[block] != BLOCK_NOTEXPLORED)) { 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()
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()
629 s->PUtable[block] = BLOCK_FREE; in INFTL_mount()
634 if ((logical_block >= s->nb_blocks) || in INFTL_mount()
635 ((prev_block >= s->nb_blocks) && in INFTL_mount()
661 s->PUtable[block] = BLOCK_NIL; in INFTL_mount()
663 s->PUtable[last_block] = block; in INFTL_mount()
672 if (block > s->lastEUN) { 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()
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()
729 s->VUtable[logical_block] = block; in INFTL_mount()
730 s->PUtable[last_block] = BLOCK_NIL; in INFTL_mount()
734 ANAC--; in INFTL_mount()
736 block = s->PUtable[block]; in INFTL_mount()
739 if (i >= s->nb_blocks) { 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()
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()