Linux Audio

Check our new training course

Loading...
v6.8
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Linux driver for NAND Flash Translation Layer
  4 *
  5 * Copyright © 1999 Machine Vision Holdings, Inc.
  6 * Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org>
  7 */
  8
  9#define PRERELEASE
 10
 11#include <linux/kernel.h>
 12#include <linux/module.h>
 13#include <asm/errno.h>
 14#include <asm/io.h>
 15#include <linux/uaccess.h>
 16#include <linux/delay.h>
 17#include <linux/slab.h>
 18#include <linux/init.h>
 19#include <linux/hdreg.h>
 20#include <linux/blkdev.h>
 21
 22#include <linux/kmod.h>
 23#include <linux/mtd/mtd.h>
 24#include <linux/mtd/rawnand.h>
 25#include <linux/mtd/nftl.h>
 26#include <linux/mtd/blktrans.h>
 27
 28/* maximum number of loops while examining next block, to have a
 29   chance to detect consistency problems (they should never happen
 30   because of the checks done in the mounting */
 31
 32#define MAX_LOOPS 10000
 33
 34
 35static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 36{
 37	struct NFTLrecord *nftl;
 38	unsigned long temp;
 39
 40	if (!mtd_type_is_nand(mtd) || mtd->size > UINT_MAX)
 41		return;
 42	/* OK, this is moderately ugly.  But probably safe.  Alternatives? */
 43	if (memcmp(mtd->name, "DiskOnChip", 10))
 44		return;
 45
 46	pr_debug("NFTL: add_mtd for %s\n", mtd->name);
 47
 48	nftl = kzalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
 49
 50	if (!nftl)
 51		return;
 52
 53	nftl->mbd.mtd = mtd;
 54	nftl->mbd.devnum = -1;
 55
 56	nftl->mbd.tr = tr;
 57
 58        if (NFTL_mount(nftl) < 0) {
 59		printk(KERN_WARNING "NFTL: could not mount device\n");
 60		kfree(nftl);
 61		return;
 62        }
 63
 64	/* OK, it's a new one. Set up all the data structures. */
 65
 66	/* Calculate geometry */
 67	nftl->cylinders = 1024;
 68	nftl->heads = 16;
 69
 70	temp = nftl->cylinders * nftl->heads;
 71	nftl->sectors = nftl->mbd.size / temp;
 72	if (nftl->mbd.size % temp) {
 73		nftl->sectors++;
 74		temp = nftl->cylinders * nftl->sectors;
 75		nftl->heads = nftl->mbd.size / temp;
 76
 77		if (nftl->mbd.size % temp) {
 78			nftl->heads++;
 79			temp = nftl->heads * nftl->sectors;
 80			nftl->cylinders = nftl->mbd.size / temp;
 81		}
 82	}
 83
 84	if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) {
 85		/*
 86		  Oh no we don't have
 87		   mbd.size == heads * cylinders * sectors
 88		*/
 89		printk(KERN_WARNING "NFTL: cannot calculate a geometry to "
 90		       "match size of 0x%lx.\n", nftl->mbd.size);
 91		printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d "
 92			"(== 0x%lx sects)\n",
 93			nftl->cylinders, nftl->heads , nftl->sectors,
 94			(long)nftl->cylinders * (long)nftl->heads *
 95			(long)nftl->sectors );
 96	}
 97
 98	if (add_mtd_blktrans_dev(&nftl->mbd)) {
 99		kfree(nftl->ReplUnitTable);
100		kfree(nftl->EUNtable);
101		kfree(nftl);
102		return;
103	}
104#ifdef PSYCHO_DEBUG
105	printk(KERN_INFO "NFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a');
106#endif
107}
108
109static void nftl_remove_dev(struct mtd_blktrans_dev *dev)
110{
111	struct NFTLrecord *nftl = (void *)dev;
112
113	pr_debug("NFTL: remove_dev (i=%d)\n", dev->devnum);
114
115	del_mtd_blktrans_dev(dev);
116	kfree(nftl->ReplUnitTable);
117	kfree(nftl->EUNtable);
118}
119
120/*
121 * Read oob data from flash
122 */
123int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
124		  size_t *retlen, uint8_t *buf)
125{
126	loff_t mask = mtd->writesize - 1;
127	struct mtd_oob_ops ops = { };
128	int res;
129
130	ops.mode = MTD_OPS_PLACE_OOB;
131	ops.ooboffs = offs & mask;
132	ops.ooblen = len;
133	ops.oobbuf = buf;
134	ops.datbuf = NULL;
135
136	res = mtd_read_oob(mtd, offs & ~mask, &ops);
137	*retlen = ops.oobretlen;
138	return res;
139}
140
141/*
142 * Write oob data to flash
143 */
144int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
145		   size_t *retlen, uint8_t *buf)
146{
147	loff_t mask = mtd->writesize - 1;
148	struct mtd_oob_ops ops = { };
149	int res;
150
151	ops.mode = MTD_OPS_PLACE_OOB;
152	ops.ooboffs = offs & mask;
153	ops.ooblen = len;
154	ops.oobbuf = buf;
155	ops.datbuf = NULL;
156
157	res = mtd_write_oob(mtd, offs & ~mask, &ops);
158	*retlen = ops.oobretlen;
159	return res;
160}
161
162#ifdef CONFIG_NFTL_RW
163
164/*
165 * Write data and oob to flash
166 */
167static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
168		      size_t *retlen, uint8_t *buf, uint8_t *oob)
169{
170	loff_t mask = mtd->writesize - 1;
171	struct mtd_oob_ops ops = { };
172	int res;
173
174	ops.mode = MTD_OPS_PLACE_OOB;
175	ops.ooboffs = offs & mask;
176	ops.ooblen = mtd->oobsize;
177	ops.oobbuf = oob;
178	ops.datbuf = buf;
179	ops.len = len;
180
181	res = mtd_write_oob(mtd, offs & ~mask, &ops);
182	*retlen = ops.retlen;
183	return res;
184}
185
186/* Actual NFTL access routines */
187/* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
188 *	when the give Virtual Unit Chain
189 */
190static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
191{
192	/* For a given Virtual Unit Chain: find or create a free block and
193	   add it to the chain */
194	/* We're passed the number of the last EUN in the chain, to save us from
195	   having to look it up again */
196	u16 pot = nftl->LastFreeEUN;
197	int silly = nftl->nb_blocks;
198
199	/* Normally, we force a fold to happen before we run out of free blocks completely */
200	if (!desperate && nftl->numfreeEUNs < 2) {
201		pr_debug("NFTL_findfreeblock: there are too few free EUNs\n");
202		return BLOCK_NIL;
203	}
204
205	/* Scan for a free block */
206	do {
207		if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {
208			nftl->LastFreeEUN = pot;
209			nftl->numfreeEUNs--;
210			return pot;
211		}
212
213		/* This will probably point to the MediaHdr unit itself,
214		   right at the beginning of the partition. But that unit
215		   (and the backup unit too) should have the UCI set
216		   up so that it's not selected for overwriting */
217		if (++pot > nftl->lastEUN)
218			pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN);
219
220		if (!silly--) {
221			printk("Argh! No free blocks found! LastFreeEUN = %d, "
222			       "FirstEUN = %d\n", nftl->LastFreeEUN,
223			       le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
224			return BLOCK_NIL;
225		}
226	} while (pot != nftl->LastFreeEUN);
227
228	return BLOCK_NIL;
229}
230
231static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
232{
233	struct mtd_info *mtd = nftl->mbd.mtd;
234	u16 BlockMap[MAX_SECTORS_PER_UNIT];
235	unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
236	unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
237	unsigned int thisEUN;
238	int block;
239	int silly;
240	unsigned int targetEUN;
241	struct nftl_oob oob;
242	int inplace = 1;
243	size_t retlen;
244
245	memset(BlockMap, 0xff, sizeof(BlockMap));
246	memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
247
248	thisEUN = nftl->EUNtable[thisVUC];
249
250	if (thisEUN == BLOCK_NIL) {
251		printk(KERN_WARNING "Trying to fold non-existent "
252		       "Virtual Unit Chain %d!\n", thisVUC);
253		return BLOCK_NIL;
254	}
255
256	/* Scan to find the Erase Unit which holds the actual data for each
257	   512-byte block within the Chain.
258	*/
259	silly = MAX_LOOPS;
260	targetEUN = BLOCK_NIL;
261	while (thisEUN <= nftl->lastEUN ) {
262		unsigned int status, foldmark;
263
264		targetEUN = thisEUN;
265		for (block = 0; block < nftl->EraseSize / 512; block ++) {
266			nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
267				      (block * 512), 16 , &retlen,
268				      (char *)&oob);
269			if (block == 2) {
270				foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
271				if (foldmark == FOLD_MARK_IN_PROGRESS) {
272					pr_debug("Write Inhibited on EUN %d\n", thisEUN);
273					inplace = 0;
274				} else {
275					/* There's no other reason not to do inplace,
276					   except ones that come later. So we don't need
277					   to preserve inplace */
278					inplace = 1;
279				}
280			}
281			status = oob.b.Status | oob.b.Status1;
282			BlockLastState[block] = status;
283
284			switch(status) {
285			case SECTOR_FREE:
286				BlockFreeFound[block] = 1;
287				break;
288
289			case SECTOR_USED:
290				if (!BlockFreeFound[block])
291					BlockMap[block] = thisEUN;
292				else
293					printk(KERN_WARNING
294					       "SECTOR_USED found after SECTOR_FREE "
295					       "in Virtual Unit Chain %d for block %d\n",
296					       thisVUC, block);
297				break;
298			case SECTOR_DELETED:
299				if (!BlockFreeFound[block])
300					BlockMap[block] = BLOCK_NIL;
301				else
302					printk(KERN_WARNING
303					       "SECTOR_DELETED found after SECTOR_FREE "
304					       "in Virtual Unit Chain %d for block %d\n",
305					       thisVUC, block);
306				break;
307
308			case SECTOR_IGNORE:
309				break;
310			default:
311				printk("Unknown status for block %d in EUN %d: %x\n",
312				       block, thisEUN, status);
313			}
314		}
315
316		if (!silly--) {
317			printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
318			       thisVUC);
319			return BLOCK_NIL;
320		}
321
322		thisEUN = nftl->ReplUnitTable[thisEUN];
323	}
324
325	if (inplace) {
326		/* We're being asked to be a fold-in-place. Check
327		   that all blocks which actually have data associated
328		   with them (i.e. BlockMap[block] != BLOCK_NIL) are
329		   either already present or SECTOR_FREE in the target
330		   block. If not, we're going to have to fold out-of-place
331		   anyway.
332		*/
333		for (block = 0; block < nftl->EraseSize / 512 ; block++) {
334			if (BlockLastState[block] != SECTOR_FREE &&
335			    BlockMap[block] != BLOCK_NIL &&
336			    BlockMap[block] != targetEUN) {
337				pr_debug("Setting inplace to 0. VUC %d, "
338				      "block %d was %x lastEUN, "
339				      "and is in EUN %d (%s) %d\n",
340				      thisVUC, block, BlockLastState[block],
341				      BlockMap[block],
342				      BlockMap[block]== targetEUN ? "==" : "!=",
343				      targetEUN);
344				inplace = 0;
345				break;
346			}
347		}
348
349		if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) &&
350		    pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&
351		    BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=
352		    SECTOR_FREE) {
353			pr_debug("Pending write not free in EUN %d. "
354			      "Folding out of place.\n", targetEUN);
355			inplace = 0;
356		}
357	}
358
359	if (!inplace) {
360		pr_debug("Cannot fold Virtual Unit Chain %d in place. "
361		      "Trying out-of-place\n", thisVUC);
362		/* We need to find a targetEUN to fold into. */
363		targetEUN = NFTL_findfreeblock(nftl, 1);
364		if (targetEUN == BLOCK_NIL) {
365			/* Ouch. Now we're screwed. We need to do a
366			   fold-in-place of another chain to make room
367			   for this one. We need a better way of selecting
368			   which chain to fold, because makefreeblock will
369			   only ask us to fold the same one again.
370			*/
371			printk(KERN_WARNING
372			       "NFTL_findfreeblock(desperate) returns 0xffff.\n");
373			return BLOCK_NIL;
374		}
375	} else {
376		/* We put a fold mark in the chain we are folding only if we
377               fold in place to help the mount check code. If we do not fold in
378               place, it is possible to find the valid chain by selecting the
379               longer one */
380		oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
381		oob.u.c.unused = 0xffffffff;
382		nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
383			       8, &retlen, (char *)&oob.u);
384	}
385
386	/* OK. We now know the location of every block in the Virtual Unit Chain,
387	   and the Erase Unit into which we are supposed to be copying.
388	   Go for it.
389	*/
390	pr_debug("Folding chain %d into unit %d\n", thisVUC, targetEUN);
391	for (block = 0; block < nftl->EraseSize / 512 ; block++) {
392		unsigned char movebuf[512];
393		int ret;
394
395		/* If it's in the target EUN already, or if it's pending write, do nothing */
396		if (BlockMap[block] == targetEUN ||
397		    (pendingblock == (thisVUC * (nftl->EraseSize / 512) + block))) {
398			continue;
399		}
400
401		/* copy only in non free block (free blocks can only
402                   happen in case of media errors or deleted blocks) */
403		if (BlockMap[block] == BLOCK_NIL)
404			continue;
405
406		ret = mtd_read(mtd,
407			       (nftl->EraseSize * BlockMap[block]) + (block * 512),
408			       512,
409			       &retlen,
410			       movebuf);
411		if (ret < 0 && !mtd_is_bitflip(ret)) {
412			ret = mtd_read(mtd,
413				       (nftl->EraseSize * BlockMap[block]) + (block * 512),
414				       512,
415				       &retlen,
416				       movebuf);
417			if (ret != -EIO)
418				printk("Error went away on retry.\n");
419		}
420		memset(&oob, 0xff, sizeof(struct nftl_oob));
421		oob.b.Status = oob.b.Status1 = SECTOR_USED;
422
423		nftl_write(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) +
424			   (block * 512), 512, &retlen, movebuf, (char *)&oob);
425	}
426
427	/* add the header so that it is now a valid chain */
428	oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
429	oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = BLOCK_NIL;
430
431	nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 8,
432		       8, &retlen, (char *)&oob.u);
433
434	/* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
435
436	/* At this point, we have two different chains for this Virtual Unit, and no way to tell
437	   them apart. If we crash now, we get confused. However, both contain the same data, so we
438	   shouldn't actually lose data in this case. It's just that when we load up on a medium which
439	   has duplicate chains, we need to free one of the chains because it's not necessary any more.
440	*/
441	thisEUN = nftl->EUNtable[thisVUC];
442	pr_debug("Want to erase\n");
443
444	/* For each block in the old chain (except the targetEUN of course),
445	   free it and make it available for future use */
446	while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
447		unsigned int EUNtmp;
448
449		EUNtmp = nftl->ReplUnitTable[thisEUN];
450
451		if (NFTL_formatblock(nftl, thisEUN) < 0) {
452			/* could not erase : mark block as reserved
453			 */
454			nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
455		} else {
456			/* correctly erased : mark it as free */
457			nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
458			nftl->numfreeEUNs++;
459		}
460		thisEUN = EUNtmp;
461	}
462
463	/* Make this the new start of chain for thisVUC */
464	nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
465	nftl->EUNtable[thisVUC] = targetEUN;
466
467	return targetEUN;
468}
469
470static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
471{
472	/* This is the part that needs some cleverness applied.
473	   For now, I'm doing the minimum applicable to actually
474	   get the thing to work.
475	   Wear-levelling and other clever stuff needs to be implemented
476	   and we also need to do some assessment of the results when
477	   the system loses power half-way through the routine.
478	*/
479	u16 LongestChain = 0;
480	u16 ChainLength = 0, thislen;
481	u16 chain, EUN;
482
483	for (chain = 0; chain < le32_to_cpu(nftl->MediaHdr.FormattedSize) / nftl->EraseSize; chain++) {
484		EUN = nftl->EUNtable[chain];
485		thislen = 0;
486
487		while (EUN <= nftl->lastEUN) {
488			thislen++;
489			//printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
490			EUN = nftl->ReplUnitTable[EUN] & 0x7fff;
491			if (thislen > 0xff00) {
492				printk("Endless loop in Virtual Chain %d: Unit %x\n",
493				       chain, EUN);
494			}
495			if (thislen > 0xff10) {
496				/* Actually, don't return failure. Just ignore this chain and
497				   get on with it. */
498				thislen = 0;
499				break;
500			}
501		}
502
503		if (thislen > ChainLength) {
504			//printk("New longest chain is %d with length %d\n", chain, thislen);
505			ChainLength = thislen;
506			LongestChain = chain;
507		}
508	}
509
510	if (ChainLength < 2) {
511		printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
512		       "Failing request\n");
513		return BLOCK_NIL;
514	}
515
516	return NFTL_foldchain (nftl, LongestChain, pendingblock);
517}
518
519/* NFTL_findwriteunit: Return the unit number into which we can write
520                       for this block. Make it available if it isn't already
521*/
522static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
523{
524	u16 lastEUN;
525	u16 thisVUC = block / (nftl->EraseSize / 512);
526	struct mtd_info *mtd = nftl->mbd.mtd;
527	unsigned int writeEUN;
528	unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
529	size_t retlen;
530	int silly, silly2 = 3;
531	struct nftl_oob oob;
532
533	do {
534		/* Scan the media to find a unit in the VUC which has
535		   a free space for the block in question.
536		*/
537
538		/* This condition catches the 0x[7f]fff cases, as well as
539		   being a sanity check for past-end-of-media access
540		*/
541		lastEUN = BLOCK_NIL;
542		writeEUN = nftl->EUNtable[thisVUC];
543		silly = MAX_LOOPS;
544		while (writeEUN <= nftl->lastEUN) {
545			struct nftl_bci bci;
546			size_t retlen;
547			unsigned int status;
548
549			lastEUN = writeEUN;
550
551			nftl_read_oob(mtd,
552				      (writeEUN * nftl->EraseSize) + blockofs,
553				      8, &retlen, (char *)&bci);
554
555			pr_debug("Status of block %d in EUN %d is %x\n",
556			      block , writeEUN, le16_to_cpu(bci.Status));
557
558			status = bci.Status | bci.Status1;
559			switch(status) {
560			case SECTOR_FREE:
561				return writeEUN;
562
563			case SECTOR_DELETED:
564			case SECTOR_USED:
565			case SECTOR_IGNORE:
566				break;
567			default:
568				// Invalid block. Don't use it any more. Must implement.
569				break;
570			}
571
572			if (!silly--) {
573				printk(KERN_WARNING
574				       "Infinite loop in Virtual Unit Chain 0x%x\n",
575				       thisVUC);
576				return BLOCK_NIL;
577			}
578
579			/* Skip to next block in chain */
580			writeEUN = nftl->ReplUnitTable[writeEUN];
581		}
582
583		/* OK. We didn't find one in the existing chain, or there
584		   is no existing chain. */
585
586		/* Try to find an already-free block */
587		writeEUN = NFTL_findfreeblock(nftl, 0);
588
589		if (writeEUN == BLOCK_NIL) {
590			/* That didn't work - there were no free blocks just
591			   waiting to be picked up. We're going to have to fold
592			   a chain to make room.
593			*/
594
595			/* First remember the start of this chain */
596			//u16 startEUN = nftl->EUNtable[thisVUC];
597
598			//printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
599			writeEUN = NFTL_makefreeblock(nftl, BLOCK_NIL);
600
601			if (writeEUN == BLOCK_NIL) {
602				/* OK, we accept that the above comment is
603				   lying - there may have been free blocks
604				   last time we called NFTL_findfreeblock(),
605				   but they are reserved for when we're
606				   desperate. Well, now we're desperate.
607				*/
608				pr_debug("Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC);
609				writeEUN = NFTL_findfreeblock(nftl, 1);
610			}
611			if (writeEUN == BLOCK_NIL) {
612				/* Ouch. This should never happen - we should
613				   always be able to make some room somehow.
614				   If we get here, we've allocated more storage
615				   space than actual media, or our makefreeblock
616				   routine is missing something.
617				*/
618				printk(KERN_WARNING "Cannot make free space.\n");
619				return BLOCK_NIL;
620			}
621			//printk("Restarting scan\n");
622			continue;
623		}
624
625		/* We've found a free block. Insert it into the chain. */
626
627		if (lastEUN != BLOCK_NIL) {
628			thisVUC |= 0x8000; /* It's a replacement block */
629		} else {
630			/* The first block in a new chain */
631			nftl->EUNtable[thisVUC] = writeEUN;
632		}
633
634		/* set up the actual EUN we're writing into */
635		/* Both in our cache... */
636		nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
637
638		/* ... and on the flash itself */
639		nftl_read_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
640			      &retlen, (char *)&oob.u);
641
642		oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
643
644		nftl_write_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
645			       &retlen, (char *)&oob.u);
646
647		/* we link the new block to the chain only after the
648                   block is ready. It avoids the case where the chain
649                   could point to a free block */
650		if (lastEUN != BLOCK_NIL) {
651			/* Both in our cache... */
652			nftl->ReplUnitTable[lastEUN] = writeEUN;
653			/* ... and on the flash itself */
654			nftl_read_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
655				      8, &retlen, (char *)&oob.u);
656
657			oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
658				= cpu_to_le16(writeEUN);
659
660			nftl_write_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
661				       8, &retlen, (char *)&oob.u);
662		}
663
664		return writeEUN;
665
666	} while (silly2--);
667
668	printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
669	       thisVUC);
670	return BLOCK_NIL;
671}
672
673static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
674			   char *buffer)
675{
676	struct NFTLrecord *nftl = (void *)mbd;
677	u16 writeEUN;
678	unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
679	size_t retlen;
680	struct nftl_oob oob;
681
682	writeEUN = NFTL_findwriteunit(nftl, block);
683
684	if (writeEUN == BLOCK_NIL) {
685		printk(KERN_WARNING
686		       "NFTL_writeblock(): Cannot find block to write to\n");
687		/* If we _still_ haven't got a block to use, we're screwed */
688		return 1;
689	}
690
691	memset(&oob, 0xff, sizeof(struct nftl_oob));
692	oob.b.Status = oob.b.Status1 = SECTOR_USED;
693
694	nftl_write(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
695		   512, &retlen, (char *)buffer, (char *)&oob);
696	return 0;
697}
698#endif /* CONFIG_NFTL_RW */
699
700static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
701			  char *buffer)
702{
703	struct NFTLrecord *nftl = (void *)mbd;
704	struct mtd_info *mtd = nftl->mbd.mtd;
705	u16 lastgoodEUN;
706	u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
707	unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
708	unsigned int status;
709	int silly = MAX_LOOPS;
710	size_t retlen;
711	struct nftl_bci bci;
712
713	lastgoodEUN = BLOCK_NIL;
714
715	if (thisEUN != BLOCK_NIL) {
716		while (thisEUN < nftl->nb_blocks) {
717			if (nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
718					  blockofs, 8, &retlen,
719					  (char *)&bci) < 0)
720				status = SECTOR_IGNORE;
721			else
722				status = bci.Status | bci.Status1;
723
724			switch (status) {
725			case SECTOR_FREE:
726				/* no modification of a sector should follow a free sector */
727				goto the_end;
728			case SECTOR_DELETED:
729				lastgoodEUN = BLOCK_NIL;
730				break;
731			case SECTOR_USED:
732				lastgoodEUN = thisEUN;
733				break;
734			case SECTOR_IGNORE:
735				break;
736			default:
737				printk("Unknown status for block %ld in EUN %d: %x\n",
738				       block, thisEUN, status);
739				break;
740			}
741
742			if (!silly--) {
743				printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%lx\n",
744				       block / (nftl->EraseSize / 512));
745				return 1;
746			}
747			thisEUN = nftl->ReplUnitTable[thisEUN];
748		}
749	}
750
751 the_end:
752	if (lastgoodEUN == BLOCK_NIL) {
753		/* the requested block is not on the media, return all 0x00 */
754		memset(buffer, 0, 512);
755	} else {
756		loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
757		size_t retlen;
758		int res = mtd_read(mtd, ptr, 512, &retlen, buffer);
759
760		if (res < 0 && !mtd_is_bitflip(res))
761			return -EIO;
762	}
763	return 0;
764}
765
766static int nftl_getgeo(struct mtd_blktrans_dev *dev,  struct hd_geometry *geo)
767{
768	struct NFTLrecord *nftl = (void *)dev;
769
770	geo->heads = nftl->heads;
771	geo->sectors = nftl->sectors;
772	geo->cylinders = nftl->cylinders;
773
774	return 0;
775}
776
777/****************************************************************************
778 *
779 * Module stuff
780 *
781 ****************************************************************************/
782
783
784static struct mtd_blktrans_ops nftl_tr = {
785	.name		= "nftl",
786	.major		= NFTL_MAJOR,
787	.part_bits	= NFTL_PARTN_BITS,
788	.blksize 	= 512,
789	.getgeo		= nftl_getgeo,
790	.readsect	= nftl_readblock,
791#ifdef CONFIG_NFTL_RW
792	.writesect	= nftl_writeblock,
793#endif
794	.add_mtd	= nftl_add_mtd,
795	.remove_dev	= nftl_remove_dev,
796	.owner		= THIS_MODULE,
797};
798
799module_mtd_blktrans(nftl_tr);
800
801MODULE_LICENSE("GPL");
802MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
803MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium");
804MODULE_ALIAS_BLOCKDEV_MAJOR(NFTL_MAJOR);
v6.2
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Linux driver for NAND Flash Translation Layer
  4 *
  5 * Copyright © 1999 Machine Vision Holdings, Inc.
  6 * Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org>
  7 */
  8
  9#define PRERELEASE
 10
 11#include <linux/kernel.h>
 12#include <linux/module.h>
 13#include <asm/errno.h>
 14#include <asm/io.h>
 15#include <linux/uaccess.h>
 16#include <linux/delay.h>
 17#include <linux/slab.h>
 18#include <linux/init.h>
 19#include <linux/hdreg.h>
 20#include <linux/blkdev.h>
 21
 22#include <linux/kmod.h>
 23#include <linux/mtd/mtd.h>
 24#include <linux/mtd/rawnand.h>
 25#include <linux/mtd/nftl.h>
 26#include <linux/mtd/blktrans.h>
 27
 28/* maximum number of loops while examining next block, to have a
 29   chance to detect consistency problems (they should never happen
 30   because of the checks done in the mounting */
 31
 32#define MAX_LOOPS 10000
 33
 34
 35static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 36{
 37	struct NFTLrecord *nftl;
 38	unsigned long temp;
 39
 40	if (!mtd_type_is_nand(mtd) || mtd->size > UINT_MAX)
 41		return;
 42	/* OK, this is moderately ugly.  But probably safe.  Alternatives? */
 43	if (memcmp(mtd->name, "DiskOnChip", 10))
 44		return;
 45
 46	pr_debug("NFTL: add_mtd for %s\n", mtd->name);
 47
 48	nftl = kzalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
 49
 50	if (!nftl)
 51		return;
 52
 53	nftl->mbd.mtd = mtd;
 54	nftl->mbd.devnum = -1;
 55
 56	nftl->mbd.tr = tr;
 57
 58        if (NFTL_mount(nftl) < 0) {
 59		printk(KERN_WARNING "NFTL: could not mount device\n");
 60		kfree(nftl);
 61		return;
 62        }
 63
 64	/* OK, it's a new one. Set up all the data structures. */
 65
 66	/* Calculate geometry */
 67	nftl->cylinders = 1024;
 68	nftl->heads = 16;
 69
 70	temp = nftl->cylinders * nftl->heads;
 71	nftl->sectors = nftl->mbd.size / temp;
 72	if (nftl->mbd.size % temp) {
 73		nftl->sectors++;
 74		temp = nftl->cylinders * nftl->sectors;
 75		nftl->heads = nftl->mbd.size / temp;
 76
 77		if (nftl->mbd.size % temp) {
 78			nftl->heads++;
 79			temp = nftl->heads * nftl->sectors;
 80			nftl->cylinders = nftl->mbd.size / temp;
 81		}
 82	}
 83
 84	if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) {
 85		/*
 86		  Oh no we don't have
 87		   mbd.size == heads * cylinders * sectors
 88		*/
 89		printk(KERN_WARNING "NFTL: cannot calculate a geometry to "
 90		       "match size of 0x%lx.\n", nftl->mbd.size);
 91		printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d "
 92			"(== 0x%lx sects)\n",
 93			nftl->cylinders, nftl->heads , nftl->sectors,
 94			(long)nftl->cylinders * (long)nftl->heads *
 95			(long)nftl->sectors );
 96	}
 97
 98	if (add_mtd_blktrans_dev(&nftl->mbd)) {
 99		kfree(nftl->ReplUnitTable);
100		kfree(nftl->EUNtable);
101		kfree(nftl);
102		return;
103	}
104#ifdef PSYCHO_DEBUG
105	printk(KERN_INFO "NFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a');
106#endif
107}
108
109static void nftl_remove_dev(struct mtd_blktrans_dev *dev)
110{
111	struct NFTLrecord *nftl = (void *)dev;
112
113	pr_debug("NFTL: remove_dev (i=%d)\n", dev->devnum);
114
115	del_mtd_blktrans_dev(dev);
116	kfree(nftl->ReplUnitTable);
117	kfree(nftl->EUNtable);
118}
119
120/*
121 * Read oob data from flash
122 */
123int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
124		  size_t *retlen, uint8_t *buf)
125{
126	loff_t mask = mtd->writesize - 1;
127	struct mtd_oob_ops ops = { };
128	int res;
129
130	ops.mode = MTD_OPS_PLACE_OOB;
131	ops.ooboffs = offs & mask;
132	ops.ooblen = len;
133	ops.oobbuf = buf;
134	ops.datbuf = NULL;
135
136	res = mtd_read_oob(mtd, offs & ~mask, &ops);
137	*retlen = ops.oobretlen;
138	return res;
139}
140
141/*
142 * Write oob data to flash
143 */
144int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
145		   size_t *retlen, uint8_t *buf)
146{
147	loff_t mask = mtd->writesize - 1;
148	struct mtd_oob_ops ops = { };
149	int res;
150
151	ops.mode = MTD_OPS_PLACE_OOB;
152	ops.ooboffs = offs & mask;
153	ops.ooblen = len;
154	ops.oobbuf = buf;
155	ops.datbuf = NULL;
156
157	res = mtd_write_oob(mtd, offs & ~mask, &ops);
158	*retlen = ops.oobretlen;
159	return res;
160}
161
162#ifdef CONFIG_NFTL_RW
163
164/*
165 * Write data and oob to flash
166 */
167static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
168		      size_t *retlen, uint8_t *buf, uint8_t *oob)
169{
170	loff_t mask = mtd->writesize - 1;
171	struct mtd_oob_ops ops = { };
172	int res;
173
174	ops.mode = MTD_OPS_PLACE_OOB;
175	ops.ooboffs = offs & mask;
176	ops.ooblen = mtd->oobsize;
177	ops.oobbuf = oob;
178	ops.datbuf = buf;
179	ops.len = len;
180
181	res = mtd_write_oob(mtd, offs & ~mask, &ops);
182	*retlen = ops.retlen;
183	return res;
184}
185
186/* Actual NFTL access routines */
187/* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
188 *	when the give Virtual Unit Chain
189 */
190static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
191{
192	/* For a given Virtual Unit Chain: find or create a free block and
193	   add it to the chain */
194	/* We're passed the number of the last EUN in the chain, to save us from
195	   having to look it up again */
196	u16 pot = nftl->LastFreeEUN;
197	int silly = nftl->nb_blocks;
198
199	/* Normally, we force a fold to happen before we run out of free blocks completely */
200	if (!desperate && nftl->numfreeEUNs < 2) {
201		pr_debug("NFTL_findfreeblock: there are too few free EUNs\n");
202		return BLOCK_NIL;
203	}
204
205	/* Scan for a free block */
206	do {
207		if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {
208			nftl->LastFreeEUN = pot;
209			nftl->numfreeEUNs--;
210			return pot;
211		}
212
213		/* This will probably point to the MediaHdr unit itself,
214		   right at the beginning of the partition. But that unit
215		   (and the backup unit too) should have the UCI set
216		   up so that it's not selected for overwriting */
217		if (++pot > nftl->lastEUN)
218			pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN);
219
220		if (!silly--) {
221			printk("Argh! No free blocks found! LastFreeEUN = %d, "
222			       "FirstEUN = %d\n", nftl->LastFreeEUN,
223			       le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
224			return BLOCK_NIL;
225		}
226	} while (pot != nftl->LastFreeEUN);
227
228	return BLOCK_NIL;
229}
230
231static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
232{
233	struct mtd_info *mtd = nftl->mbd.mtd;
234	u16 BlockMap[MAX_SECTORS_PER_UNIT];
235	unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
236	unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
237	unsigned int thisEUN;
238	int block;
239	int silly;
240	unsigned int targetEUN;
241	struct nftl_oob oob;
242	int inplace = 1;
243	size_t retlen;
244
245	memset(BlockMap, 0xff, sizeof(BlockMap));
246	memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
247
248	thisEUN = nftl->EUNtable[thisVUC];
249
250	if (thisEUN == BLOCK_NIL) {
251		printk(KERN_WARNING "Trying to fold non-existent "
252		       "Virtual Unit Chain %d!\n", thisVUC);
253		return BLOCK_NIL;
254	}
255
256	/* Scan to find the Erase Unit which holds the actual data for each
257	   512-byte block within the Chain.
258	*/
259	silly = MAX_LOOPS;
260	targetEUN = BLOCK_NIL;
261	while (thisEUN <= nftl->lastEUN ) {
262		unsigned int status, foldmark;
263
264		targetEUN = thisEUN;
265		for (block = 0; block < nftl->EraseSize / 512; block ++) {
266			nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
267				      (block * 512), 16 , &retlen,
268				      (char *)&oob);
269			if (block == 2) {
270				foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
271				if (foldmark == FOLD_MARK_IN_PROGRESS) {
272					pr_debug("Write Inhibited on EUN %d\n", thisEUN);
273					inplace = 0;
274				} else {
275					/* There's no other reason not to do inplace,
276					   except ones that come later. So we don't need
277					   to preserve inplace */
278					inplace = 1;
279				}
280			}
281			status = oob.b.Status | oob.b.Status1;
282			BlockLastState[block] = status;
283
284			switch(status) {
285			case SECTOR_FREE:
286				BlockFreeFound[block] = 1;
287				break;
288
289			case SECTOR_USED:
290				if (!BlockFreeFound[block])
291					BlockMap[block] = thisEUN;
292				else
293					printk(KERN_WARNING
294					       "SECTOR_USED found after SECTOR_FREE "
295					       "in Virtual Unit Chain %d for block %d\n",
296					       thisVUC, block);
297				break;
298			case SECTOR_DELETED:
299				if (!BlockFreeFound[block])
300					BlockMap[block] = BLOCK_NIL;
301				else
302					printk(KERN_WARNING
303					       "SECTOR_DELETED found after SECTOR_FREE "
304					       "in Virtual Unit Chain %d for block %d\n",
305					       thisVUC, block);
306				break;
307
308			case SECTOR_IGNORE:
309				break;
310			default:
311				printk("Unknown status for block %d in EUN %d: %x\n",
312				       block, thisEUN, status);
313			}
314		}
315
316		if (!silly--) {
317			printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
318			       thisVUC);
319			return BLOCK_NIL;
320		}
321
322		thisEUN = nftl->ReplUnitTable[thisEUN];
323	}
324
325	if (inplace) {
326		/* We're being asked to be a fold-in-place. Check
327		   that all blocks which actually have data associated
328		   with them (i.e. BlockMap[block] != BLOCK_NIL) are
329		   either already present or SECTOR_FREE in the target
330		   block. If not, we're going to have to fold out-of-place
331		   anyway.
332		*/
333		for (block = 0; block < nftl->EraseSize / 512 ; block++) {
334			if (BlockLastState[block] != SECTOR_FREE &&
335			    BlockMap[block] != BLOCK_NIL &&
336			    BlockMap[block] != targetEUN) {
337				pr_debug("Setting inplace to 0. VUC %d, "
338				      "block %d was %x lastEUN, "
339				      "and is in EUN %d (%s) %d\n",
340				      thisVUC, block, BlockLastState[block],
341				      BlockMap[block],
342				      BlockMap[block]== targetEUN ? "==" : "!=",
343				      targetEUN);
344				inplace = 0;
345				break;
346			}
347		}
348
349		if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) &&
350		    pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&
351		    BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=
352		    SECTOR_FREE) {
353			pr_debug("Pending write not free in EUN %d. "
354			      "Folding out of place.\n", targetEUN);
355			inplace = 0;
356		}
357	}
358
359	if (!inplace) {
360		pr_debug("Cannot fold Virtual Unit Chain %d in place. "
361		      "Trying out-of-place\n", thisVUC);
362		/* We need to find a targetEUN to fold into. */
363		targetEUN = NFTL_findfreeblock(nftl, 1);
364		if (targetEUN == BLOCK_NIL) {
365			/* Ouch. Now we're screwed. We need to do a
366			   fold-in-place of another chain to make room
367			   for this one. We need a better way of selecting
368			   which chain to fold, because makefreeblock will
369			   only ask us to fold the same one again.
370			*/
371			printk(KERN_WARNING
372			       "NFTL_findfreeblock(desperate) returns 0xffff.\n");
373			return BLOCK_NIL;
374		}
375	} else {
376		/* We put a fold mark in the chain we are folding only if we
377               fold in place to help the mount check code. If we do not fold in
378               place, it is possible to find the valid chain by selecting the
379               longer one */
380		oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
381		oob.u.c.unused = 0xffffffff;
382		nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
383			       8, &retlen, (char *)&oob.u);
384	}
385
386	/* OK. We now know the location of every block in the Virtual Unit Chain,
387	   and the Erase Unit into which we are supposed to be copying.
388	   Go for it.
389	*/
390	pr_debug("Folding chain %d into unit %d\n", thisVUC, targetEUN);
391	for (block = 0; block < nftl->EraseSize / 512 ; block++) {
392		unsigned char movebuf[512];
393		int ret;
394
395		/* If it's in the target EUN already, or if it's pending write, do nothing */
396		if (BlockMap[block] == targetEUN ||
397		    (pendingblock == (thisVUC * (nftl->EraseSize / 512) + block))) {
398			continue;
399		}
400
401		/* copy only in non free block (free blocks can only
402                   happen in case of media errors or deleted blocks) */
403		if (BlockMap[block] == BLOCK_NIL)
404			continue;
405
406		ret = mtd_read(mtd,
407			       (nftl->EraseSize * BlockMap[block]) + (block * 512),
408			       512,
409			       &retlen,
410			       movebuf);
411		if (ret < 0 && !mtd_is_bitflip(ret)) {
412			ret = mtd_read(mtd,
413				       (nftl->EraseSize * BlockMap[block]) + (block * 512),
414				       512,
415				       &retlen,
416				       movebuf);
417			if (ret != -EIO)
418				printk("Error went away on retry.\n");
419		}
420		memset(&oob, 0xff, sizeof(struct nftl_oob));
421		oob.b.Status = oob.b.Status1 = SECTOR_USED;
422
423		nftl_write(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) +
424			   (block * 512), 512, &retlen, movebuf, (char *)&oob);
425	}
426
427	/* add the header so that it is now a valid chain */
428	oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
429	oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = BLOCK_NIL;
430
431	nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 8,
432		       8, &retlen, (char *)&oob.u);
433
434	/* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
435
436	/* At this point, we have two different chains for this Virtual Unit, and no way to tell
437	   them apart. If we crash now, we get confused. However, both contain the same data, so we
438	   shouldn't actually lose data in this case. It's just that when we load up on a medium which
439	   has duplicate chains, we need to free one of the chains because it's not necessary any more.
440	*/
441	thisEUN = nftl->EUNtable[thisVUC];
442	pr_debug("Want to erase\n");
443
444	/* For each block in the old chain (except the targetEUN of course),
445	   free it and make it available for future use */
446	while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
447		unsigned int EUNtmp;
448
449		EUNtmp = nftl->ReplUnitTable[thisEUN];
450
451		if (NFTL_formatblock(nftl, thisEUN) < 0) {
452			/* could not erase : mark block as reserved
453			 */
454			nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
455		} else {
456			/* correctly erased : mark it as free */
457			nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
458			nftl->numfreeEUNs++;
459		}
460		thisEUN = EUNtmp;
461	}
462
463	/* Make this the new start of chain for thisVUC */
464	nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
465	nftl->EUNtable[thisVUC] = targetEUN;
466
467	return targetEUN;
468}
469
470static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
471{
472	/* This is the part that needs some cleverness applied.
473	   For now, I'm doing the minimum applicable to actually
474	   get the thing to work.
475	   Wear-levelling and other clever stuff needs to be implemented
476	   and we also need to do some assessment of the results when
477	   the system loses power half-way through the routine.
478	*/
479	u16 LongestChain = 0;
480	u16 ChainLength = 0, thislen;
481	u16 chain, EUN;
482
483	for (chain = 0; chain < le32_to_cpu(nftl->MediaHdr.FormattedSize) / nftl->EraseSize; chain++) {
484		EUN = nftl->EUNtable[chain];
485		thislen = 0;
486
487		while (EUN <= nftl->lastEUN) {
488			thislen++;
489			//printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
490			EUN = nftl->ReplUnitTable[EUN] & 0x7fff;
491			if (thislen > 0xff00) {
492				printk("Endless loop in Virtual Chain %d: Unit %x\n",
493				       chain, EUN);
494			}
495			if (thislen > 0xff10) {
496				/* Actually, don't return failure. Just ignore this chain and
497				   get on with it. */
498				thislen = 0;
499				break;
500			}
501		}
502
503		if (thislen > ChainLength) {
504			//printk("New longest chain is %d with length %d\n", chain, thislen);
505			ChainLength = thislen;
506			LongestChain = chain;
507		}
508	}
509
510	if (ChainLength < 2) {
511		printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
512		       "Failing request\n");
513		return BLOCK_NIL;
514	}
515
516	return NFTL_foldchain (nftl, LongestChain, pendingblock);
517}
518
519/* NFTL_findwriteunit: Return the unit number into which we can write
520                       for this block. Make it available if it isn't already
521*/
522static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
523{
524	u16 lastEUN;
525	u16 thisVUC = block / (nftl->EraseSize / 512);
526	struct mtd_info *mtd = nftl->mbd.mtd;
527	unsigned int writeEUN;
528	unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
529	size_t retlen;
530	int silly, silly2 = 3;
531	struct nftl_oob oob;
532
533	do {
534		/* Scan the media to find a unit in the VUC which has
535		   a free space for the block in question.
536		*/
537
538		/* This condition catches the 0x[7f]fff cases, as well as
539		   being a sanity check for past-end-of-media access
540		*/
541		lastEUN = BLOCK_NIL;
542		writeEUN = nftl->EUNtable[thisVUC];
543		silly = MAX_LOOPS;
544		while (writeEUN <= nftl->lastEUN) {
545			struct nftl_bci bci;
546			size_t retlen;
547			unsigned int status;
548
549			lastEUN = writeEUN;
550
551			nftl_read_oob(mtd,
552				      (writeEUN * nftl->EraseSize) + blockofs,
553				      8, &retlen, (char *)&bci);
554
555			pr_debug("Status of block %d in EUN %d is %x\n",
556			      block , writeEUN, le16_to_cpu(bci.Status));
557
558			status = bci.Status | bci.Status1;
559			switch(status) {
560			case SECTOR_FREE:
561				return writeEUN;
562
563			case SECTOR_DELETED:
564			case SECTOR_USED:
565			case SECTOR_IGNORE:
566				break;
567			default:
568				// Invalid block. Don't use it any more. Must implement.
569				break;
570			}
571
572			if (!silly--) {
573				printk(KERN_WARNING
574				       "Infinite loop in Virtual Unit Chain 0x%x\n",
575				       thisVUC);
576				return BLOCK_NIL;
577			}
578
579			/* Skip to next block in chain */
580			writeEUN = nftl->ReplUnitTable[writeEUN];
581		}
582
583		/* OK. We didn't find one in the existing chain, or there
584		   is no existing chain. */
585
586		/* Try to find an already-free block */
587		writeEUN = NFTL_findfreeblock(nftl, 0);
588
589		if (writeEUN == BLOCK_NIL) {
590			/* That didn't work - there were no free blocks just
591			   waiting to be picked up. We're going to have to fold
592			   a chain to make room.
593			*/
594
595			/* First remember the start of this chain */
596			//u16 startEUN = nftl->EUNtable[thisVUC];
597
598			//printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
599			writeEUN = NFTL_makefreeblock(nftl, BLOCK_NIL);
600
601			if (writeEUN == BLOCK_NIL) {
602				/* OK, we accept that the above comment is
603				   lying - there may have been free blocks
604				   last time we called NFTL_findfreeblock(),
605				   but they are reserved for when we're
606				   desperate. Well, now we're desperate.
607				*/
608				pr_debug("Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC);
609				writeEUN = NFTL_findfreeblock(nftl, 1);
610			}
611			if (writeEUN == BLOCK_NIL) {
612				/* Ouch. This should never happen - we should
613				   always be able to make some room somehow.
614				   If we get here, we've allocated more storage
615				   space than actual media, or our makefreeblock
616				   routine is missing something.
617				*/
618				printk(KERN_WARNING "Cannot make free space.\n");
619				return BLOCK_NIL;
620			}
621			//printk("Restarting scan\n");
622			continue;
623		}
624
625		/* We've found a free block. Insert it into the chain. */
626
627		if (lastEUN != BLOCK_NIL) {
628			thisVUC |= 0x8000; /* It's a replacement block */
629		} else {
630			/* The first block in a new chain */
631			nftl->EUNtable[thisVUC] = writeEUN;
632		}
633
634		/* set up the actual EUN we're writing into */
635		/* Both in our cache... */
636		nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
637
638		/* ... and on the flash itself */
639		nftl_read_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
640			      &retlen, (char *)&oob.u);
641
642		oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
643
644		nftl_write_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
645			       &retlen, (char *)&oob.u);
646
647		/* we link the new block to the chain only after the
648                   block is ready. It avoids the case where the chain
649                   could point to a free block */
650		if (lastEUN != BLOCK_NIL) {
651			/* Both in our cache... */
652			nftl->ReplUnitTable[lastEUN] = writeEUN;
653			/* ... and on the flash itself */
654			nftl_read_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
655				      8, &retlen, (char *)&oob.u);
656
657			oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
658				= cpu_to_le16(writeEUN);
659
660			nftl_write_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
661				       8, &retlen, (char *)&oob.u);
662		}
663
664		return writeEUN;
665
666	} while (silly2--);
667
668	printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
669	       thisVUC);
670	return BLOCK_NIL;
671}
672
673static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
674			   char *buffer)
675{
676	struct NFTLrecord *nftl = (void *)mbd;
677	u16 writeEUN;
678	unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
679	size_t retlen;
680	struct nftl_oob oob;
681
682	writeEUN = NFTL_findwriteunit(nftl, block);
683
684	if (writeEUN == BLOCK_NIL) {
685		printk(KERN_WARNING
686		       "NFTL_writeblock(): Cannot find block to write to\n");
687		/* If we _still_ haven't got a block to use, we're screwed */
688		return 1;
689	}
690
691	memset(&oob, 0xff, sizeof(struct nftl_oob));
692	oob.b.Status = oob.b.Status1 = SECTOR_USED;
693
694	nftl_write(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
695		   512, &retlen, (char *)buffer, (char *)&oob);
696	return 0;
697}
698#endif /* CONFIG_NFTL_RW */
699
700static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
701			  char *buffer)
702{
703	struct NFTLrecord *nftl = (void *)mbd;
704	struct mtd_info *mtd = nftl->mbd.mtd;
705	u16 lastgoodEUN;
706	u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
707	unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
708	unsigned int status;
709	int silly = MAX_LOOPS;
710	size_t retlen;
711	struct nftl_bci bci;
712
713	lastgoodEUN = BLOCK_NIL;
714
715	if (thisEUN != BLOCK_NIL) {
716		while (thisEUN < nftl->nb_blocks) {
717			if (nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
718					  blockofs, 8, &retlen,
719					  (char *)&bci) < 0)
720				status = SECTOR_IGNORE;
721			else
722				status = bci.Status | bci.Status1;
723
724			switch (status) {
725			case SECTOR_FREE:
726				/* no modification of a sector should follow a free sector */
727				goto the_end;
728			case SECTOR_DELETED:
729				lastgoodEUN = BLOCK_NIL;
730				break;
731			case SECTOR_USED:
732				lastgoodEUN = thisEUN;
733				break;
734			case SECTOR_IGNORE:
735				break;
736			default:
737				printk("Unknown status for block %ld in EUN %d: %x\n",
738				       block, thisEUN, status);
739				break;
740			}
741
742			if (!silly--) {
743				printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%lx\n",
744				       block / (nftl->EraseSize / 512));
745				return 1;
746			}
747			thisEUN = nftl->ReplUnitTable[thisEUN];
748		}
749	}
750
751 the_end:
752	if (lastgoodEUN == BLOCK_NIL) {
753		/* the requested block is not on the media, return all 0x00 */
754		memset(buffer, 0, 512);
755	} else {
756		loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
757		size_t retlen;
758		int res = mtd_read(mtd, ptr, 512, &retlen, buffer);
759
760		if (res < 0 && !mtd_is_bitflip(res))
761			return -EIO;
762	}
763	return 0;
764}
765
766static int nftl_getgeo(struct mtd_blktrans_dev *dev,  struct hd_geometry *geo)
767{
768	struct NFTLrecord *nftl = (void *)dev;
769
770	geo->heads = nftl->heads;
771	geo->sectors = nftl->sectors;
772	geo->cylinders = nftl->cylinders;
773
774	return 0;
775}
776
777/****************************************************************************
778 *
779 * Module stuff
780 *
781 ****************************************************************************/
782
783
784static struct mtd_blktrans_ops nftl_tr = {
785	.name		= "nftl",
786	.major		= NFTL_MAJOR,
787	.part_bits	= NFTL_PARTN_BITS,
788	.blksize 	= 512,
789	.getgeo		= nftl_getgeo,
790	.readsect	= nftl_readblock,
791#ifdef CONFIG_NFTL_RW
792	.writesect	= nftl_writeblock,
793#endif
794	.add_mtd	= nftl_add_mtd,
795	.remove_dev	= nftl_remove_dev,
796	.owner		= THIS_MODULE,
797};
798
799module_mtd_blktrans(nftl_tr);
800
801MODULE_LICENSE("GPL");
802MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
803MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium");
804MODULE_ALIAS_BLOCKDEV_MAJOR(NFTL_MAJOR);