⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nftlcore.c

📁 linux下的MTD设备驱动源代码,配合jffs2 yaffss2文件系统.
💻 C
📖 第 1 页 / 共 2 页
字号:
	   shouldn't actually lose data in this case. It's just that when we load up on a medium which	   has duplicate chains, we need to free one of the chains because it's not necessary any more.	*/	thisEUN = nftl->EUNtable[thisVUC];	DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");	/* For each block in the old chain (except the targetEUN of course), 	   free it and make it available for future use */	while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {		unsigned int EUNtmp;                EUNtmp = nftl->ReplUnitTable[thisEUN];                if (NFTL_formatblock(nftl, thisEUN) < 0) {			/* could not erase : mark block as reserved			 * FixMe: Update Bad Unit Table on disk			 */			nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;                } else {			/* correctly erased : mark it as free */			nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;			nftl->numfreeEUNs++;                }                thisEUN = EUNtmp;	}		/* Make this the new start of chain for thisVUC */	nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;	nftl->EUNtable[thisVUC] = targetEUN;	return targetEUN;}u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock){	/* This is the part that needs some cleverness applied. 	   For now, I'm doing the minimum applicable to actually	   get the thing to work.	   Wear-levelling and other clever stuff needs to be implemented	   and we also need to do some assessment of the results when	   the system loses power half-way through the routine.	*/	u16 LongestChain = 0;	u16 ChainLength = 0, thislen;	u16 chain, EUN;	for (chain = 0; chain < le32_to_cpu(nftl->MediaHdr.FormattedSize) / nftl->EraseSize; chain++) {		EUN = nftl->EUNtable[chain];		thislen = 0;		while (EUN <= nftl->lastEUN) {			thislen++;			//printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);			EUN = nftl->ReplUnitTable[EUN] & 0x7fff;			if (thislen > 0xff00) {				printk("Endless loop in Virtual Chain %d: Unit %x\n",				       chain, EUN);			}			if (thislen > 0xff10) {				/* Actually, don't return failure. Just ignore this chain and				   get on with it. */				thislen = 0;				break;			}		}		if (thislen > ChainLength) {			//printk("New longest chain is %d with length %d\n", chain, thislen);			ChainLength = thislen;			LongestChain = chain;		}	}	if (ChainLength < 2) {		printk(KERN_WARNING "No Virtual Unit Chains available for folding. "		       "Failing request\n");		return 0xffff;	}	return NFTL_foldchain (nftl, LongestChain, pendingblock);}/* NFTL_findwriteunit: Return the unit number into which we can write                        for this block. Make it available if it isn't already*/static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block){	u16 lastEUN;	u16 thisVUC = block / (nftl->EraseSize / 512);	unsigned int writeEUN;	unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);	size_t retlen;	int silly, silly2 = 3;	struct nftl_oob oob;	do {		/* Scan the media to find a unit in the VUC which has		   a free space for the block in question.		*/		/* This condition catches the 0x[7f]fff cases, as well as 		   being a sanity check for past-end-of-media access		*/		lastEUN = BLOCK_NIL;		writeEUN = nftl->EUNtable[thisVUC];                silly = MAX_LOOPS;		while (writeEUN <= nftl->lastEUN) {			struct nftl_bci bci;			size_t retlen;                        unsigned int status;			lastEUN = writeEUN;			MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,				    8, &retlen, (char *)&bci);						DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",			      block , writeEUN, le16_to_cpu(bci.Status));                        status = bci.Status | bci.Status1;			switch(status) {			case SECTOR_FREE:				return writeEUN;			case SECTOR_DELETED:			case SECTOR_USED:			case SECTOR_IGNORE:				break;			default:				// Invalid block. Don't use it any more. Must implement.				break;						}						if (!silly--) { 				printk(KERN_WARNING				       "Infinite loop in Virtual Unit Chain 0x%x\n",				       thisVUC);				return 0xffff;			}			/* Skip to next block in chain */			writeEUN = nftl->ReplUnitTable[writeEUN];		}		/* OK. We didn't find one in the existing chain, or there 		   is no existing chain. */		/* Try to find an already-free block */		writeEUN = NFTL_findfreeblock(nftl, 0);		if (writeEUN == BLOCK_NIL) {			/* That didn't work - there were no free blocks just			   waiting to be picked up. We're going to have to fold			   a chain to make room.			*/			/* First remember the start of this chain */			//u16 startEUN = nftl->EUNtable[thisVUC];						//printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);			writeEUN = NFTL_makefreeblock(nftl, 0xffff);			if (writeEUN == BLOCK_NIL) {				/* OK, we accept that the above comment is 				   lying - there may have been free blocks				   last time we called NFTL_findfreeblock(),				   but they are reserved for when we're				   desperate. Well, now we're desperate.				*/				DEBUG(MTD_DEBUG_LEVEL1, "Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC);				writeEUN = NFTL_findfreeblock(nftl, 1);			}			if (writeEUN == BLOCK_NIL) {				/* Ouch. This should never happen - we should				   always be able to make some room somehow. 				   If we get here, we've allocated more storage 				   space than actual media, or our makefreeblock				   routine is missing something.				*/				printk(KERN_WARNING "Cannot make free space.\n");				return BLOCK_NIL;			}						//printk("Restarting scan\n");			lastEUN = BLOCK_NIL;			continue;		}		/* We've found a free block. Insert it into the chain. */				if (lastEUN != BLOCK_NIL) {                    thisVUC |= 0x8000; /* It's a replacement block */		} else {                    /* The first block in a new chain */                    nftl->EUNtable[thisVUC] = writeEUN;		}		/* set up the actual EUN we're writing into */		/* Both in our cache... */		nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;		/* ... and on the flash itself */		MTD_READOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8,			    &retlen, (char *)&oob.u);		oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);		MTD_WRITEOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8,                             &retlen, (char *)&oob.u);                /* we link the new block to the chain only after the                   block is ready. It avoids the case where the chain                   could point to a free block */                if (lastEUN != BLOCK_NIL) {			/* Both in our cache... */			nftl->ReplUnitTable[lastEUN] = writeEUN;			/* ... and on the flash itself */			MTD_READOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8,				    8, &retlen, (char *)&oob.u);			oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum				= cpu_to_le16(writeEUN);			MTD_WRITEOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8,				     8, &retlen, (char *)&oob.u);		}		return writeEUN;	} while (silly2--);	printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",	       thisVUC);	return 0xffff;}static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,			   char *buffer){	struct NFTLrecord *nftl = (void *)mbd;	u16 writeEUN;	unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);	size_t retlen;	u8 eccbuf[6];	writeEUN = NFTL_findwriteunit(nftl, block);	if (writeEUN == BLOCK_NIL) {		printk(KERN_WARNING		       "NFTL_writeblock(): Cannot find block to write to\n");		/* If we _still_ haven't got a block to use, we're screwed */		return 1;	}	MTD_WRITEECC(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,		     512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP);        /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */	return 0;}#endif /* CONFIG_NFTL_RW */static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,			  char *buffer){	struct NFTLrecord *nftl = (void *)mbd;	u16 lastgoodEUN;	u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];	unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);        unsigned int status;	int silly = MAX_LOOPS;        size_t retlen;        struct nftl_bci bci;	lastgoodEUN = BLOCK_NIL;        if (thisEUN != BLOCK_NIL) {		while (thisEUN < nftl->nb_blocks) {			if (MTD_READOOB(nftl->mbd.mtd, (thisEUN * nftl->EraseSize) + blockofs,					8, &retlen, (char *)&bci) < 0)				status = SECTOR_IGNORE;			else				status = bci.Status | bci.Status1;			switch (status) {			case SECTOR_FREE:				/* no modification of a sector should follow a free sector */				goto the_end;			case SECTOR_DELETED:				lastgoodEUN = BLOCK_NIL;				break;			case SECTOR_USED:				lastgoodEUN = thisEUN;				break;			case SECTOR_IGNORE:				break;			default:				printk("Unknown status for block %ld in EUN %d: %x\n",				       block, thisEUN, status);				break;			}			if (!silly--) {				printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%lx\n",				       block / (nftl->EraseSize / 512));				return 1;			}			thisEUN = nftl->ReplUnitTable[thisEUN];		}        } the_end:	if (lastgoodEUN == BLOCK_NIL) {		/* the requested block is not on the media, return all 0x00 */		memset(buffer, 0, 512);	} else {		loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;		size_t retlen;		u_char eccbuf[6];		if (MTD_READECC(nftl->mbd.mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP))			return -EIO;	}	return 0;}static int nftl_getgeo(struct mtd_blktrans_dev *dev,  struct hd_geometry *geo){	struct NFTLrecord *nftl = (void *)dev;	geo->heads = nftl->heads;	geo->sectors = nftl->sectors;	geo->cylinders = nftl->cylinders;	return 0;}/**************************************************************************** * * Module stuff * ****************************************************************************/struct mtd_blktrans_ops nftl_tr = {	.name		= "nftl",	.major		= NFTL_MAJOR,	.part_bits	= NFTL_PARTN_BITS,	.getgeo		= nftl_getgeo,	.readsect	= nftl_readblock,#ifdef CONFIG_NFTL_RW	.writesect	= nftl_writeblock,#endif	.add_mtd	= nftl_add_mtd,	.remove_dev	= nftl_remove_dev,	.owner		= THIS_MODULE,};extern char nftlmountrev[];int __init init_nftl(void){	printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.94 $, nftlmount.c %s\n", nftlmountrev);	return register_mtd_blktrans(&nftl_tr);}static void __exit cleanup_nftl(void){	deregister_mtd_blktrans(&nftl_tr);}module_init(init_nftl);module_exit(cleanup_nftl);MODULE_LICENSE("GPL");MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -