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