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

📄 inftlcore.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=%p,"		"block=%d)\n", inftl, block);	do {		/*		 * Scan the media to find a unit in the VUC which has		 * a free space for the block in question.		 */		writeEUN = BLOCK_NIL;		thisEUN = inftl->VUtable[thisVUC];		silly = MAX_LOOPS;		while (thisEUN <= inftl->lastEUN) {			inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +				       blockofs, 8, &retlen, (char *)&bci);			status = bci.Status | bci.Status1;			DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in "				"EUN %d is %x\n", block , writeEUN, status);			switch(status) {			case SECTOR_FREE:				writeEUN = thisEUN;				break;			case SECTOR_DELETED:			case SECTOR_USED:				/* Can't go any further */				goto hitused;			case SECTOR_IGNORE:				break;			default:				/*				 * Invalid block. Don't use it any more.				 * Must implement.				 */				break;			}			if (!silly--) {				printk(KERN_WARNING "INFTL: infinite loop in "					"Virtual Unit Chain 0x%x\n", thisVUC);				return 0xffff;			}			/* Skip to next block in chain */			thisEUN = inftl->PUtable[thisEUN];		}hitused:		if (writeEUN != BLOCK_NIL)			return writeEUN;		/*		 * OK. We didn't find one in the existing chain, or there		 * is no existing chain. Allocate a new one.		 */		writeEUN = INFTL_findfreeblock(inftl, 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.			 */			thisEUN = INFTL_makefreeblock(inftl, 0xffff);			/*			 * Hopefully we free something, lets try again.			 * This time we are desperate...			 */			DEBUG(MTD_DEBUG_LEVEL1, "INFTL: using desperate==1 "				"to find free EUN to accommodate write to "				"VUC %d\n", thisVUC);			writeEUN = INFTL_findfreeblock(inftl, 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 "INFTL: cannot make free "					"space.\n");#ifdef DEBUG				INFTL_dumptables(inftl);				INFTL_dumpVUchains(inftl);#endif				return BLOCK_NIL;			}		}		/*		 * Insert new block into virtual chain. Firstly update the		 * block headers in flash...		 */		anac = 0;		nacs = 0;		thisEUN = inftl->VUtable[thisVUC];		if (thisEUN != BLOCK_NIL) {			inftl_read_oob(mtd, thisEUN * inftl->EraseSize				       + 8, 8, &retlen, (char *)&oob.u);			anac = oob.u.a.ANAC + 1;			nacs = oob.u.a.NACs + 1;		}		prev_block = inftl->VUtable[thisVUC];		if (prev_block < inftl->nb_blocks)			prev_block -= inftl->firstEUN;		parity = (nrbits(thisVUC, 16) & 0x1) ? 0x1 : 0;		parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0;		parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0;		parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0;		oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC);		oob.u.a.prevUnitNo = cpu_to_le16(prev_block);		oob.u.a.ANAC = anac;		oob.u.a.NACs = nacs;		oob.u.a.parityPerField = parity;		oob.u.a.discarded = 0xaa;		inftl_write_oob(mtd, writeEUN * inftl->EraseSize + 8, 8,				&retlen, (char *)&oob.u);		/* Also back up header... */		oob.u.b.virtualUnitNo = cpu_to_le16(thisVUC);		oob.u.b.prevUnitNo = cpu_to_le16(prev_block);		oob.u.b.ANAC = anac;		oob.u.b.NACs = nacs;		oob.u.b.parityPerField = parity;		oob.u.b.discarded = 0xaa;		inftl_write_oob(mtd, writeEUN * inftl->EraseSize +				SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);		inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC];		inftl->VUtable[thisVUC] = writeEUN;		inftl->numfreeEUNs--;		return writeEUN;	} while (silly2--);	printk(KERN_WARNING "INFTL: error folding to make room for Virtual "		"Unit Chain 0x%x\n", thisVUC);	return 0xffff;}/* * Given a Virtual Unit Chain, see if it can be deleted, and if so do it. */static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC){	struct mtd_info *mtd = inftl->mbd.mtd;	unsigned char BlockUsed[MAX_SECTORS_PER_UNIT];	unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];	unsigned int thisEUN, status;	int block, silly;	struct inftl_bci bci;	size_t retlen;	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=%p,"		"thisVUC=%d)\n", inftl, thisVUC);	memset(BlockUsed, 0, sizeof(BlockUsed));	memset(BlockDeleted, 0, sizeof(BlockDeleted));	thisEUN = inftl->VUtable[thisVUC];	if (thisEUN == BLOCK_NIL) {		printk(KERN_WARNING "INFTL: trying to delete non-existent "		       "Virtual Unit Chain %d!\n", thisVUC);		return;	}	/*	 * Scan through the Erase Units to determine whether any data is in	 * each of the 512-byte blocks within the Chain.	 */	silly = MAX_LOOPS;	while (thisEUN < inftl->nb_blocks) {		for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++) {			if (BlockUsed[block] || BlockDeleted[block])				continue;			if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)					   + (block * SECTORSIZE), 8 , &retlen,					  (char *)&bci) < 0)				status = SECTOR_IGNORE;			else				status = bci.Status | bci.Status1;			switch(status) {			case SECTOR_FREE:			case SECTOR_IGNORE:				break;			case SECTOR_USED:				BlockUsed[block] = 1;				continue;			case SECTOR_DELETED:				BlockDeleted[block] = 1;				continue;			default:				printk(KERN_WARNING "INFTL: unknown status "					"for block %d in EUN %d: 0x%x\n",					block, thisEUN, status);			}		}		if (!silly--) {			printk(KERN_WARNING "INFTL: infinite loop in Virtual "				"Unit Chain 0x%x\n", thisVUC);			return;		}		thisEUN = inftl->PUtable[thisEUN];	}	for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++)		if (BlockUsed[block])			return;	/*	 * For each block in the chain free it and make it available	 * for future use. Erase from the oldest unit first.	 */	DEBUG(MTD_DEBUG_LEVEL1, "INFTL: deleting empty VUC %d\n", thisVUC);	for (;;) {		u16 *prevEUN = &inftl->VUtable[thisVUC];		thisEUN = *prevEUN;		/* If the chain is all gone already, we're done */		if (thisEUN == BLOCK_NIL) {			DEBUG(MTD_DEBUG_LEVEL2, "INFTL: Empty VUC %d for deletion was already absent\n", thisEUN);			return;		}		/* Find oldest unit in chain. */		while (inftl->PUtable[thisEUN] != BLOCK_NIL) {			BUG_ON(thisEUN >= inftl->nb_blocks);			prevEUN = &inftl->PUtable[thisEUN];			thisEUN = *prevEUN;		}		DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n",		      thisEUN, thisVUC);		if (INFTL_formatblock(inftl, thisEUN) < 0) {			/*			 * Could not erase : mark block as reserved.			 */			inftl->PUtable[thisEUN] = BLOCK_RESERVED;		} else {			/* Correctly erased : mark it as free */			inftl->PUtable[thisEUN] = BLOCK_FREE;			inftl->numfreeEUNs++;		}		/* Now sort out whatever was pointing to it... */		*prevEUN = BLOCK_NIL;		/* Ideally we'd actually be responsive to new		   requests while we're doing this -- if there's		   free space why should others be made to wait? */		cond_resched();	}	inftl->VUtable[thisVUC] = BLOCK_NIL;}static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block){	unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];	unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);	struct mtd_info *mtd = inftl->mbd.mtd;	unsigned int status;	int silly = MAX_LOOPS;	size_t retlen;	struct inftl_bci bci;	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=%p,"		"block=%d)\n", inftl, block);	while (thisEUN < inftl->nb_blocks) {		if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +				   blockofs, 8, &retlen, (char *)&bci) < 0)			status = SECTOR_IGNORE;		else			status = bci.Status | bci.Status1;		switch (status) {		case SECTOR_FREE:		case SECTOR_IGNORE:			break;		case SECTOR_DELETED:			thisEUN = BLOCK_NIL;			goto foundit;		case SECTOR_USED:			goto foundit;		default:			printk(KERN_WARNING "INFTL: unknown status for "				"block %d in EUN %d: 0x%x\n",				block, thisEUN, status);			break;		}		if (!silly--) {			printk(KERN_WARNING "INFTL: infinite loop in Virtual "				"Unit Chain 0x%x\n",				block / (inftl->EraseSize / SECTORSIZE));			return 1;		}		thisEUN = inftl->PUtable[thisEUN];	}foundit:	if (thisEUN != BLOCK_NIL) {		loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;		if (inftl_read_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0)			return -EIO;		bci.Status = bci.Status1 = SECTOR_DELETED;		if (inftl_write_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0)			return -EIO;		INFTL_trydeletechain(inftl, block / (inftl->EraseSize / SECTORSIZE));	}	return 0;}static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,			    char *buffer){	struct INFTLrecord *inftl = (void *)mbd;	unsigned int writeEUN;	unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);	size_t retlen;	struct inftl_oob oob;	char *p, *pend;	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=%p,block=%ld,"		"buffer=%p)\n", inftl, block, buffer);	/* Is block all zero? */	pend = buffer + SECTORSIZE;	for (p = buffer; p < pend && !*p; p++)		;	if (p < pend) {		writeEUN = INFTL_findwriteunit(inftl, block);		if (writeEUN == BLOCK_NIL) {			printk(KERN_WARNING "inftl_writeblock(): cannot find "				"block to write to\n");			/*			 * If we _still_ haven't got a block to use,			 * we're screwed.			 */			return 1;		}		memset(&oob, 0xff, sizeof(struct inftl_oob));		oob.b.Status = oob.b.Status1 = SECTOR_USED;		inftl_write(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +			    blockofs, SECTORSIZE, &retlen, (char *)buffer,			    (char *)&oob);		/*		 * need to write SECTOR_USED flags since they are not written		 * in mtd_writeecc		 */	} else {		INFTL_deleteblock(inftl, block);	}	return 0;}static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,			   char *buffer){	struct INFTLrecord *inftl = (void *)mbd;	unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];	unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);	struct mtd_info *mtd = inftl->mbd.mtd;	unsigned int status;	int silly = MAX_LOOPS;	struct inftl_bci bci;	size_t retlen;	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld,"		"buffer=%p)\n", inftl, block, buffer);	while (thisEUN < inftl->nb_blocks) {		if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +				  blockofs, 8, &retlen, (char *)&bci) < 0)			status = SECTOR_IGNORE;		else			status = bci.Status | bci.Status1;		switch (status) {		case SECTOR_DELETED:			thisEUN = BLOCK_NIL;			goto foundit;		case SECTOR_USED:			goto foundit;		case SECTOR_FREE:		case SECTOR_IGNORE:			break;		default:			printk(KERN_WARNING "INFTL: unknown status for "				"block %ld in EUN %d: 0x%04x\n",				block, thisEUN, status);			break;		}		if (!silly--) {			printk(KERN_WARNING "INFTL: infinite loop in "				"Virtual Unit Chain 0x%lx\n",				block / (inftl->EraseSize / SECTORSIZE));			return 1;		}		thisEUN = inftl->PUtable[thisEUN];	}foundit:	if (thisEUN == BLOCK_NIL) {		/* The requested block is not on the media, return all 0x00 */		memset(buffer, 0, SECTORSIZE);	} else {		size_t retlen;		loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;		int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer);		/* Handle corrected bit flips gracefully */		if (ret < 0 && ret != -EUCLEAN)			return -EIO;	}	return 0;}static int inftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo){	struct INFTLrecord *inftl = (void *)dev;	geo->heads = inftl->heads;	geo->sectors = inftl->sectors;	geo->cylinders = inftl->cylinders;	return 0;}static struct mtd_blktrans_ops inftl_tr = {	.name		= "inftl",	.major		= INFTL_MAJOR,	.part_bits	= INFTL_PARTN_BITS,	.blksize 	= 512,	.getgeo		= inftl_getgeo,	.readsect	= inftl_readblock,	.writesect	= inftl_writeblock,	.add_mtd	= inftl_add_mtd,	.remove_dev	= inftl_remove_dev,	.owner		= THIS_MODULE,};static int __init init_inftl(void){	return register_mtd_blktrans(&inftl_tr);}static void __exit cleanup_inftl(void){	deregister_mtd_blktrans(&inftl_tr);}module_init(init_inftl);module_exit(cleanup_inftl);MODULE_LICENSE("GPL");MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>, David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");MODULE_DESCRIPTION("Support code for Inverse Flash Translation Layer, used on M-Systems DiskOnChip 2000, Millennium and Millennium Plus");

⌨️ 快捷键说明

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