mtd/drivers/mtd/nand diskonchip.c,1.16,1.17

dbrown at infradead.org dbrown at infradead.org
Thu Jun 24 10:29:43 EDT 2004


Update of /home/cvs/mtd/drivers/mtd/nand
In directory phoenix.infradead.org:/tmp/cvs-serv14441

Modified Files:
	diskonchip.c 
Log Message:
Add versioned BBTs for NFTL.  Support UnitSizeFactor!=0xff.  Fix DOC2000 floor counting.


Index: diskonchip.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/diskonchip.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- diskonchip.c	22 Jun 2004 18:27:34 -0000	1.16
+++ diskonchip.c	24 Jun 2004 14:29:40 -0000	1.17
@@ -70,11 +70,13 @@
 };
 
 static struct nand_bbt_descr nftl_bbt_descr0 = {
-	.options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT | NAND_BBT_SAVECONTENT | NAND_BBT_WRITE
+	.options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT | NAND_BBT_SAVECONTENT | NAND_BBT_WRITE | NAND_BBT_VERSION,
+	.veroffs = 6
 };
 
 static struct nand_bbt_descr nftl_bbt_descr1 = {
-	.options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT | NAND_BBT_SAVECONTENT | NAND_BBT_WRITE
+	.options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT | NAND_BBT_SAVECONTENT | NAND_BBT_WRITE | NAND_BBT_VERSION,
+	.veroffs = 6
 };
 
 #define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
@@ -251,7 +253,7 @@
 	doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
 	this->write_byte(mtd, 0);
 	doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
-	
+
 	ret = this->read_byte(mtd) << 8;
 	ret |= this->read_byte(mtd);
 
@@ -261,8 +263,6 @@
 			uint32_t dword;
 			uint8_t byte[4];
 		} ident;
-		struct nand_chip *this = mtd->priv;
-		struct doc_priv *doc = (void *)this->priv;
 		unsigned long docptr = doc->virtadr;
 
 		doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
@@ -301,6 +301,7 @@
 			break;
 	}
 	doc->chips_per_floor = i;
+	printk(KERN_DEBUG "Detected %d chips per floor.\n", i);
 }
 
 static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
@@ -662,15 +663,17 @@
 {
 	struct nand_chip *this = mtd->priv;
 	struct doc_priv *doc = (void *)this->priv;
-	int offs, end = (MAX_MEDIAHEADER_SCAN << this->erase_shift);
+	int offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift);
 	int ret, retlen;
 
 	end = min(end, mtd->size); // paranoia
 	for (offs = 0; offs < end; offs += mtd->erasesize) {
-/* DBB note: This read will use ECC.  Is this OK?  Check with David. */
-		if ((ret = mtd->read(mtd, offs, SECTORSIZE, &retlen, buf)))
-			continue;
-		if (retlen != SECTORSIZE) continue;
+		ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
+		if (retlen != mtd->oobblock) continue;
+		if (ret) {
+			printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n",
+				offs);
+		}
 		if (memcmp(buf, id, 6)) continue;
 		printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs);
 		if (doc->mh0_page == -1) {
@@ -688,8 +691,8 @@
 	/* Only one mediaheader was found.  We want buf to contain a
 	   mediaheader on return, so we'll have to re-read the one we found. */
 	offs = doc->mh0_page << this->page_shift;
-	ret = mtd->read(mtd, offs, SECTORSIZE, &retlen, buf);
-	if (ret || (retlen != SECTORSIZE)) {
+	ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
+	if (retlen != mtd->oobblock) {
 		/* Insanity.  Give up. */
 		printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");
 		return 0;
@@ -704,9 +707,11 @@
 	struct doc_priv *doc = (void *)this->priv;
 	u_char *buf = this->data_buf;
 	struct NFTLMediaHeader *mh = (struct NFTLMediaHeader *) buf;
-	int offs;
+	const int psize = 1 << this->page_shift;
+	int blocks, maxblocks;
+	int offs, numheaders;
 
-	if (!find_media_headers(mtd, buf, "ANAND", 1)) return 0;
+	if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) return 0;
 
 //#ifdef CONFIG_MTD_DEBUG_VERBOSE
 //	if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
@@ -720,8 +725,39 @@
 		mh->UnitSizeFactor);
 //#endif
 
+	blocks = mtd->size >> this->phys_erase_shift;
+	maxblocks = min(32768, mtd->erasesize - psize);
+
+	if (mh->UnitSizeFactor == 0x00) {
+		/* Auto-determine UnitSizeFactor.  The constraints are:
+		   - There can be at most 32768 virtual blocks.
+		   - There can be at most (virtual block size - page size)
+		     virtual blocks (because MediaHeader+BBT must fit in 1).
+		*/
+		mh->UnitSizeFactor = 0xff;
+		while (blocks > maxblocks) {
+			blocks >>= 1;
+			maxblocks = min(32768, (maxblocks << 1) + psize);
+			mh->UnitSizeFactor--;
+		}
+		printk(KERN_WARNING "UnitSizeFactor=0x00 detected.  Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor);
+	}
+
+	/* NOTE: The lines below modify internal variables of the NAND and MTD
+	   layers; variables with have already been configured by nand_scan.
+	   Unfortunately, we didn't know before this point what these values
+	   should be.  Thus, this code is somewhat dependant on the exact
+	   implementation of the NAND layer.  */
 	if (mh->UnitSizeFactor != 0xff) {
-		printk(KERN_ERR "Currently only UnitSizeFactor=0xff is supported.\n");
+		this->bbt_erase_shift += (0xff - mh->UnitSizeFactor);
+		mtd->erasesize <<= (0xff - mh->UnitSizeFactor);
+		printk(KERN_INFO "Setting virtual erase size to %d\n", mtd->erasesize);
+		blocks = mtd->size >> this->bbt_erase_shift;
+		maxblocks = min(32768, mtd->erasesize - psize);
+	}
+
+	if (blocks > maxblocks) {
+		printk(KERN_ERR "UnitSizeFactor of 0x%02x is inconsistent with device size.  Aborting.\n", mh->UnitSizeFactor);
 		return 0;
 	}
 
@@ -736,7 +772,7 @@
 
 	parts[0].name = "DiskOnChip BDTL partition";
 	parts[0].offset = offs;
-	parts[0].size = mh->NumEraseUnits << this->erase_shift;
+	parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
 
 	offs += parts[0].size;
 	if (offs < mtd->size) {
@@ -758,12 +794,13 @@
 	struct INFTLMediaHeader *mh = (struct INFTLMediaHeader *) buf;
 	struct INFTLPartition *ip;
 	int numparts = 0;
-	int lastblock = 0;
+	int blocks;
+	int vshift, lastvunit = 0;
 	int i;
 	int end = mtd->size;
 
 	if (inftl_bbt_write)
-		end -= (INFTL_BBT_RESERVED_BLOCKS << this->erase_shift);
+		end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);
 
 	if (!find_media_headers(mtd, buf, "BNAND", 0)) return 0;
 	doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);
@@ -792,8 +829,17 @@
 		mh->OsakVersion, mh->PercentUsed);
 //#endif
 
-	if (mh->BlockMultiplierBits != 0) {
-		printk(KERN_ERR "Currently only BlockMultiplierBits=0 is supported.\n");
+	vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
+
+	blocks = mtd->size >> vshift;
+	if (blocks > 32768) {
+		printk(KERN_ERR "BlockMultiplierBits=%d is inconsistent with device size.  Aborting.\n", mh->BlockMultiplierBits);
+		return 0;
+	}
+
+	blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift);
+	if (inftl_bbt_write && (blocks > mtd->erasesize)) {
+		printk(KERN_ERR "Writeable BBTs spanning more than one erase block are not yet supported.  FIX ME!\n");
 		return 0;
 	}
 
@@ -833,16 +879,16 @@
 			parts[numparts].name = "DiskOnChip BDK partition";
 		else
 			parts[numparts].name = "DiskOnChip BDTL partition";
-		parts[numparts].offset = ip->firstUnit << this->erase_shift;
-		parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << this->erase_shift;
+		parts[numparts].offset = ip->firstUnit << vshift;
+		parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;
 		numparts++;
-		if (ip->lastUnit > lastblock) lastblock = ip->lastUnit;
+		if (ip->lastUnit > lastvunit) lastvunit = ip->lastUnit;
 		if (ip->flags & INFTL_LAST) break;
 	}
-	lastblock++;
-	if ((lastblock << this->erase_shift) < end) {
+	lastvunit++;
+	if ((lastvunit << vshift) < end) {
 		parts[numparts].name = "DiskOnChip Remainder partition";
-		parts[numparts].offset = lastblock << this->erase_shift;
+		parts[numparts].offset = lastvunit << vshift;
 		parts[numparts].size = end - parts[numparts].offset;
 		numparts++;
 	}
@@ -856,10 +902,6 @@
 	struct doc_priv *doc = (void *)this->priv;
 	struct mtd_partition parts[2];
 
-	if (this->numchips > doc->chips_per_floor) {
-		printk(KERN_ERR "Multi-floor devices not yet supported.\n");
-		return -EIO;
-	}
 	memset((char *) parts, 0, sizeof(parts));
 	/* On NFTL, we have to find the media headers before we can read the
 	   BBTs, since they're stored in the media header eraseblocks. */
@@ -888,7 +930,7 @@
 	struct mtd_partition parts[5];
 
 	if (this->numchips > doc->chips_per_floor) {
-		printk(KERN_ERR "Multi-floor devices not yet supported.\n");
+		printk(KERN_ERR "Multi-floor INFTL devices not yet supported.\n");
 		return -EIO;
 	}
 	if (inftl_bbt_write) {
@@ -900,7 +942,9 @@
 	if (ret = nand_scan_bbt(mtd, NULL)) return ret;
 	memset((char *) parts, 0, sizeof(parts));
 	numparts = inftl_partscan(mtd, parts);
-	/* At least for now, require the INFTL Media Header. */
+	/* At least for now, require the INFTL Media Header.  We could probably
+	   do without it for non-INFTL use, since all it gives us is
+	   autopartitioning, but I want to give it more thought. */
 	if (!numparts) return -EIO;
 	add_mtd_device(mtd);
 #if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
@@ -967,10 +1011,10 @@
                 mynand.bbt_md = &nftl_bbt_descr1;
 		mynand.scan_bbt = nftl_scan_bbt;
 
+		mydoc.CDSNControl |= CDSN_CTRL_FLASH_IO|CDSN_CTRL_ECC_IO;
 		doc2000_count_chips(&mymtd);
 		nrchips = 4 * mydoc.chips_per_floor;
 		mymtd.name = "DiskOnChip 2000 (NFTL Model)";
-		mydoc.CDSNControl |= CDSN_CTRL_FLASH_IO|CDSN_CTRL_ECC_IO;
 
 		break;
 





More information about the linux-mtd-cvs mailing list