aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/devices/doc2000.c39
-rw-r--r--drivers/mtd/devices/doc2001.c34
-rw-r--r--drivers/mtd/devices/doc2001plus.c34
-rw-r--r--drivers/mtd/inftlcore.c111
-rw-r--r--drivers/mtd/inftlmount.c27
-rw-r--r--drivers/mtd/mtdchar.c59
-rw-r--r--drivers/mtd/mtdconcat.c90
-rw-r--r--drivers/mtd/mtdpart.c29
-rw-r--r--drivers/mtd/nand/nand_base.c542
-rw-r--r--drivers/mtd/nand/nand_bbt.c188
-rw-r--r--drivers/mtd/nftlcore.c92
-rw-r--r--drivers/mtd/nftlmount.c29
-rw-r--r--drivers/mtd/onenand/onenand_base.c46
-rw-r--r--drivers/mtd/onenand/onenand_bbt.c7
14 files changed, 859 insertions, 468 deletions
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c
index d9ba1ee658f6..c54e40464d82 100644
--- a/drivers/mtd/devices/doc2000.c
+++ b/drivers/mtd/devices/doc2000.c
@@ -59,10 +59,10 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
59 size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); 59 size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
60static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, 60static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
61 size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); 61 size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
62static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, 62static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
63 size_t *retlen, u_char *buf); 63 struct mtd_oob_ops *ops);
64static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, 64static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
65 size_t *retlen, const u_char *buf); 65 struct mtd_oob_ops *ops);
66static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len, 66static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
67 size_t *retlen, const u_char *buf); 67 size_t *retlen, const u_char *buf);
68static int doc_erase (struct mtd_info *mtd, struct erase_info *instr); 68static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
@@ -959,12 +959,18 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
959 return 0; 959 return 0;
960} 960}
961 961
962static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, 962static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
963 size_t * retlen, u_char * buf) 963 struct mtd_oob_ops *ops)
964{ 964{
965 struct DiskOnChip *this = mtd->priv; 965 struct DiskOnChip *this = mtd->priv;
966 int len256 = 0, ret; 966 int len256 = 0, ret;
967 struct Nand *mychip; 967 struct Nand *mychip;
968 uint8_t *buf = ops->oobbuf;
969 size_t len = ops->len;
970
971 BUG_ON(ops->mode != MTD_OOB_PLACE);
972
973 ofs += ops->ooboffs;
968 974
969 mutex_lock(&this->lock); 975 mutex_lock(&this->lock);
970 976
@@ -1005,7 +1011,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
1005 1011
1006 DoC_ReadBuf(this, &buf[len256], len - len256); 1012 DoC_ReadBuf(this, &buf[len256], len - len256);
1007 1013
1008 *retlen = len; 1014 ops->retlen = len;
1009 /* Reading the full OOB data drops us off of the end of the page, 1015 /* Reading the full OOB data drops us off of the end of the page,
1010 * causing the flash device to go into busy mode, so we need 1016 * causing the flash device to go into busy mode, so we need
1011 * to wait until ready 11.4.1 and Toshiba TC58256FT docs */ 1017 * to wait until ready 11.4.1 and Toshiba TC58256FT docs */
@@ -1120,17 +1126,20 @@ static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
1120 1126
1121} 1127}
1122 1128
1123static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, 1129static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
1124 size_t * retlen, const u_char * buf) 1130 struct mtd_oob_ops *ops)
1125{ 1131{
1126 struct DiskOnChip *this = mtd->priv; 1132 struct DiskOnChip *this = mtd->priv;
1127 int ret; 1133 int ret;
1128 1134
1129 mutex_lock(&this->lock); 1135 BUG_ON(ops->mode != MTD_OOB_PLACE);
1130 ret = doc_write_oob_nolock(mtd, ofs, len, retlen, buf); 1136
1137 mutex_lock(&this->lock);
1138 ret = doc_write_oob_nolock(mtd, ofs + ops->ooboffs, ops->len,
1139 &ops->retlen, ops->oobbuf);
1131 1140
1132 mutex_unlock(&this->lock); 1141 mutex_unlock(&this->lock);
1133 return ret; 1142 return ret;
1134} 1143}
1135 1144
1136static int doc_erase(struct mtd_info *mtd, struct erase_info *instr) 1145static int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c
index 579c0b570ae5..0cf022a69e65 100644
--- a/drivers/mtd/devices/doc2001.c
+++ b/drivers/mtd/devices/doc2001.c
@@ -43,10 +43,10 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
43static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, 43static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
44 size_t *retlen, const u_char *buf, u_char *eccbuf, 44 size_t *retlen, const u_char *buf, u_char *eccbuf,
45 struct nand_oobinfo *oobsel); 45 struct nand_oobinfo *oobsel);
46static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, 46static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
47 size_t *retlen, u_char *buf); 47 struct mtd_oob_ops *ops);
48static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, 48static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
49 size_t *retlen, const u_char *buf); 49 struct mtd_oob_ops *ops);
50static int doc_erase (struct mtd_info *mtd, struct erase_info *instr); 50static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
51 51
52static struct mtd_info *docmillist = NULL; 52static struct mtd_info *docmillist = NULL;
@@ -662,8 +662,8 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
662 return ret; 662 return ret;
663} 663}
664 664
665static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, 665static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
666 size_t *retlen, u_char *buf) 666 struct mtd_oob_ops *ops)
667{ 667{
668#ifndef USE_MEMCPY 668#ifndef USE_MEMCPY
669 int i; 669 int i;
@@ -672,6 +672,12 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
672 struct DiskOnChip *this = mtd->priv; 672 struct DiskOnChip *this = mtd->priv;
673 void __iomem *docptr = this->virtadr; 673 void __iomem *docptr = this->virtadr;
674 struct Nand *mychip = &this->chips[ofs >> this->chipshift]; 674 struct Nand *mychip = &this->chips[ofs >> this->chipshift];
675 uint8_t *buf = ops->oobbuf;
676 size_t len = ops->len;
677
678 BUG_ON(ops->mode != MTD_OOB_PLACE);
679
680 ofs += ops->ooboffs;
675 681
676 /* Find the chip which is to be used and select it */ 682 /* Find the chip which is to be used and select it */
677 if (this->curfloor != mychip->floor) { 683 if (this->curfloor != mychip->floor) {
@@ -708,13 +714,13 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
708#endif 714#endif
709 buf[len - 1] = ReadDOC(docptr, LastDataRead); 715 buf[len - 1] = ReadDOC(docptr, LastDataRead);
710 716
711 *retlen = len; 717 ops->retlen = len;
712 718
713 return 0; 719 return 0;
714} 720}
715 721
716static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, 722static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
717 size_t *retlen, const u_char *buf) 723 struct mtd_oob_ops *ops)
718{ 724{
719#ifndef USE_MEMCPY 725#ifndef USE_MEMCPY
720 int i; 726 int i;
@@ -724,6 +730,12 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
724 struct DiskOnChip *this = mtd->priv; 730 struct DiskOnChip *this = mtd->priv;
725 void __iomem *docptr = this->virtadr; 731 void __iomem *docptr = this->virtadr;
726 struct Nand *mychip = &this->chips[ofs >> this->chipshift]; 732 struct Nand *mychip = &this->chips[ofs >> this->chipshift];
733 uint8_t *buf = ops->oobbuf;
734 size_t len = ops->len;
735
736 BUG_ON(ops->mode != MTD_OOB_PLACE);
737
738 ofs += ops->ooboffs;
727 739
728 /* Find the chip which is to be used and select it */ 740 /* Find the chip which is to be used and select it */
729 if (this->curfloor != mychip->floor) { 741 if (this->curfloor != mychip->floor) {
@@ -775,12 +787,12 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
775 if (ReadDOC(docptr, Mil_CDSN_IO) & 1) { 787 if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
776 printk("Error programming oob data\n"); 788 printk("Error programming oob data\n");
777 /* FIXME: implement Bad Block Replacement (in nftl.c ??) */ 789 /* FIXME: implement Bad Block Replacement (in nftl.c ??) */
778 *retlen = 0; 790 ops->retlen = 0;
779 ret = -EIO; 791 ret = -EIO;
780 } 792 }
781 dummy = ReadDOC(docptr, LastDataRead); 793 dummy = ReadDOC(docptr, LastDataRead);
782 794
783 *retlen = len; 795 ops->retlen = len;
784 796
785 return ret; 797 return ret;
786} 798}
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c
index 1ee0c0dcb53b..66cb1e50469a 100644
--- a/drivers/mtd/devices/doc2001plus.c
+++ b/drivers/mtd/devices/doc2001plus.c
@@ -47,10 +47,10 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
47static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, 47static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
48 size_t *retlen, const u_char *buf, u_char *eccbuf, 48 size_t *retlen, const u_char *buf, u_char *eccbuf,
49 struct nand_oobinfo *oobsel); 49 struct nand_oobinfo *oobsel);
50static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, 50static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
51 size_t *retlen, u_char *buf); 51 struct mtd_oob_ops *ops);
52static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, 52static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
53 size_t *retlen, const u_char *buf); 53 struct mtd_oob_ops *ops);
54static int doc_erase (struct mtd_info *mtd, struct erase_info *instr); 54static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
55 55
56static struct mtd_info *docmilpluslist = NULL; 56static struct mtd_info *docmilpluslist = NULL;
@@ -868,14 +868,20 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
868 return ret; 868 return ret;
869} 869}
870 870
871static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, 871static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
872 size_t *retlen, u_char *buf) 872 struct mtd_oob_ops *ops)
873{ 873{
874 loff_t fofs, base; 874 loff_t fofs, base;
875 struct DiskOnChip *this = mtd->priv; 875 struct DiskOnChip *this = mtd->priv;
876 void __iomem * docptr = this->virtadr; 876 void __iomem * docptr = this->virtadr;
877 struct Nand *mychip = &this->chips[ofs >> this->chipshift]; 877 struct Nand *mychip = &this->chips[ofs >> this->chipshift];
878 size_t i, size, got, want; 878 size_t i, size, got, want;
879 uint8_t *buf = ops->oobbuf;
880 size_t len = ops->len;
881
882 BUG_ON(ops->mode != MTD_OOB_PLACE);
883
884 ofs += ops->ooboffs;
879 885
880 DoC_CheckASIC(docptr); 886 DoC_CheckASIC(docptr);
881 887
@@ -941,12 +947,12 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
941 /* Disable flash internally */ 947 /* Disable flash internally */
942 WriteDOC(0, docptr, Mplus_FlashSelect); 948 WriteDOC(0, docptr, Mplus_FlashSelect);
943 949
944 *retlen = len; 950 ops->retlen = len;
945 return 0; 951 return 0;
946} 952}
947 953
948static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, 954static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
949 size_t *retlen, const u_char *buf) 955 struct mtd_oob_ops *ops)
950{ 956{
951 volatile char dummy; 957 volatile char dummy;
952 loff_t fofs, base; 958 loff_t fofs, base;
@@ -955,6 +961,12 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
955 struct Nand *mychip = &this->chips[ofs >> this->chipshift]; 961 struct Nand *mychip = &this->chips[ofs >> this->chipshift];
956 size_t i, size, got, want; 962 size_t i, size, got, want;
957 int ret = 0; 963 int ret = 0;
964 uint8_t *buf = ops->oobbuf;
965 size_t len = ops->len;
966
967 BUG_ON(ops->mode != MTD_OOB_PLACE);
968
969 ofs += ops->ooboffs;
958 970
959 DoC_CheckASIC(docptr); 971 DoC_CheckASIC(docptr);
960 972
@@ -1030,7 +1042,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
1030 printk("MTD: Error 0x%x programming oob at 0x%x\n", 1042 printk("MTD: Error 0x%x programming oob at 0x%x\n",
1031 dummy, (int)ofs); 1043 dummy, (int)ofs);
1032 /* FIXME: implement Bad Block Replacement */ 1044 /* FIXME: implement Bad Block Replacement */
1033 *retlen = 0; 1045 ops->retlen = 0;
1034 ret = -EIO; 1046 ret = -EIO;
1035 } 1047 }
1036 dummy = ReadDOC(docptr, Mplus_LastDataRead); 1048 dummy = ReadDOC(docptr, Mplus_LastDataRead);
@@ -1043,7 +1055,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
1043 /* Disable flash internally */ 1055 /* Disable flash internally */
1044 WriteDOC(0, docptr, Mplus_FlashSelect); 1056 WriteDOC(0, docptr, Mplus_FlashSelect);
1045 1057
1046 *retlen = len; 1058 ops->retlen = len;
1047 return ret; 1059 return ret;
1048} 1060}
1049 1061
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index 3396f0e1ac5f..efb1a95aa0a0 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -151,6 +151,69 @@ static void inftl_remove_dev(struct mtd_blktrans_dev *dev)
151 */ 151 */
152 152
153/* 153/*
154 * Read oob data from flash
155 */
156int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
157 size_t *retlen, uint8_t *buf)
158{
159 struct mtd_oob_ops ops;
160 int res;
161
162 ops.mode = MTD_OOB_PLACE;
163 ops.ooboffs = offs & (mtd->writesize - 1);
164 ops.ooblen = len;
165 ops.oobbuf = buf;
166 ops.datbuf = NULL;
167 ops.len = len;
168
169 res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
170 *retlen = ops.retlen;
171 return res;
172}
173
174/*
175 * Write oob data to flash
176 */
177int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
178 size_t *retlen, uint8_t *buf)
179{
180 struct mtd_oob_ops ops;
181 int res;
182
183 ops.mode = MTD_OOB_PLACE;
184 ops.ooboffs = offs & (mtd->writesize - 1);
185 ops.ooblen = len;
186 ops.oobbuf = buf;
187 ops.datbuf = NULL;
188 ops.len = len;
189
190 res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
191 *retlen = ops.retlen;
192 return res;
193}
194
195/*
196 * Write data and oob to flash
197 */
198static int inftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
199 size_t *retlen, uint8_t *buf, uint8_t *oob)
200{
201 struct mtd_oob_ops ops;
202 int res;
203
204 ops.mode = MTD_OOB_PLACE;
205 ops.ooboffs = offs;
206 ops.ooblen = mtd->oobsize;
207 ops.oobbuf = oob;
208 ops.datbuf = buf;
209 ops.len = len;
210
211 res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
212 *retlen = ops.retlen;
213 return res;
214}
215
216/*
154 * INFTL_findfreeblock: Find a free Erase Unit on the INFTL partition. 217 * INFTL_findfreeblock: Find a free Erase Unit on the INFTL partition.
155 * This function is used when the give Virtual Unit Chain. 218 * This function is used when the give Virtual Unit Chain.
156 */ 219 */
@@ -227,9 +290,9 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
227 if ((BlockMap[block] != 0xffff) || BlockDeleted[block]) 290 if ((BlockMap[block] != 0xffff) || BlockDeleted[block])
228 continue; 291 continue;
229 292
230 if (mtd->read_oob(mtd, (thisEUN * inftl->EraseSize) 293 if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)
231 + (block * SECTORSIZE), 16 , &retlen, 294 + (block * SECTORSIZE), 16, &retlen,
232 (char *)&oob) < 0) 295 (char *)&oob) < 0)
233 status = SECTOR_IGNORE; 296 status = SECTOR_IGNORE;
234 else 297 else
235 status = oob.b.Status | oob.b.Status1; 298 status = oob.b.Status | oob.b.Status1;
@@ -304,9 +367,9 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
304 memset(&oob, 0xff, sizeof(struct inftl_oob)); 367 memset(&oob, 0xff, sizeof(struct inftl_oob));
305 oob.b.Status = oob.b.Status1 = SECTOR_USED; 368 oob.b.Status = oob.b.Status1 = SECTOR_USED;
306 369
307 nand_write_raw(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) + 370 inftl_write(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
308 (block * SECTORSIZE), SECTORSIZE, &retlen, 371 (block * SECTORSIZE), SECTORSIZE, &retlen,
309 movebuf, (char *)&oob); 372 movebuf, (char *)&oob);
310 } 373 }
311 374
312 /* 375 /*
@@ -437,8 +500,8 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
437 silly = MAX_LOOPS; 500 silly = MAX_LOOPS;
438 501
439 while (thisEUN <= inftl->lastEUN) { 502 while (thisEUN <= inftl->lastEUN) {
440 mtd->read_oob(mtd, (thisEUN * inftl->EraseSize) + 503 inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +
441 blockofs, 8, &retlen, (char *)&bci); 504 blockofs, 8, &retlen, (char *)&bci);
442 505
443 status = bci.Status | bci.Status1; 506 status = bci.Status | bci.Status1;
444 DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in " 507 DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in "
@@ -525,8 +588,8 @@ hitused:
525 nacs = 0; 588 nacs = 0;
526 thisEUN = inftl->VUtable[thisVUC]; 589 thisEUN = inftl->VUtable[thisVUC];
527 if (thisEUN != BLOCK_NIL) { 590 if (thisEUN != BLOCK_NIL) {
528 mtd->read_oob(mtd, thisEUN * inftl->EraseSize 591 inftl_read_oob(mtd, thisEUN * inftl->EraseSize
529 + 8, 8, &retlen, (char *)&oob.u); 592 + 8, 8, &retlen, (char *)&oob.u);
530 anac = oob.u.a.ANAC + 1; 593 anac = oob.u.a.ANAC + 1;
531 nacs = oob.u.a.NACs + 1; 594 nacs = oob.u.a.NACs + 1;
532 } 595 }
@@ -547,8 +610,8 @@ hitused:
547 oob.u.a.parityPerField = parity; 610 oob.u.a.parityPerField = parity;
548 oob.u.a.discarded = 0xaa; 611 oob.u.a.discarded = 0xaa;
549 612
550 mtd->write_oob(mtd, writeEUN * inftl->EraseSize + 8, 8, 613 inftl_write_oob(mtd, writeEUN * inftl->EraseSize + 8, 8,
551 &retlen, (char *)&oob.u); 614 &retlen, (char *)&oob.u);
552 615
553 /* Also back up header... */ 616 /* Also back up header... */
554 oob.u.b.virtualUnitNo = cpu_to_le16(thisVUC); 617 oob.u.b.virtualUnitNo = cpu_to_le16(thisVUC);
@@ -558,8 +621,8 @@ hitused:
558 oob.u.b.parityPerField = parity; 621 oob.u.b.parityPerField = parity;
559 oob.u.b.discarded = 0xaa; 622 oob.u.b.discarded = 0xaa;
560 623
561 mtd->write_oob(mtd, writeEUN * inftl->EraseSize + 624 inftl_write_oob(mtd, writeEUN * inftl->EraseSize +
562 SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u); 625 SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);
563 626
564 inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC]; 627 inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC];
565 inftl->VUtable[thisVUC] = writeEUN; 628 inftl->VUtable[thisVUC] = writeEUN;
@@ -610,8 +673,8 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
610 if (BlockUsed[block] || BlockDeleted[block]) 673 if (BlockUsed[block] || BlockDeleted[block])
611 continue; 674 continue;
612 675
613 if (mtd->read_oob(mtd, (thisEUN * inftl->EraseSize) 676 if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)
614 + (block * SECTORSIZE), 8 , &retlen, 677 + (block * SECTORSIZE), 8 , &retlen,
615 (char *)&bci) < 0) 678 (char *)&bci) < 0)
616 status = SECTOR_IGNORE; 679 status = SECTOR_IGNORE;
617 else 680 else
@@ -711,8 +774,8 @@ static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block)
711 "block=%d)\n", inftl, block); 774 "block=%d)\n", inftl, block);
712 775
713 while (thisEUN < inftl->nb_blocks) { 776 while (thisEUN < inftl->nb_blocks) {
714 if (mtd->read_oob(mtd, (thisEUN * inftl->EraseSize) + 777 if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +
715 blockofs, 8, &retlen, (char *)&bci) < 0) 778 blockofs, 8, &retlen, (char *)&bci) < 0)
716 status = SECTOR_IGNORE; 779 status = SECTOR_IGNORE;
717 else 780 else
718 status = bci.Status | bci.Status1; 781 status = bci.Status | bci.Status1;
@@ -746,10 +809,10 @@ foundit:
746 if (thisEUN != BLOCK_NIL) { 809 if (thisEUN != BLOCK_NIL) {
747 loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs; 810 loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
748 811
749 if (mtd->read_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0) 812 if (inftl_read_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0)
750 return -EIO; 813 return -EIO;
751 bci.Status = bci.Status1 = SECTOR_DELETED; 814 bci.Status = bci.Status1 = SECTOR_DELETED;
752 if (mtd->write_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0) 815 if (inftl_write_oob(mtd, ptr, 8, &retlen, (char *)&bci) < 0)
753 return -EIO; 816 return -EIO;
754 INFTL_trydeletechain(inftl, block / (inftl->EraseSize / SECTORSIZE)); 817 INFTL_trydeletechain(inftl, block / (inftl->EraseSize / SECTORSIZE));
755 } 818 }
@@ -790,9 +853,9 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
790 memset(&oob, 0xff, sizeof(struct inftl_oob)); 853 memset(&oob, 0xff, sizeof(struct inftl_oob));
791 oob.b.Status = oob.b.Status1 = SECTOR_USED; 854 oob.b.Status = oob.b.Status1 = SECTOR_USED;
792 855
793 nand_write_raw(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) + 856 inftl_write(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
794 blockofs, SECTORSIZE, &retlen, (char *)buffer, 857 blockofs, SECTORSIZE, &retlen, (char *)buffer,
795 (char *)&oob); 858 (char *)&oob);
796 /* 859 /*
797 * need to write SECTOR_USED flags since they are not written 860 * need to write SECTOR_USED flags since they are not written
798 * in mtd_writeecc 861 * in mtd_writeecc
@@ -820,7 +883,7 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
820 "buffer=%p)\n", inftl, block, buffer); 883 "buffer=%p)\n", inftl, block, buffer);
821 884
822 while (thisEUN < inftl->nb_blocks) { 885 while (thisEUN < inftl->nb_blocks) {
823 if (mtd->read_oob(mtd, (thisEUN * inftl->EraseSize) + 886 if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +
824 blockofs, 8, &retlen, (char *)&bci) < 0) 887 blockofs, 8, &retlen, (char *)&bci) < 0)
825 status = SECTOR_IGNORE; 888 status = SECTOR_IGNORE;
826 else 889 else
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c
index b4cda7d0a52d..8f6006f1a519 100644
--- a/drivers/mtd/inftlmount.c
+++ b/drivers/mtd/inftlmount.c
@@ -43,6 +43,11 @@
43 43
44char inftlmountrev[]="$Revision: 1.18 $"; 44char inftlmountrev[]="$Revision: 1.18 $";
45 45
46extern int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
47 size_t *retlen, uint8_t *buf);
48extern int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
49 size_t *retlen, uint8_t *buf);
50
46/* 51/*
47 * find_boot_record: Find the INFTL Media Header and its Spare copy which 52 * find_boot_record: Find the INFTL Media Header and its Spare copy which
48 * contains the various device information of the INFTL partition and 53 * contains the various device information of the INFTL partition and
@@ -107,9 +112,9 @@ static int find_boot_record(struct INFTLrecord *inftl)
107 } 112 }
108 113
109 /* To be safer with BIOS, also use erase mark as discriminant */ 114 /* To be safer with BIOS, also use erase mark as discriminant */
110 if ((ret = mtd->read_oob(mtd, block * inftl->EraseSize + 115 if ((ret = inftl_read_oob(mtd, block * inftl->EraseSize +
111 SECTORSIZE + 8, 8, &retlen, 116 SECTORSIZE + 8, 8, &retlen,
112 (char *)&h1) < 0)) { 117 (char *)&h1) < 0)) {
113 printk(KERN_WARNING "INFTL: ANAND header found at " 118 printk(KERN_WARNING "INFTL: ANAND header found at "
114 "0x%x in mtd%d, but OOB data read failed " 119 "0x%x in mtd%d, but OOB data read failed "
115 "(err %d)\n", block * inftl->EraseSize, 120 "(err %d)\n", block * inftl->EraseSize,
@@ -363,8 +368,8 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
363 return -1; 368 return -1;
364 369
365 if (check_oob) { 370 if (check_oob) {
366 if(mtd->read_oob(mtd, address, mtd->oobsize, 371 if(inftl_read_oob(mtd, address, mtd->oobsize,
367 &retlen, &buf[SECTORSIZE]) < 0) 372 &retlen, &buf[SECTORSIZE]) < 0)
368 return -1; 373 return -1;
369 if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0) 374 if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)
370 return -1; 375 return -1;
@@ -433,7 +438,7 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block)
433 uci.Reserved[2] = 0; 438 uci.Reserved[2] = 0;
434 uci.Reserved[3] = 0; 439 uci.Reserved[3] = 0;
435 instr->addr = block * inftl->EraseSize + SECTORSIZE * 2; 440 instr->addr = block * inftl->EraseSize + SECTORSIZE * 2;
436 if (mtd->write_oob(mtd, instr->addr + 8, 8, &retlen, (char *)&uci) < 0) 441 if (inftl_write_oob(mtd, instr->addr + 8, 8, &retlen, (char *)&uci) < 0)
437 goto fail; 442 goto fail;
438 return 0; 443 return 0;
439fail: 444fail:
@@ -611,11 +616,11 @@ int INFTL_mount(struct INFTLrecord *s)
611 break; 616 break;
612 } 617 }
613 618
614 if (mtd->read_oob(mtd, block * s->EraseSize + 8, 619 if (inftl_read_oob(mtd, block * s->EraseSize + 8,
615 8, &retlen, (char *)&h0) < 0 || 620 8, &retlen, (char *)&h0) < 0 ||
616 mtd->read_oob(mtd, block * s->EraseSize + 621 inftl_read_oob(mtd, block * s->EraseSize +
617 2 * SECTORSIZE + 8, 8, &retlen, 622 2 * SECTORSIZE + 8, 8, &retlen,
618 (char *)&h1) < 0) { 623 (char *)&h1) < 0) {
619 /* Should never happen? */ 624 /* Should never happen? */
620 do_format_chain++; 625 do_format_chain++;
621 break; 626 break;
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index b45e7747daa3..7522fc3a2827 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -408,8 +408,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
408 case MEMWRITEOOB: 408 case MEMWRITEOOB:
409 { 409 {
410 struct mtd_oob_buf buf; 410 struct mtd_oob_buf buf;
411 void *databuf; 411 struct mtd_oob_ops ops;
412 ssize_t retlen;
413 412
414 if(!(file->f_mode & 2)) 413 if(!(file->f_mode & 2))
415 return -EPERM; 414 return -EPERM;
@@ -417,7 +416,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
417 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) 416 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
418 return -EFAULT; 417 return -EFAULT;
419 418
420 if (buf.length > 0x4096) 419 if (buf.length > 4096)
421 return -EINVAL; 420 return -EINVAL;
422 421
423 if (!mtd->write_oob) 422 if (!mtd->write_oob)
@@ -429,21 +428,32 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
429 if (ret) 428 if (ret)
430 return ret; 429 return ret;
431 430
432 databuf = kmalloc(buf.length, GFP_KERNEL); 431 ops.len = buf.length;
433 if (!databuf) 432 ops.ooblen = mtd->oobsize;
433 ops.ooboffs = buf.start & (mtd->oobsize - 1);
434 ops.datbuf = NULL;
435 ops.mode = MTD_OOB_PLACE;
436
437 if (ops.ooboffs && ops.len > (ops.ooblen - ops.ooboffs))
438 return -EINVAL;
439
440 ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
441 if (!ops.oobbuf)
434 return -ENOMEM; 442 return -ENOMEM;
435 443
436 if (copy_from_user(databuf, buf.ptr, buf.length)) { 444 if (copy_from_user(ops.oobbuf, buf.ptr, buf.length)) {
437 kfree(databuf); 445 kfree(ops.oobbuf);
438 return -EFAULT; 446 return -EFAULT;
439 } 447 }
440 448
441 ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf); 449 buf.start &= ~(mtd->oobsize - 1);
450 ret = mtd->write_oob(mtd, buf.start, &ops);
442 451
443 if (copy_to_user(argp + sizeof(uint32_t), &retlen, sizeof(uint32_t))) 452 if (copy_to_user(argp + sizeof(uint32_t), &ops.retlen,
453 sizeof(uint32_t)))
444 ret = -EFAULT; 454 ret = -EFAULT;
445 455
446 kfree(databuf); 456 kfree(ops.oobbuf);
447 break; 457 break;
448 458
449 } 459 }
@@ -451,13 +461,12 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
451 case MEMREADOOB: 461 case MEMREADOOB:
452 { 462 {
453 struct mtd_oob_buf buf; 463 struct mtd_oob_buf buf;
454 void *databuf; 464 struct mtd_oob_ops ops;
455 ssize_t retlen;
456 465
457 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) 466 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
458 return -EFAULT; 467 return -EFAULT;
459 468
460 if (buf.length > 0x4096) 469 if (buf.length > 4096)
461 return -EINVAL; 470 return -EINVAL;
462 471
463 if (!mtd->read_oob) 472 if (!mtd->read_oob)
@@ -465,22 +474,32 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
465 else 474 else
466 ret = access_ok(VERIFY_WRITE, buf.ptr, 475 ret = access_ok(VERIFY_WRITE, buf.ptr,
467 buf.length) ? 0 : -EFAULT; 476 buf.length) ? 0 : -EFAULT;
468
469 if (ret) 477 if (ret)
470 return ret; 478 return ret;
471 479
472 databuf = kmalloc(buf.length, GFP_KERNEL); 480 ops.len = buf.length;
473 if (!databuf) 481 ops.ooblen = mtd->oobsize;
482 ops.ooboffs = buf.start & (mtd->oobsize - 1);
483 ops.datbuf = NULL;
484 ops.mode = MTD_OOB_PLACE;
485
486 if (ops.ooboffs && ops.len > (ops.ooblen - ops.ooboffs))
487 return -EINVAL;
488
489 ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
490 if (!ops.oobbuf)
474 return -ENOMEM; 491 return -ENOMEM;
475 492
476 ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf); 493 buf.start &= ~(mtd->oobsize - 1);
494 ret = mtd->read_oob(mtd, buf.start, &ops);
477 495
478 if (put_user(retlen, (uint32_t __user *)argp)) 496 if (put_user(ops.retlen, (uint32_t __user *)argp))
479 ret = -EFAULT; 497 ret = -EFAULT;
480 else if (retlen && copy_to_user(buf.ptr, databuf, retlen)) 498 else if (ops.retlen && copy_to_user(buf.ptr, ops.oobbuf,
499 ops.retlen))
481 ret = -EFAULT; 500 ret = -EFAULT;
482 501
483 kfree(databuf); 502 kfree(ops.oobbuf);
484 break; 503 break;
485 } 504 }
486 505
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index ec15abcdbdfa..38151b8e6631 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -231,101 +231,85 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
231} 231}
232 232
233static int 233static int
234concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len, 234concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
235 size_t * retlen, u_char * buf)
236{ 235{
237 struct mtd_concat *concat = CONCAT(mtd); 236 struct mtd_concat *concat = CONCAT(mtd);
238 int err = -EINVAL; 237 struct mtd_oob_ops devops = *ops;
239 int i; 238 int i, err;
240 239
241 *retlen = 0; 240 ops->retlen = 0;
242 241
243 for (i = 0; i < concat->num_subdev; i++) { 242 for (i = 0; i < concat->num_subdev; i++) {
244 struct mtd_info *subdev = concat->subdev[i]; 243 struct mtd_info *subdev = concat->subdev[i];
245 size_t size, retsize;
246 244
247 if (from >= subdev->size) { 245 if (from >= subdev->size) {
248 /* Not destined for this subdev */
249 size = 0;
250 from -= subdev->size; 246 from -= subdev->size;
251 continue; 247 continue;
252 } 248 }
253 if (from + len > subdev->size)
254 /* First part goes into this subdev */
255 size = subdev->size - from;
256 else
257 /* Entire transaction goes into this subdev */
258 size = len;
259 249
260 if (subdev->read_oob) 250 /* partial read ? */
261 err = subdev->read_oob(subdev, from, size, 251 if (from + devops.len > subdev->size)
262 &retsize, buf); 252 devops.len = subdev->size - from;
263 else
264 err = -EINVAL;
265 253
254 err = subdev->read_oob(subdev, from, &devops);
255 ops->retlen += devops.retlen;
266 if (err) 256 if (err)
267 break; 257 return err;
268 258
269 *retlen += retsize; 259 devops.len = ops->len - ops->retlen;
270 len -= size; 260 if (!devops.len)
271 if (len == 0) 261 return 0;
272 break; 262
263 if (devops.datbuf)
264 devops.datbuf += devops.retlen;
265 if (devops.oobbuf)
266 devops.oobbuf += devops.ooblen;
273 267
274 err = -EINVAL;
275 buf += size;
276 from = 0; 268 from = 0;
277 } 269 }
278 return err; 270 return -EINVAL;
279} 271}
280 272
281static int 273static int
282concat_write_oob(struct mtd_info *mtd, loff_t to, size_t len, 274concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
283 size_t * retlen, const u_char * buf)
284{ 275{
285 struct mtd_concat *concat = CONCAT(mtd); 276 struct mtd_concat *concat = CONCAT(mtd);
286 int err = -EINVAL; 277 struct mtd_oob_ops devops = *ops;
287 int i; 278 int i, err;
288 279
289 if (!(mtd->flags & MTD_WRITEABLE)) 280 if (!(mtd->flags & MTD_WRITEABLE))
290 return -EROFS; 281 return -EROFS;
291 282
292 *retlen = 0; 283 ops->retlen = 0;
293 284
294 for (i = 0; i < concat->num_subdev; i++) { 285 for (i = 0; i < concat->num_subdev; i++) {
295 struct mtd_info *subdev = concat->subdev[i]; 286 struct mtd_info *subdev = concat->subdev[i];
296 size_t size, retsize;
297 287
298 if (to >= subdev->size) { 288 if (to >= subdev->size) {
299 size = 0;
300 to -= subdev->size; 289 to -= subdev->size;
301 continue; 290 continue;
302 } 291 }
303 if (to + len > subdev->size)
304 size = subdev->size - to;
305 else
306 size = len;
307 292
308 if (!(subdev->flags & MTD_WRITEABLE)) 293 /* partial write ? */
309 err = -EROFS; 294 if (to + devops.len > subdev->size)
310 else if (subdev->write_oob) 295 devops.len = subdev->size - to;
311 err = subdev->write_oob(subdev, to, size, &retsize,
312 buf);
313 else
314 err = -EINVAL;
315 296
297 err = subdev->write_oob(subdev, to, &devops);
298 ops->retlen += devops.retlen;
316 if (err) 299 if (err)
317 break; 300 return err;
318 301
319 *retlen += retsize; 302 devops.len = ops->len - ops->retlen;
320 len -= size; 303 if (!devops.len)
321 if (len == 0) 304 return 0;
322 break;
323 305
324 err = -EINVAL; 306 if (devops.datbuf)
325 buf += size; 307 devops.datbuf += devops.retlen;
308 if (devops.oobbuf)
309 devops.oobbuf += devops.ooblen;
326 to = 0; 310 to = 0;
327 } 311 }
328 return err; 312 return -EINVAL;
329} 313}
330 314
331static void concat_erase_callback(struct erase_info *instr) 315static void concat_erase_callback(struct erase_info *instr)
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 6d7639b98eab..f22aeccf01e7 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -78,16 +78,16 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_
78 part->master->unpoint (part->master, addr, from + part->offset, len); 78 part->master->unpoint (part->master, addr, from + part->offset, len);
79} 79}
80 80
81static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, 81static int part_read_oob(struct mtd_info *mtd, loff_t from,
82 size_t *retlen, u_char *buf) 82 struct mtd_oob_ops *ops)
83{ 83{
84 struct mtd_part *part = PART(mtd); 84 struct mtd_part *part = PART(mtd);
85
85 if (from >= mtd->size) 86 if (from >= mtd->size)
86 len = 0; 87 return -EINVAL;
87 else if (from + len > mtd->size) 88 if (from + ops->len > mtd->size)
88 len = mtd->size - from; 89 return -EINVAL;
89 return part->master->read_oob (part->master, from + part->offset, 90 return part->master->read_oob(part->master, from + part->offset, ops);
90 len, retlen, buf);
91} 91}
92 92
93static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 93static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
@@ -134,18 +134,19 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
134 len, retlen, buf); 134 len, retlen, buf);
135} 135}
136 136
137static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len, 137static int part_write_oob(struct mtd_info *mtd, loff_t to,
138 size_t *retlen, const u_char *buf) 138 struct mtd_oob_ops *ops)
139{ 139{
140 struct mtd_part *part = PART(mtd); 140 struct mtd_part *part = PART(mtd);
141
141 if (!(mtd->flags & MTD_WRITEABLE)) 142 if (!(mtd->flags & MTD_WRITEABLE))
142 return -EROFS; 143 return -EROFS;
144
143 if (to >= mtd->size) 145 if (to >= mtd->size)
144 len = 0; 146 return -EINVAL;
145 else if (to + len > mtd->size) 147 if (to + ops->len > mtd->size)
146 len = mtd->size - to; 148 return -EINVAL;
147 return part->master->write_oob (part->master, to + part->offset, 149 return part->master->write_oob(part->master, to + part->offset, ops);
148 len, retlen, buf);
149} 150}
150 151
151static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 152static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index e922b829c4be..b8e6e1579cf1 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -81,23 +81,12 @@ static struct nand_ecclayout nand_oob_64 = {
81 .length = 38}} 81 .length = 38}}
82}; 82};
83 83
84/* This is used for padding purposes in nand_write_oob */
85static uint8_t ffchars[] = {
86 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
87 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
88 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
89 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
90 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
91 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
92 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
93 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
94};
95
96static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
97 size_t *retlen, const uint8_t *buf);
98static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, 84static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
99 int new_state); 85 int new_state);
100 86
87static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
88 struct mtd_oob_ops *ops);
89
101/* 90/*
102 * For devices which display every fart in the system on a seperate LED. Is 91 * For devices which display every fart in the system on a seperate LED. Is
103 * compiled away when LED support is disabled. 92 * compiled away when LED support is disabled.
@@ -358,7 +347,6 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
358{ 347{
359 struct nand_chip *chip = mtd->priv; 348 struct nand_chip *chip = mtd->priv;
360 uint8_t buf[2] = { 0, 0 }; 349 uint8_t buf[2] = { 0, 0 };
361 size_t retlen;
362 int block; 350 int block;
363 351
364 /* Get block number */ 352 /* Get block number */
@@ -371,8 +359,13 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
371 return nand_update_bbt(mtd, ofs); 359 return nand_update_bbt(mtd, ofs);
372 360
373 /* We write two bytes, so we dont have to mess with 16 bit access */ 361 /* We write two bytes, so we dont have to mess with 16 bit access */
374 ofs += mtd->oobsize + (chip->badblockpos & ~0x01); 362 ofs += mtd->oobsize;
375 return nand_write_oob(mtd, ofs, 2, &retlen, buf); 363 chip->ops.len = 2;
364 chip->ops.datbuf = NULL;
365 chip->ops.oobbuf = buf;
366 chip->ops.ooboffs = chip->badblockpos & ~0x01;
367
368 return nand_do_write_oob(mtd, ofs, &chip->ops);
376} 369}
377 370
378/** 371/**
@@ -740,6 +733,20 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip, int state)
740} 733}
741 734
742/** 735/**
736 * nand_read_page_raw - [Intern] read raw page data without ecc
737 * @mtd: mtd info structure
738 * @chip: nand chip info structure
739 * @buf: buffer to store read data
740 */
741static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
742 uint8_t *buf)
743{
744 chip->read_buf(mtd, buf, mtd->writesize);
745 chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
746 return 0;
747}
748
749/**
743 * nand_read_page_swecc - {REPLACABLE] software ecc based page read function 750 * nand_read_page_swecc - {REPLACABLE] software ecc based page read function
744 * @mtd: mtd info structure 751 * @mtd: mtd info structure
745 * @chip: nand chip info structure 752 * @chip: nand chip info structure
@@ -756,11 +763,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
756 uint8_t *ecc_code = chip->buffers.ecccode; 763 uint8_t *ecc_code = chip->buffers.ecccode;
757 int *eccpos = chip->ecc.layout->eccpos; 764 int *eccpos = chip->ecc.layout->eccpos;
758 765
759 chip->read_buf(mtd, buf, mtd->writesize); 766 nand_read_page_raw(mtd, chip, buf);
760 chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
761
762 if (chip->ecc.mode == NAND_ECC_NONE)
763 return 0;
764 767
765 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) 768 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
766 chip->ecc.calculate(mtd, p, &ecc_calc[i]); 769 chip->ecc.calculate(mtd, p, &ecc_calc[i]);
@@ -882,18 +885,50 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
882} 885}
883 886
884/** 887/**
885 * nand_do_read - [Internal] Read data with ECC 888 * nand_transfer_oob - [Internal] Transfer oob to client buffer
889 * @chip: nand chip structure
890 * @ops: oob ops structure
891 */
892static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
893 struct mtd_oob_ops *ops)
894{
895 size_t len = ops->ooblen;
896
897 switch(ops->mode) {
898
899 case MTD_OOB_PLACE:
900 case MTD_OOB_RAW:
901 memcpy(oob, chip->oob_poi + ops->ooboffs, len);
902 return oob + len;
903
904 case MTD_OOB_AUTO: {
905 struct nand_oobfree *free = chip->ecc.layout->oobfree;
906 size_t bytes;
907
908 for(; free->length && len; free++, len -= bytes) {
909 bytes = min(len, free->length);
910
911 memcpy(oob, chip->oob_poi + free->offset, bytes);
912 oob += bytes;
913 }
914 return oob;
915 }
916 default:
917 BUG();
918 }
919 return NULL;
920}
921
922/**
923 * nand_do_read_ops - [Internal] Read data with ECC
886 * 924 *
887 * @mtd: MTD device structure 925 * @mtd: MTD device structure
888 * @from: offset to read from 926 * @from: offset to read from
889 * @len: number of bytes to read
890 * @retlen: pointer to variable to store the number of read bytes
891 * @buf: the databuffer to put data
892 * 927 *
893 * Internal function. Called with chip held. 928 * Internal function. Called with chip held.
894 */ 929 */
895int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, 930static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
896 size_t *retlen, uint8_t *buf) 931 struct mtd_oob_ops *ops)
897{ 932{
898 int chipnr, page, realpage, col, bytes, aligned; 933 int chipnr, page, realpage, col, bytes, aligned;
899 struct nand_chip *chip = mtd->priv; 934 struct nand_chip *chip = mtd->priv;
@@ -901,8 +936,8 @@ int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
901 int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; 936 int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
902 int sndcmd = 1; 937 int sndcmd = 1;
903 int ret = 0; 938 int ret = 0;
904 uint32_t readlen = len; 939 uint32_t readlen = ops->len;
905 uint8_t *bufpoi; 940 uint8_t *bufpoi, *oob, *buf;
906 941
907 stats = mtd->ecc_stats; 942 stats = mtd->ecc_stats;
908 943
@@ -915,12 +950,15 @@ int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
915 col = (int)(from & (mtd->writesize - 1)); 950 col = (int)(from & (mtd->writesize - 1));
916 chip->oob_poi = chip->buffers.oobrbuf; 951 chip->oob_poi = chip->buffers.oobrbuf;
917 952
953 buf = ops->datbuf;
954 oob = ops->oobbuf;
955
918 while(1) { 956 while(1) {
919 bytes = min(mtd->writesize - col, readlen); 957 bytes = min(mtd->writesize - col, readlen);
920 aligned = (bytes == mtd->writesize); 958 aligned = (bytes == mtd->writesize);
921 959
922 /* Is the current page in the buffer ? */ 960 /* Is the current page in the buffer ? */
923 if (realpage != chip->pagebuf) { 961 if (realpage != chip->pagebuf || oob) {
924 bufpoi = aligned ? buf : chip->buffers.databuf; 962 bufpoi = aligned ? buf : chip->buffers.databuf;
925 963
926 if (likely(sndcmd)) { 964 if (likely(sndcmd)) {
@@ -939,6 +977,16 @@ int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
939 memcpy(buf, chip->buffers.databuf + col, bytes); 977 memcpy(buf, chip->buffers.databuf + col, bytes);
940 } 978 }
941 979
980 buf += bytes;
981
982 if (unlikely(oob)) {
983 /* Raw mode does data:oob:data:oob */
984 if (ops->mode != MTD_OOB_RAW)
985 oob = nand_transfer_oob(chip, oob, ops);
986 else
987 buf = nand_transfer_oob(chip, buf, ops);
988 }
989
942 if (!(chip->options & NAND_NO_READRDY)) { 990 if (!(chip->options & NAND_NO_READRDY)) {
943 /* 991 /*
944 * Apply delay or wait for ready/busy pin. Do 992 * Apply delay or wait for ready/busy pin. Do
@@ -952,10 +1000,11 @@ int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
952 else 1000 else
953 nand_wait_ready(mtd); 1001 nand_wait_ready(mtd);
954 } 1002 }
955 } else 1003 } else {
956 memcpy(buf, chip->buffers.databuf + col, bytes); 1004 memcpy(buf, chip->buffers.databuf + col, bytes);
1005 buf += bytes;
1006 }
957 1007
958 buf += bytes;
959 readlen -= bytes; 1008 readlen -= bytes;
960 1009
961 if (!readlen) 1010 if (!readlen)
@@ -981,7 +1030,7 @@ int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
981 sndcmd = 1; 1030 sndcmd = 1;
982 } 1031 }
983 1032
984 *retlen = len - (size_t) readlen; 1033 ops->retlen = ops->len - (size_t) readlen;
985 1034
986 if (ret) 1035 if (ret)
987 return ret; 1036 return ret;
@@ -1002,57 +1051,49 @@ int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
1002static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, 1051static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
1003 size_t *retlen, uint8_t *buf) 1052 size_t *retlen, uint8_t *buf)
1004{ 1053{
1054 struct nand_chip *chip = mtd->priv;
1005 int ret; 1055 int ret;
1006 1056
1007 *retlen = 0;
1008 /* Do not allow reads past end of device */ 1057 /* Do not allow reads past end of device */
1009 if ((from + len) > mtd->size) 1058 if ((from + len) > mtd->size)
1010 return -EINVAL; 1059 return -EINVAL;
1011 if (!len) 1060 if (!len)
1012 return 0; 1061 return 0;
1013 1062
1014 nand_get_device(mtd->priv, mtd, FL_READING); 1063 nand_get_device(chip, mtd, FL_READING);
1015 1064
1016 ret = nand_do_read(mtd, from, len, retlen, buf); 1065 chip->ops.len = len;
1066 chip->ops.datbuf = buf;
1067 chip->ops.oobbuf = NULL;
1068
1069 ret = nand_do_read_ops(mtd, from, &chip->ops);
1017 1070
1018 nand_release_device(mtd); 1071 nand_release_device(mtd);
1019 1072
1073 *retlen = chip->ops.retlen;
1020 return ret; 1074 return ret;
1021} 1075}
1022 1076
1023/** 1077/**
1024 * nand_read_oob - [MTD Interface] NAND read out-of-band 1078 * nand_do_read_oob - [Intern] NAND read out-of-band
1025 * @mtd: MTD device structure 1079 * @mtd: MTD device structure
1026 * @from: offset to read from 1080 * @from: offset to read from
1027 * @len: number of bytes to read 1081 * @ops: oob operations description structure
1028 * @retlen: pointer to variable to store the number of read bytes
1029 * @buf: the databuffer to put data
1030 * 1082 *
1031 * NAND read out-of-band data from the spare area 1083 * NAND read out-of-band data from the spare area
1032 */ 1084 */
1033static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, 1085static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
1034 size_t *retlen, uint8_t *buf) 1086 struct mtd_oob_ops *ops)
1035{ 1087{
1036 int col, page, realpage, chipnr, sndcmd = 1; 1088 int col, page, realpage, chipnr, sndcmd = 1;
1037 struct nand_chip *chip = mtd->priv; 1089 struct nand_chip *chip = mtd->priv;
1038 int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; 1090 int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
1039 int readlen = len; 1091 int direct, bytes, readlen = ops->len;
1092 uint8_t *bufpoi, *buf = ops->oobbuf;
1040 1093
1041 DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", 1094 DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n",
1042 (unsigned int)from, (int)len); 1095 (unsigned int)from, (int)len);
1043 1096
1044 /* Initialize return length value */
1045 *retlen = 0;
1046
1047 /* Do not allow reads past end of device */
1048 if ((from + len) > mtd->size) {
1049 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
1050 "Attempt read beyond end of device\n");
1051 return -EINVAL;
1052 }
1053
1054 nand_get_device(chip, mtd, FL_READING);
1055
1056 chipnr = (int)(from >> chip->chip_shift); 1097 chipnr = (int)(from >> chip->chip_shift);
1057 chip->select_chip(mtd, chipnr); 1098 chip->select_chip(mtd, chipnr);
1058 1099
@@ -1060,20 +1101,31 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
1060 realpage = (int)(from >> chip->page_shift); 1101 realpage = (int)(from >> chip->page_shift);
1061 page = realpage & chip->pagemask; 1102 page = realpage & chip->pagemask;
1062 1103
1063 /* Mask to get column */ 1104 if (ops->mode != MTD_OOB_AUTO) {
1064 col = from & (mtd->oobsize - 1); 1105 col = ops->ooboffs;
1106 direct = 1;
1107 } else {
1108 col = 0;
1109 direct = 0;
1110 }
1065 1111
1066 while(1) { 1112 while(1) {
1067 int bytes = min((int)(mtd->oobsize - col), readlen); 1113 bytes = direct ? ops->ooblen : mtd->oobsize;
1114 bufpoi = direct ? buf : chip->buffers.oobrbuf;
1068 1115
1069 if (likely(sndcmd)) { 1116 if (likely(sndcmd)) {
1070 chip->cmdfunc(mtd, NAND_CMD_READOOB, col, page); 1117 chip->cmdfunc(mtd, NAND_CMD_READOOB, col, page);
1071 sndcmd = 0; 1118 sndcmd = 0;
1072 } 1119 }
1073 1120
1074 chip->read_buf(mtd, buf, bytes); 1121 chip->read_buf(mtd, bufpoi, bytes);
1075 1122
1076 readlen -= bytes; 1123 if (unlikely(!direct))
1124 buf = nand_transfer_oob(chip, buf, ops);
1125 else
1126 buf += ops->ooblen;
1127
1128 readlen -= ops->ooblen;
1077 if (!readlen) 1129 if (!readlen)
1078 break; 1130 break;
1079 1131
@@ -1090,10 +1142,6 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
1090 nand_wait_ready(mtd); 1142 nand_wait_ready(mtd);
1091 } 1143 }
1092 1144
1093 buf += bytes;
1094 bytes = mtd->oobsize;
1095 col = 0;
1096
1097 /* Increment page address */ 1145 /* Increment page address */
1098 realpage++; 1146 realpage++;
1099 1147
@@ -1112,81 +1160,76 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
1112 sndcmd = 1; 1160 sndcmd = 1;
1113 } 1161 }
1114 1162
1115 /* Deselect and wake up anyone waiting on the device */ 1163 ops->retlen = ops->len;
1116 nand_release_device(mtd);
1117
1118 *retlen = len;
1119 return 0; 1164 return 0;
1120} 1165}
1121 1166
1122/** 1167/**
1123 * nand_read_raw - [GENERIC] Read raw data including oob into buffer 1168 * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band
1124 * @mtd: MTD device structure 1169 * @mtd: MTD device structure
1125 * @buf: temporary buffer
1126 * @from: offset to read from 1170 * @from: offset to read from
1127 * @len: number of bytes to read 1171 * @ops: oob operation description structure
1128 * @ooblen: number of oob data bytes to read
1129 * 1172 *
1130 * Read raw data including oob into buffer 1173 * NAND read data and/or out-of-band data
1131 */ 1174 */
1132int nand_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, 1175static int nand_read_oob(struct mtd_info *mtd, loff_t from,
1133 size_t ooblen) 1176 struct mtd_oob_ops *ops)
1134{ 1177{
1178 int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
1179 uint8_t *buf) = NULL;
1135 struct nand_chip *chip = mtd->priv; 1180 struct nand_chip *chip = mtd->priv;
1136 int page = (int)(from >> chip->page_shift); 1181 int ret = -ENOTSUPP;
1137 int chipnr = (int)(from >> chip->chip_shift); 1182
1138 int sndcmd = 1; 1183 ops->retlen = 0;
1139 int cnt = 0;
1140 int pagesize = mtd->writesize + mtd->oobsize;
1141 int blockcheck;
1142 1184
1143 /* Do not allow reads past end of device */ 1185 /* Do not allow reads past end of device */
1144 if ((from + len) > mtd->size) { 1186 if ((from + ops->len) > mtd->size) {
1145 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: " 1187 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
1146 "Attempt read beyond end of device\n"); 1188 "Attempt read beyond end of device\n");
1147 return -EINVAL; 1189 return -EINVAL;
1148 } 1190 }
1149 1191
1150 /* Grab the lock and see if the device is available */
1151 nand_get_device(chip, mtd, FL_READING); 1192 nand_get_device(chip, mtd, FL_READING);
1152 1193
1153 chip->select_chip(mtd, chipnr); 1194 switch(ops->mode) {
1154 1195 case MTD_OOB_PLACE:
1155 /* Add requested oob length */ 1196 case MTD_OOB_AUTO:
1156 len += ooblen; 1197 break;
1157 blockcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
1158 1198
1159 while (len) { 1199 case MTD_OOB_RAW:
1160 if (likely(sndcmd)) { 1200 /* Replace the read_page algorithm temporary */
1161 chip->cmdfunc(mtd, NAND_CMD_READ0, 0, 1201 read_page = chip->ecc.read_page;
1162 page & chip->pagemask); 1202 chip->ecc.read_page = nand_read_page_raw;
1163 sndcmd = 0; 1203 break;
1164 }
1165 1204
1166 chip->read_buf(mtd, &buf[cnt], pagesize); 1205 default:
1206 goto out;
1207 }
1167 1208
1168 len -= pagesize; 1209 if (!ops->datbuf)
1169 cnt += pagesize; 1210 ret = nand_do_read_oob(mtd, from, ops);
1170 page++; 1211 else
1212 ret = nand_do_read_ops(mtd, from, ops);
1171 1213
1172 if (!(chip->options & NAND_NO_READRDY)) { 1214 if (unlikely(ops->mode == MTD_OOB_RAW))
1173 if (!chip->dev_ready) 1215 chip->ecc.read_page = read_page;
1174 udelay(chip->chip_delay); 1216 out:
1175 else 1217 nand_release_device(mtd);
1176 nand_wait_ready(mtd); 1218 return ret;
1177 } 1219}
1178 1220
1179 /*
1180 * Check, if the chip supports auto page increment or if we
1181 * cross a block boundary.
1182 */
1183 if (!NAND_CANAUTOINCR(chip) || !(page & blockcheck))
1184 sndcmd = 1;
1185 }
1186 1221
1187 /* Deselect and wake up anyone waiting on the device */ 1222/**
1188 nand_release_device(mtd); 1223 * nand_write_page_raw - [Intern] raw page write function
1189 return 0; 1224 * @mtd: mtd info structure
1225 * @chip: nand chip info structure
1226 * @buf: data buffer
1227 */
1228static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
1229 const uint8_t *buf)
1230{
1231 chip->write_buf(mtd, buf, mtd->writesize);
1232 chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
1190} 1233}
1191 1234
1192/** 1235/**
@@ -1205,17 +1248,14 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
1205 const uint8_t *p = buf; 1248 const uint8_t *p = buf;
1206 int *eccpos = chip->ecc.layout->eccpos; 1249 int *eccpos = chip->ecc.layout->eccpos;
1207 1250
1208 if (chip->ecc.mode != NAND_ECC_NONE) { 1251 /* Software ecc calculation */
1209 /* Software ecc calculation */ 1252 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
1210 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) 1253 chip->ecc.calculate(mtd, p, &ecc_calc[i]);
1211 chip->ecc.calculate(mtd, p, &ecc_calc[i]);
1212 1254
1213 for (i = 0; i < chip->ecc.total; i++) 1255 for (i = 0; i < chip->ecc.total; i++)
1214 chip->oob_poi[eccpos[i]] = ecc_calc[i]; 1256 chip->oob_poi[eccpos[i]] = ecc_calc[i];
1215 }
1216 1257
1217 chip->write_buf(mtd, buf, mtd->writesize); 1258 nand_write_page_raw(mtd, chip, buf);
1218 chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
1219} 1259}
1220 1260
1221/** 1261/**
@@ -1342,51 +1382,77 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
1342 return 0; 1382 return 0;
1343} 1383}
1344 1384
1385/**
1386 * nand_fill_oob - [Internal] Transfer client buffer to oob
1387 * @chip: nand chip structure
1388 * @oob: oob data buffer
1389 * @ops: oob ops structure
1390 */
1391static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
1392 struct mtd_oob_ops *ops)
1393{
1394 size_t len = ops->ooblen;
1395
1396 switch(ops->mode) {
1397
1398 case MTD_OOB_PLACE:
1399 case MTD_OOB_RAW:
1400 memcpy(chip->oob_poi + ops->ooboffs, oob, len);
1401 return oob + len;
1402
1403 case MTD_OOB_AUTO: {
1404 struct nand_oobfree *free = chip->ecc.layout->oobfree;
1405 size_t bytes;
1406
1407 for(; free->length && len; free++, len -= bytes) {
1408 bytes = min(len, free->length);
1409 memcpy(chip->oob_poi + free->offset, oob, bytes);
1410 oob += bytes;
1411 }
1412 return oob;
1413 }
1414 default:
1415 BUG();
1416 }
1417 return NULL;
1418}
1419
1345#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0 1420#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
1346 1421
1347/** 1422/**
1348 * nand_write - [MTD Interface] NAND write with ECC 1423 * nand_do_write_ops - [Internal] NAND write with ECC
1349 * @mtd: MTD device structure 1424 * @mtd: MTD device structure
1350 * @to: offset to write to 1425 * @to: offset to write to
1351 * @len: number of bytes to write 1426 * @ops: oob operations description structure
1352 * @retlen: pointer to variable to store the number of written bytes
1353 * @buf: the data to write
1354 * 1427 *
1355 * NAND write with ECC 1428 * NAND write with ECC
1356 */ 1429 */
1357static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, 1430static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
1358 size_t *retlen, const uint8_t *buf) 1431 struct mtd_oob_ops *ops)
1359{ 1432{
1360 int chipnr, realpage, page, blockmask; 1433 int chipnr, realpage, page, blockmask;
1361 struct nand_chip *chip = mtd->priv; 1434 struct nand_chip *chip = mtd->priv;
1362 uint32_t writelen = len; 1435 uint32_t writelen = ops->len;
1436 uint8_t *oob = ops->oobbuf;
1437 uint8_t *buf = ops->datbuf;
1363 int bytes = mtd->writesize; 1438 int bytes = mtd->writesize;
1364 int ret = -EIO; 1439 int ret;
1365 1440
1366 *retlen = 0; 1441 ops->retlen = 0;
1367
1368 /* Do not allow write past end of device */
1369 if ((to + len) > mtd->size) {
1370 DEBUG(MTD_DEBUG_LEVEL0, "nand_write: "
1371 "Attempt to write past end of page\n");
1372 return -EINVAL;
1373 }
1374 1442
1375 /* reject writes, which are not page aligned */ 1443 /* reject writes, which are not page aligned */
1376 if (NOTALIGNED(to) || NOTALIGNED(len)) { 1444 if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
1377 printk(KERN_NOTICE "nand_write: " 1445 printk(KERN_NOTICE "nand_write: "
1378 "Attempt to write not page aligned data\n"); 1446 "Attempt to write not page aligned data\n");
1379 return -EINVAL; 1447 return -EINVAL;
1380 } 1448 }
1381 1449
1382 if (!len) 1450 if (!writelen)
1383 return 0; 1451 return 0;
1384 1452
1385 nand_get_device(chip, mtd, FL_WRITING);
1386
1387 /* Check, if it is write protected */ 1453 /* Check, if it is write protected */
1388 if (nand_check_wp(mtd)) 1454 if (nand_check_wp(mtd))
1389 goto out; 1455 return -EIO;
1390 1456
1391 chipnr = (int)(to >> chip->chip_shift); 1457 chipnr = (int)(to >> chip->chip_shift);
1392 chip->select_chip(mtd, chipnr); 1458 chip->select_chip(mtd, chipnr);
@@ -1397,7 +1463,7 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
1397 1463
1398 /* Invalidate the page cache, when we write to the cached page */ 1464 /* Invalidate the page cache, when we write to the cached page */
1399 if (to <= (chip->pagebuf << chip->page_shift) && 1465 if (to <= (chip->pagebuf << chip->page_shift) &&
1400 (chip->pagebuf << chip->page_shift) < (to + len)) 1466 (chip->pagebuf << chip->page_shift) < (to + ops->len))
1401 chip->pagebuf = -1; 1467 chip->pagebuf = -1;
1402 1468
1403 chip->oob_poi = chip->buffers.oobwbuf; 1469 chip->oob_poi = chip->buffers.oobwbuf;
@@ -1405,6 +1471,9 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
1405 while(1) { 1471 while(1) {
1406 int cached = writelen > bytes && page != blockmask; 1472 int cached = writelen > bytes && page != blockmask;
1407 1473
1474 if (unlikely(oob))
1475 oob = nand_fill_oob(chip, oob, ops);
1476
1408 ret = nand_write_page(mtd, chip, buf, page, cached); 1477 ret = nand_write_page(mtd, chip, buf, page, cached);
1409 if (ret) 1478 if (ret)
1410 break; 1479 break;
@@ -1424,94 +1493,74 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
1424 chip->select_chip(mtd, chipnr); 1493 chip->select_chip(mtd, chipnr);
1425 } 1494 }
1426 } 1495 }
1427 out: 1496
1428 *retlen = len - writelen; 1497 if (unlikely(oob))
1429 nand_release_device(mtd); 1498 memset(chip->oob_poi, 0xff, mtd->oobsize);
1499
1500 ops->retlen = ops->len - writelen;
1430 return ret; 1501 return ret;
1431} 1502}
1432 1503
1433/** 1504/**
1434 * nand_write_raw - [GENERIC] Write raw data including oob 1505 * nand_write - [MTD Interface] NAND write with ECC
1435 * @mtd: MTD device structure 1506 * @mtd: MTD device structure
1436 * @buf: source buffer
1437 * @to: offset to write to 1507 * @to: offset to write to
1438 * @len: number of bytes to write 1508 * @len: number of bytes to write
1439 * @buf: source buffer 1509 * @retlen: pointer to variable to store the number of written bytes
1440 * @oob: oob buffer 1510 * @buf: the data to write
1441 * 1511 *
1442 * Write raw data including oob 1512 * NAND write with ECC
1443 */ 1513 */
1444int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, 1514static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
1445 const uint8_t *buf, uint8_t *oob) 1515 size_t *retlen, const uint8_t *buf)
1446{ 1516{
1447 struct nand_chip *chip = mtd->priv; 1517 struct nand_chip *chip = mtd->priv;
1448 int page = (int)(to >> chip->page_shift);
1449 int chipnr = (int)(to >> chip->chip_shift);
1450 int ret; 1518 int ret;
1451 1519
1452 *retlen = 0; 1520 /* Do not allow reads past end of device */
1453 1521 if ((to + len) > mtd->size)
1454 /* Do not allow writes past end of device */
1455 if ((to + len) > mtd->size) {
1456 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt write "
1457 "beyond end of device\n");
1458 return -EINVAL; 1522 return -EINVAL;
1459 } 1523 if (!len)
1524 return 0;
1460 1525
1461 /* Grab the lock and see if the device is available */ 1526 nand_get_device(chip, mtd, FL_READING);
1462 nand_get_device(chip, mtd, FL_WRITING);
1463 1527
1464 chip->select_chip(mtd, chipnr); 1528 chip->ops.len = len;
1465 chip->oob_poi = oob; 1529 chip->ops.datbuf = (uint8_t *)buf;
1530 chip->ops.oobbuf = NULL;
1466 1531
1467 while (len != *retlen) { 1532 ret = nand_do_write_ops(mtd, to, &chip->ops);
1468 ret = nand_write_page(mtd, chip, buf, page, 0);
1469 if (ret)
1470 return ret;
1471 page++;
1472 *retlen += mtd->writesize;
1473 buf += mtd->writesize;
1474 chip->oob_poi += mtd->oobsize;
1475 }
1476 1533
1477 /* Deselect and wake up anyone waiting on the device */
1478 nand_release_device(mtd); 1534 nand_release_device(mtd);
1479 return 0; 1535
1536 *retlen = chip->ops.retlen;
1537 return ret;
1480} 1538}
1481EXPORT_SYMBOL_GPL(nand_write_raw);
1482 1539
1483/** 1540/**
1484 * nand_write_oob - [MTD Interface] NAND write out-of-band 1541 * nand_do_write_oob - [MTD Interface] NAND write out-of-band
1485 * @mtd: MTD device structure 1542 * @mtd: MTD device structure
1486 * @to: offset to write to 1543 * @to: offset to write to
1487 * @len: number of bytes to write 1544 * @ops: oob operation description structure
1488 * @retlen: pointer to variable to store the number of written bytes
1489 * @buf: the data to write
1490 * 1545 *
1491 * NAND write out-of-band 1546 * NAND write out-of-band
1492 */ 1547 */
1493static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, 1548static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
1494 size_t *retlen, const uint8_t *buf) 1549 struct mtd_oob_ops *ops)
1495{ 1550{
1496 int column, page, status, ret = -EIO, chipnr; 1551 int chipnr, page, status;
1497 struct nand_chip *chip = mtd->priv; 1552 struct nand_chip *chip = mtd->priv;
1498 1553
1499 DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", 1554 DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
1500 (unsigned int)to, (int)len); 1555 (unsigned int)to, (int)ops->len);
1501
1502 /* Initialize return length value */
1503 *retlen = 0;
1504 1556
1505 /* Do not allow write past end of page */ 1557 /* Do not allow write past end of page */
1506 column = to & (mtd->oobsize - 1); 1558 if ((ops->ooboffs + ops->len) > mtd->oobsize) {
1507 if ((column + len) > mtd->oobsize) {
1508 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " 1559 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
1509 "Attempt to write past end of page\n"); 1560 "Attempt to write past end of page\n");
1510 return -EINVAL; 1561 return -EINVAL;
1511 } 1562 }
1512 1563
1513 nand_get_device(chip, mtd, FL_WRITING);
1514
1515 chipnr = (int)(to >> chip->chip_shift); 1564 chipnr = (int)(to >> chip->chip_shift);
1516 chip->select_chip(mtd, chipnr); 1565 chip->select_chip(mtd, chipnr);
1517 1566
@@ -1528,26 +1577,27 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
1528 1577
1529 /* Check, if it is write protected */ 1578 /* Check, if it is write protected */
1530 if (nand_check_wp(mtd)) 1579 if (nand_check_wp(mtd))
1531 goto out; 1580 return -EROFS;
1532 1581
1533 /* Invalidate the page cache, if we write to the cached page */ 1582 /* Invalidate the page cache, if we write to the cached page */
1534 if (page == chip->pagebuf) 1583 if (page == chip->pagebuf)
1535 chip->pagebuf = -1; 1584 chip->pagebuf = -1;
1536 1585
1537 if (NAND_MUST_PAD(chip)) { 1586 if (ops->mode == MTD_OOB_AUTO || NAND_MUST_PAD(chip)) {
1587 chip->oob_poi = chip->buffers.oobwbuf;
1588 memset(chip->oob_poi, 0xff, mtd->oobsize);
1589 nand_fill_oob(chip, ops->oobbuf, ops);
1538 chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, 1590 chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize,
1539 page & chip->pagemask); 1591 page & chip->pagemask);
1540 /* prepad 0xff for partial programming */ 1592 chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
1541 chip->write_buf(mtd, ffchars, column); 1593 memset(chip->oob_poi, 0xff, mtd->oobsize);
1542 /* write data */
1543 chip->write_buf(mtd, buf, len);
1544 /* postpad 0xff for partial programming */
1545 chip->write_buf(mtd, ffchars, mtd->oobsize - (len + column));
1546 } else { 1594 } else {
1547 chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + column, 1595 chip->cmdfunc(mtd, NAND_CMD_SEQIN,
1596 mtd->writesize + ops->ooboffs,
1548 page & chip->pagemask); 1597 page & chip->pagemask);
1549 chip->write_buf(mtd, buf, len); 1598 chip->write_buf(mtd, ops->oobbuf, ops->len);
1550 } 1599 }
1600
1551 /* Send command to program the OOB data */ 1601 /* Send command to program the OOB data */
1552 chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); 1602 chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
1553 1603
@@ -1557,27 +1607,75 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
1557 if (status & NAND_STATUS_FAIL) { 1607 if (status & NAND_STATUS_FAIL) {
1558 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " 1608 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
1559 "Failed write, page 0x%08x\n", page); 1609 "Failed write, page 0x%08x\n", page);
1560 ret = -EIO; 1610 return -EIO;
1561 goto out;
1562 } 1611 }
1563 *retlen = len; 1612 ops->retlen = ops->len;
1564 1613
1565#ifdef CONFIG_MTD_NAND_VERIFY_WRITE 1614#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
1566 /* Send command to read back the data */ 1615 if (ops->mode != MTD_OOB_AUTO) {
1567 chip->cmdfunc(mtd, NAND_CMD_READOOB, column, page & chip->pagemask); 1616 /* Send command to read back the data */
1617 chip->cmdfunc(mtd, NAND_CMD_READOOB, ops->ooboffs,
1618 page & chip->pagemask);
1568 1619
1569 if (chip->verify_buf(mtd, buf, len)) { 1620 if (chip->verify_buf(mtd, ops->oobbuf, ops->len)) {
1570 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " 1621 DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
1571 "Failed write verify, page 0x%08x\n", page); 1622 "Failed write verify, page 0x%08x\n", page);
1572 ret = -EIO; 1623 return -EIO;
1573 goto out; 1624 }
1574 } 1625 }
1575#endif 1626#endif
1576 ret = 0; 1627 return 0;
1628}
1629
1630/**
1631 * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
1632 * @mtd: MTD device structure
1633 * @from: offset to read from
1634 * @ops: oob operation description structure
1635 */
1636static int nand_write_oob(struct mtd_info *mtd, loff_t to,
1637 struct mtd_oob_ops *ops)
1638{
1639 void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
1640 const uint8_t *buf) = NULL;
1641 struct nand_chip *chip = mtd->priv;
1642 int ret = -ENOTSUPP;
1643
1644 ops->retlen = 0;
1645
1646 /* Do not allow writes past end of device */
1647 if ((to + ops->len) > mtd->size) {
1648 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
1649 "Attempt read beyond end of device\n");
1650 return -EINVAL;
1651 }
1652
1653 nand_get_device(chip, mtd, FL_READING);
1654
1655 switch(ops->mode) {
1656 case MTD_OOB_PLACE:
1657 case MTD_OOB_AUTO:
1658 break;
1659
1660 case MTD_OOB_RAW:
1661 /* Replace the write_page algorithm temporary */
1662 write_page = chip->ecc.write_page;
1663 chip->ecc.write_page = nand_write_page_raw;
1664 break;
1665
1666 default:
1667 goto out;
1668 }
1669
1670 if (!ops->datbuf)
1671 ret = nand_do_write_oob(mtd, to, ops);
1672 else
1673 ret = nand_do_write_ops(mtd, to, ops);
1674
1675 if (unlikely(ops->mode == MTD_OOB_RAW))
1676 chip->ecc.write_page = write_page;
1577 out: 1677 out:
1578 /* Deselect and wake up anyone waiting on the device */
1579 nand_release_device(mtd); 1678 nand_release_device(mtd);
1580
1581 return ret; 1679 return ret;
1582} 1680}
1583 1681
@@ -2191,8 +2289,8 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
2191 case NAND_ECC_NONE: 2289 case NAND_ECC_NONE:
2192 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " 2290 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
2193 "This is not recommended !!\n"); 2291 "This is not recommended !!\n");
2194 chip->ecc.read_page = nand_read_page_swecc; 2292 chip->ecc.read_page = nand_read_page_raw;
2195 chip->ecc.write_page = nand_write_page_swecc; 2293 chip->ecc.write_page = nand_write_page_raw;
2196 chip->ecc.size = mtd->writesize; 2294 chip->ecc.size = mtd->writesize;
2197 chip->ecc.bytes = 0; 2295 chip->ecc.bytes = 0;
2198 break; 2296 break;
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 40f99304df76..480c3cbf9bf9 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -230,6 +230,42 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
230 return 0; 230 return 0;
231} 231}
232 232
233/*
234 * Scan read raw data from flash
235 */
236static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
237 size_t len)
238{
239 struct mtd_oob_ops ops;
240
241 ops.mode = MTD_OOB_RAW;
242 ops.ooboffs = 0;
243 ops.ooblen = mtd->oobsize;
244 ops.oobbuf = buf;
245 ops.datbuf = buf;
246 ops.len = len;
247
248 return mtd->read_oob(mtd, offs, &ops);
249}
250
251/*
252 * Scan write data with oob to flash
253 */
254static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,
255 uint8_t *buf, uint8_t *oob)
256{
257 struct mtd_oob_ops ops;
258
259 ops.mode = MTD_OOB_PLACE;
260 ops.ooboffs = 0;
261 ops.ooblen = mtd->oobsize;
262 ops.datbuf = buf;
263 ops.oobbuf = oob;
264 ops.len = len;
265
266 return mtd->write_oob(mtd, offs, &ops);
267}
268
233/** 269/**
234 * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page 270 * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
235 * @mtd: MTD device structure 271 * @mtd: MTD device structure
@@ -241,27 +277,85 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
241 * We assume that the bbt bits are in consecutive order. 277 * We assume that the bbt bits are in consecutive order.
242 * 278 *
243*/ 279*/
244static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) 280static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
281 struct nand_bbt_descr *td, struct nand_bbt_descr *md)
245{ 282{
246 struct nand_chip *this = mtd->priv; 283 struct nand_chip *this = mtd->priv;
247 284
248 /* Read the primary version, if available */ 285 /* Read the primary version, if available */
249 if (td->options & NAND_BBT_VERSION) { 286 if (td->options & NAND_BBT_VERSION) {
250 nand_read_raw(mtd, buf, td->pages[0] << this->page_shift, mtd->writesize, mtd->oobsize); 287 scan_read_raw(mtd, buf, td->pages[0] << this->page_shift,
288 mtd->writesize);
251 td->version[0] = buf[mtd->writesize + td->veroffs]; 289 td->version[0] = buf[mtd->writesize + td->veroffs];
252 printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); 290 printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
291 td->pages[0], td->version[0]);
253 } 292 }
254 293
255 /* Read the mirror version, if available */ 294 /* Read the mirror version, if available */
256 if (md && (md->options & NAND_BBT_VERSION)) { 295 if (md && (md->options & NAND_BBT_VERSION)) {
257 nand_read_raw(mtd, buf, md->pages[0] << this->page_shift, mtd->writesize, mtd->oobsize); 296 scan_read_raw(mtd, buf, md->pages[0] << this->page_shift,
297 mtd->writesize);
258 md->version[0] = buf[mtd->writesize + md->veroffs]; 298 md->version[0] = buf[mtd->writesize + md->veroffs];
259 printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); 299 printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
300 md->pages[0], md->version[0]);
260 } 301 }
261
262 return 1; 302 return 1;
263} 303}
264 304
305/*
306 * Scan a given block full
307 */
308static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
309 loff_t offs, uint8_t *buf, size_t readlen,
310 int scanlen, int len)
311{
312 int ret, j;
313
314 ret = scan_read_raw(mtd, buf, offs, readlen);
315 if (ret)
316 return ret;
317
318 for (j = 0; j < len; j++, buf += scanlen) {
319 if (check_pattern(buf, scanlen, mtd->writesize, bd))
320 return 1;
321 }
322 return 0;
323}
324
325/*
326 * Scan a given block partially
327 */
328static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
329 loff_t offs, uint8_t *buf, int len)
330{
331 struct mtd_oob_ops ops;
332 int j, ret;
333
334 ops.len = mtd->oobsize;
335 ops.ooblen = mtd->oobsize;
336 ops.oobbuf = buf;
337 ops.ooboffs = 0;
338 ops.datbuf = NULL;
339 ops.mode = MTD_OOB_PLACE;
340
341 for (j = 0; j < len; j++) {
342 /*
343 * Read the full oob until read_oob is fixed to
344 * handle single byte reads for 16 bit
345 * buswidth
346 */
347 ret = mtd->read_oob(mtd, offs, &ops);
348 if (ret)
349 return ret;
350
351 if (check_short_pattern(buf, bd))
352 return 1;
353
354 offs += mtd->writesize;
355 }
356 return 0;
357}
358
265/** 359/**
266 * create_bbt - [GENERIC] Create a bad block table by scanning the device 360 * create_bbt - [GENERIC] Create a bad block table by scanning the device
267 * @mtd: MTD device structure 361 * @mtd: MTD device structure
@@ -273,13 +367,14 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
273 * Create a bad block table by scanning the device 367 * Create a bad block table by scanning the device
274 * for the given good/bad block identify pattern 368 * for the given good/bad block identify pattern
275 */ 369 */
276static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) 370static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
371 struct nand_bbt_descr *bd, int chip)
277{ 372{
278 struct nand_chip *this = mtd->priv; 373 struct nand_chip *this = mtd->priv;
279 int i, j, numblocks, len, scanlen; 374 int i, numblocks, len, scanlen;
280 int startblock; 375 int startblock;
281 loff_t from; 376 loff_t from;
282 size_t readlen, ooblen; 377 size_t readlen;
283 378
284 printk(KERN_INFO "Scanning device for bad blocks\n"); 379 printk(KERN_INFO "Scanning device for bad blocks\n");
285 380
@@ -294,18 +389,17 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
294 389
295 if (!(bd->options & NAND_BBT_SCANEMPTY)) { 390 if (!(bd->options & NAND_BBT_SCANEMPTY)) {
296 /* We need only read few bytes from the OOB area */ 391 /* We need only read few bytes from the OOB area */
297 scanlen = ooblen = 0; 392 scanlen = 0;
298 readlen = bd->len; 393 readlen = bd->len;
299 } else { 394 } else {
300 /* Full page content should be read */ 395 /* Full page content should be read */
301 scanlen = mtd->writesize + mtd->oobsize; 396 scanlen = mtd->writesize + mtd->oobsize;
302 readlen = len * mtd->writesize; 397 readlen = len * mtd->writesize;
303 ooblen = len * mtd->oobsize;
304 } 398 }
305 399
306 if (chip == -1) { 400 if (chip == -1) {
307 /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it 401 /* Note that numblocks is 2 * (real numblocks) here, see i+=2
308 * makes shifting and masking less painful */ 402 * below as it makes shifting and masking less painful */
309 numblocks = mtd->size >> (this->bbt_erase_shift - 1); 403 numblocks = mtd->size >> (this->bbt_erase_shift - 1);
310 startblock = 0; 404 startblock = 0;
311 from = 0; 405 from = 0;
@@ -324,35 +418,21 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
324 for (i = startblock; i < numblocks;) { 418 for (i = startblock; i < numblocks;) {
325 int ret; 419 int ret;
326 420
327 if (bd->options & NAND_BBT_SCANEMPTY) 421 if (bd->options & NAND_BBT_SCANALLPAGES)
328 if ((ret = nand_read_raw(mtd, buf, from, readlen, ooblen))) 422 ret = scan_block_full(mtd, bd, from, buf, readlen,
329 return ret; 423 scanlen, len);
330 424 else
331 for (j = 0; j < len; j++) { 425 ret = scan_block_fast(mtd, bd, from, buf, len);
332 if (!(bd->options & NAND_BBT_SCANEMPTY)) { 426
333 size_t retlen; 427 if (ret < 0)
334 428 return ret;
335 /* Read the full oob until read_oob is fixed to 429
336 * handle single byte reads for 16 bit buswidth */ 430 if (ret) {
337 ret = mtd->read_oob(mtd, from + j * mtd->writesize, mtd->oobsize, &retlen, buf); 431 this->bbt[i >> 3] |= 0x03 << (i & 0x6);
338 if (ret) 432 printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
339 return ret; 433 i >> 1, (unsigned int)from);
340
341 if (check_short_pattern(buf, bd)) {
342 this->bbt[i >> 3] |= 0x03 << (i & 0x6);
343 printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
344 i >> 1, (unsigned int)from);
345 break;
346 }
347 } else {
348 if (check_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
349 this->bbt[i >> 3] |= 0x03 << (i & 0x6);
350 printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
351 i >> 1, (unsigned int)from);
352 break;
353 }
354 }
355 } 434 }
435
356 i += 2; 436 i += 2;
357 from += (1 << this->bbt_erase_shift); 437 from += (1 << this->bbt_erase_shift);
358 } 438 }
@@ -383,6 +463,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
383 int bits, startblock, block, dir; 463 int bits, startblock, block, dir;
384 int scanlen = mtd->writesize + mtd->oobsize; 464 int scanlen = mtd->writesize + mtd->oobsize;
385 int bbtblocks; 465 int bbtblocks;
466 int blocktopage = this->bbt_erase_shift - this->page_shift;
386 467
387 /* Search direction top -> down ? */ 468 /* Search direction top -> down ? */
388 if (td->options & NAND_BBT_LASTBLOCK) { 469 if (td->options & NAND_BBT_LASTBLOCK) {
@@ -412,11 +493,14 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
412 td->pages[i] = -1; 493 td->pages[i] = -1;
413 /* Scan the maximum number of blocks */ 494 /* Scan the maximum number of blocks */
414 for (block = 0; block < td->maxblocks; block++) { 495 for (block = 0; block < td->maxblocks; block++) {
496
415 int actblock = startblock + dir * block; 497 int actblock = startblock + dir * block;
498 loff_t offs = actblock << this->bbt_erase_shift;
499
416 /* Read first page */ 500 /* Read first page */
417 nand_read_raw(mtd, buf, actblock << this->bbt_erase_shift, mtd->writesize, mtd->oobsize); 501 scan_read_raw(mtd, buf, offs, mtd->writesize);
418 if (!check_pattern(buf, scanlen, mtd->writesize, td)) { 502 if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
419 td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift); 503 td->pages[i] = actblock << blocktopage;
420 if (td->options & NAND_BBT_VERSION) { 504 if (td->options & NAND_BBT_VERSION) {
421 td->version[i] = buf[mtd->writesize + td->veroffs]; 505 td->version[i] = buf[mtd->writesize + td->veroffs];
422 } 506 }
@@ -481,8 +565,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
481 int nrchips, bbtoffs, pageoffs, ooboffs; 565 int nrchips, bbtoffs, pageoffs, ooboffs;
482 uint8_t msk[4]; 566 uint8_t msk[4];
483 uint8_t rcode = td->reserved_block_code; 567 uint8_t rcode = td->reserved_block_code;
484 size_t retlen, len = 0, ooblen; 568 size_t retlen, len = 0;
485 loff_t to; 569 loff_t to;
570 struct mtd_oob_ops ops;
571
572 ops.ooblen = mtd->oobsize;
573 ops.ooboffs = 0;
574 ops.datbuf = NULL;
575 ops.mode = MTD_OOB_PLACE;
486 576
487 if (!rcode) 577 if (!rcode)
488 rcode = 0xff; 578 rcode = 0xff;
@@ -583,10 +673,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
583 "bad block table\n"); 673 "bad block table\n");
584 } 674 }
585 /* Read oob data */ 675 /* Read oob data */
586 ooblen = (len >> this->page_shift) * mtd->oobsize; 676 ops.len = (len >> this->page_shift) * mtd->oobsize;
587 res = mtd->read_oob(mtd, to + mtd->writesize, ooblen, 677 ops.oobbuf = &buf[len];
588 &retlen, &buf[len]); 678 res = mtd->read_oob(mtd, to + mtd->writesize, &ops);
589 if (res < 0 || retlen != ooblen) 679 if (res < 0 || ops.retlen != ops.len)
590 goto outerr; 680 goto outerr;
591 681
592 /* Calc the byte offset in the buffer */ 682 /* Calc the byte offset in the buffer */
@@ -635,7 +725,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
635 if (res < 0) 725 if (res < 0)
636 goto outerr; 726 goto outerr;
637 727
638 res = nand_write_raw(mtd, to, len, &retlen, buf, &buf[len]); 728 res = scan_write_bbt(mtd, to, len, buf, &buf[len]);
639 if (res < 0) 729 if (res < 0)
640 goto outerr; 730 goto outerr;
641 731
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index 359533b33d9b..f6ffe7949b26 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -134,6 +134,69 @@ static void nftl_remove_dev(struct mtd_blktrans_dev *dev)
134 kfree(nftl); 134 kfree(nftl);
135} 135}
136 136
137/*
138 * Read oob data from flash
139 */
140int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
141 size_t *retlen, uint8_t *buf)
142{
143 struct mtd_oob_ops ops;
144 int res;
145
146 ops.mode = MTD_OOB_PLACE;
147 ops.ooboffs = offs & (mtd->writesize - 1);
148 ops.ooblen = len;
149 ops.oobbuf = buf;
150 ops.datbuf = NULL;
151 ops.len = len;
152
153 res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
154 *retlen = ops.retlen;
155 return res;
156}
157
158/*
159 * Write oob data to flash
160 */
161int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
162 size_t *retlen, uint8_t *buf)
163{
164 struct mtd_oob_ops ops;
165 int res;
166
167 ops.mode = MTD_OOB_PLACE;
168 ops.ooboffs = offs & (mtd->writesize - 1);
169 ops.ooblen = len;
170 ops.oobbuf = buf;
171 ops.datbuf = NULL;
172 ops.len = len;
173
174 res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
175 *retlen = ops.retlen;
176 return res;
177}
178
179/*
180 * Write data and oob to flash
181 */
182static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
183 size_t *retlen, uint8_t *buf, uint8_t *oob)
184{
185 struct mtd_oob_ops ops;
186 int res;
187
188 ops.mode = MTD_OOB_PLACE;
189 ops.ooboffs = offs;
190 ops.ooblen = mtd->oobsize;
191 ops.oobbuf = oob;
192 ops.datbuf = buf;
193 ops.len = len;
194
195 res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
196 *retlen = ops.retlen;
197 return res;
198}
199
137#ifdef CONFIG_NFTL_RW 200#ifdef CONFIG_NFTL_RW
138 201
139/* Actual NFTL access routines */ 202/* Actual NFTL access routines */
@@ -216,7 +279,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
216 279
217 targetEUN = thisEUN; 280 targetEUN = thisEUN;
218 for (block = 0; block < nftl->EraseSize / 512; block ++) { 281 for (block = 0; block < nftl->EraseSize / 512; block ++) {
219 mtd->read_oob(mtd, (thisEUN * nftl->EraseSize) + 282 nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
220 (block * 512), 16 , &retlen, 283 (block * 512), 16 , &retlen,
221 (char *)&oob); 284 (char *)&oob);
222 if (block == 2) { 285 if (block == 2) {
@@ -333,7 +396,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
333 longer one */ 396 longer one */
334 oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS); 397 oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
335 oob.u.c.unused = 0xffffffff; 398 oob.u.c.unused = 0xffffffff;
336 mtd->write_oob(mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, 399 nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
337 8, &retlen, (char *)&oob.u); 400 8, &retlen, (char *)&oob.u);
338 } 401 }
339 402
@@ -369,17 +432,15 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
369 memset(&oob, 0xff, sizeof(struct nftl_oob)); 432 memset(&oob, 0xff, sizeof(struct nftl_oob));
370 oob.b.Status = oob.b.Status1 = SECTOR_USED; 433 oob.b.Status = oob.b.Status1 = SECTOR_USED;
371 434
372 nand_write_raw(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 435 nftl_write(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) +
373 (block * 512), 512, &retlen, movebuf, 436 (block * 512), 512, &retlen, movebuf, (char *)&oob);
374 (char *)&oob);
375
376 } 437 }
377 438
378 /* add the header so that it is now a valid chain */ 439 /* add the header so that it is now a valid chain */
379 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC); 440 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
380 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff; 441 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
381 442
382 mtd->write_oob(mtd, (nftl->EraseSize * targetEUN) + 8, 443 nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 8,
383 8, &retlen, (char *)&oob.u); 444 8, &retlen, (char *)&oob.u);
384 445
385 /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */ 446 /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
@@ -499,7 +560,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
499 560
500 lastEUN = writeEUN; 561 lastEUN = writeEUN;
501 562
502 mtd->read_oob(mtd, 563 nftl_read_oob(mtd,
503 (writeEUN * nftl->EraseSize) + blockofs, 564 (writeEUN * nftl->EraseSize) + blockofs,
504 8, &retlen, (char *)&bci); 565 8, &retlen, (char *)&bci);
505 566
@@ -588,12 +649,12 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
588 nftl->ReplUnitTable[writeEUN] = BLOCK_NIL; 649 nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
589 650
590 /* ... and on the flash itself */ 651 /* ... and on the flash itself */
591 mtd->read_oob(mtd, writeEUN * nftl->EraseSize + 8, 8, 652 nftl_read_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
592 &retlen, (char *)&oob.u); 653 &retlen, (char *)&oob.u);
593 654
594 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC); 655 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
595 656
596 mtd->write_oob(mtd, writeEUN * nftl->EraseSize + 8, 8, 657 nftl_write_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
597 &retlen, (char *)&oob.u); 658 &retlen, (char *)&oob.u);
598 659
599 /* we link the new block to the chain only after the 660 /* we link the new block to the chain only after the
@@ -603,13 +664,13 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
603 /* Both in our cache... */ 664 /* Both in our cache... */
604 nftl->ReplUnitTable[lastEUN] = writeEUN; 665 nftl->ReplUnitTable[lastEUN] = writeEUN;
605 /* ... and on the flash itself */ 666 /* ... and on the flash itself */
606 mtd->read_oob(mtd, (lastEUN * nftl->EraseSize) + 8, 667 nftl_read_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
607 8, &retlen, (char *)&oob.u); 668 8, &retlen, (char *)&oob.u);
608 669
609 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum 670 oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
610 = cpu_to_le16(writeEUN); 671 = cpu_to_le16(writeEUN);
611 672
612 mtd->write_oob(mtd, (lastEUN * nftl->EraseSize) + 8, 673 nftl_write_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
613 8, &retlen, (char *)&oob.u); 674 8, &retlen, (char *)&oob.u);
614 } 675 }
615 676
@@ -643,9 +704,8 @@ static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
643 memset(&oob, 0xff, sizeof(struct nftl_oob)); 704 memset(&oob, 0xff, sizeof(struct nftl_oob));
644 oob.b.Status = oob.b.Status1 = SECTOR_USED; 705 oob.b.Status = oob.b.Status1 = SECTOR_USED;
645 706
646 nand_write_raw(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + 707 nftl_write(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
647 blockofs, 512, &retlen, (char *)buffer, 708 512, &retlen, (char *)buffer, (char *)&oob);
648 (char *)&oob);
649 return 0; 709 return 0;
650} 710}
651#endif /* CONFIG_NFTL_RW */ 711#endif /* CONFIG_NFTL_RW */
@@ -667,7 +727,7 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
667 727
668 if (thisEUN != BLOCK_NIL) { 728 if (thisEUN != BLOCK_NIL) {
669 while (thisEUN < nftl->nb_blocks) { 729 while (thisEUN < nftl->nb_blocks) {
670 if (mtd->read_oob(mtd, (thisEUN * nftl->EraseSize) + 730 if (nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
671 blockofs, 8, &retlen, 731 blockofs, 8, &retlen,
672 (char *)&bci) < 0) 732 (char *)&bci) < 0)
673 status = SECTOR_IGNORE; 733 status = SECTOR_IGNORE;
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c
index 521b07cd2326..067262ee8df0 100644
--- a/drivers/mtd/nftlmount.c
+++ b/drivers/mtd/nftlmount.c
@@ -33,6 +33,11 @@
33 33
34char nftlmountrev[]="$Revision: 1.41 $"; 34char nftlmountrev[]="$Revision: 1.41 $";
35 35
36extern int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
37 size_t *retlen, uint8_t *buf);
38extern int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
39 size_t *retlen, uint8_t *buf);
40
36/* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the 41/* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
37 * various device information of the NFTL partition and Bad Unit Table. Update 42 * various device information of the NFTL partition and Bad Unit Table. Update
38 * the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[] 43 * the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[]
@@ -92,7 +97,7 @@ static int find_boot_record(struct NFTLrecord *nftl)
92 } 97 }
93 98
94 /* To be safer with BIOS, also use erase mark as discriminant */ 99 /* To be safer with BIOS, also use erase mark as discriminant */
95 if ((ret = mtd->read_oob(mtd, block * nftl->EraseSize + 100 if ((ret = nftl_read_oob(mtd, block * nftl->EraseSize +
96 SECTORSIZE + 8, 8, &retlen, 101 SECTORSIZE + 8, 8, &retlen,
97 (char *)&h1) < 0)) { 102 (char *)&h1) < 0)) {
98 printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n", 103 printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n",
@@ -283,7 +288,7 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int
283 return -1; 288 return -1;
284 289
285 if (check_oob) { 290 if (check_oob) {
286 if(mtd->read_oob(mtd, address, mtd->oobsize, 291 if(nftl_read_oob(mtd, address, mtd->oobsize,
287 &retlen, &buf[SECTORSIZE]) < 0) 292 &retlen, &buf[SECTORSIZE]) < 0)
288 return -1; 293 return -1;
289 if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0) 294 if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)
@@ -311,7 +316,7 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)
311 struct mtd_info *mtd = nftl->mbd.mtd; 316 struct mtd_info *mtd = nftl->mbd.mtd;
312 317
313 /* Read the Unit Control Information #1 for Wear-Leveling */ 318 /* Read the Unit Control Information #1 for Wear-Leveling */
314 if (mtd->read_oob(mtd, block * nftl->EraseSize + SECTORSIZE + 8, 319 if (nftl_read_oob(mtd, block * nftl->EraseSize + SECTORSIZE + 8,
315 8, &retlen, (char *)&uci) < 0) 320 8, &retlen, (char *)&uci) < 0)
316 goto default_uci1; 321 goto default_uci1;
317 322
@@ -351,7 +356,7 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)
351 goto fail; 356 goto fail;
352 357
353 uci.WearInfo = le32_to_cpu(nb_erases); 358 uci.WearInfo = le32_to_cpu(nb_erases);
354 if (mtd->write_oob(mtd, block * nftl->EraseSize + SECTORSIZE + 359 if (nftl_write_oob(mtd, block * nftl->EraseSize + SECTORSIZE +
355 8, 8, &retlen, (char *)&uci) < 0) 360 8, 8, &retlen, (char *)&uci) < 0)
356 goto fail; 361 goto fail;
357 return 0; 362 return 0;
@@ -383,7 +388,7 @@ static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_b
383 block = first_block; 388 block = first_block;
384 for (;;) { 389 for (;;) {
385 for (i = 0; i < sectors_per_block; i++) { 390 for (i = 0; i < sectors_per_block; i++) {
386 if (mtd->read_oob(mtd, 391 if (nftl_read_oob(mtd,
387 block * nftl->EraseSize + i * SECTORSIZE, 392 block * nftl->EraseSize + i * SECTORSIZE,
388 8, &retlen, (char *)&bci) < 0) 393 8, &retlen, (char *)&bci) < 0)
389 status = SECTOR_IGNORE; 394 status = SECTOR_IGNORE;
@@ -404,7 +409,7 @@ static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_b
404 /* sector not free actually : mark it as SECTOR_IGNORE */ 409 /* sector not free actually : mark it as SECTOR_IGNORE */
405 bci.Status = SECTOR_IGNORE; 410 bci.Status = SECTOR_IGNORE;
406 bci.Status1 = SECTOR_IGNORE; 411 bci.Status1 = SECTOR_IGNORE;
407 mtd->write_oob(mtd, block * 412 nftl_write_oob(mtd, block *
408 nftl->EraseSize + 413 nftl->EraseSize +
409 i * SECTORSIZE, 8, 414 i * SECTORSIZE, 8,
410 &retlen, (char *)&bci); 415 &retlen, (char *)&bci);
@@ -498,7 +503,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
498 size_t retlen; 503 size_t retlen;
499 504
500 /* check erase mark. */ 505 /* check erase mark. */
501 if (mtd->read_oob(mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, 506 if (nftl_read_oob(mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
502 &retlen, (char *)&h1) < 0) 507 &retlen, (char *)&h1) < 0)
503 return -1; 508 return -1;
504 509
@@ -513,7 +518,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
513 h1.EraseMark = cpu_to_le16(ERASE_MARK); 518 h1.EraseMark = cpu_to_le16(ERASE_MARK);
514 h1.EraseMark1 = cpu_to_le16(ERASE_MARK); 519 h1.EraseMark1 = cpu_to_le16(ERASE_MARK);
515 h1.WearInfo = cpu_to_le32(0); 520 h1.WearInfo = cpu_to_le32(0);
516 if (mtd->write_oob(mtd, 521 if (nftl_write_oob(mtd,
517 block * nftl->EraseSize + SECTORSIZE + 8, 8, 522 block * nftl->EraseSize + SECTORSIZE + 8, 8,
518 &retlen, (char *)&h1) < 0) 523 &retlen, (char *)&h1) < 0)
519 return -1; 524 return -1;
@@ -526,7 +531,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
526 SECTORSIZE, 0) != 0) 531 SECTORSIZE, 0) != 0)
527 return -1; 532 return -1;
528 533
529 if (mtd->read_oob(mtd, block * nftl->EraseSize + i, 534 if (nftl_read_oob(mtd, block * nftl->EraseSize + i,
530 16, &retlen, buf) < 0) 535 16, &retlen, buf) < 0)
531 return -1; 536 return -1;
532 if (i == SECTORSIZE) { 537 if (i == SECTORSIZE) {
@@ -557,7 +562,7 @@ static int get_fold_mark(struct NFTLrecord *nftl, unsigned int block)
557 struct nftl_uci2 uci; 562 struct nftl_uci2 uci;
558 size_t retlen; 563 size_t retlen;
559 564
560 if (mtd->read_oob(mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8, 565 if (nftl_read_oob(mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
561 8, &retlen, (char *)&uci) < 0) 566 8, &retlen, (char *)&uci) < 0)
562 return 0; 567 return 0;
563 568
@@ -597,10 +602,10 @@ int NFTL_mount(struct NFTLrecord *s)
597 602
598 for (;;) { 603 for (;;) {
599 /* read the block header. If error, we format the chain */ 604 /* read the block header. If error, we format the chain */
600 if (mtd->read_oob(mtd, 605 if (nftl_read_oob(mtd,
601 block * s->EraseSize + 8, 8, 606 block * s->EraseSize + 8, 8,
602 &retlen, (char *)&h0) < 0 || 607 &retlen, (char *)&h0) < 0 ||
603 mtd->read_oob(mtd, 608 nftl_read_oob(mtd,
604 block * s->EraseSize + 609 block * s->EraseSize +
605 SECTORSIZE + 8, 8, 610 SECTORSIZE + 8, 8,
606 &retlen, (char *)&h1) < 0) { 611 &retlen, (char *)&h1) < 0) {
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index a0d3f011c0f2..84ec40d25438 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -671,7 +671,7 @@ out:
671} 671}
672 672
673/** 673/**
674 * onenand_read_oob - [MTD Interface] OneNAND read out-of-band 674 * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band
675 * @param mtd MTD device structure 675 * @param mtd MTD device structure
676 * @param from offset to read from 676 * @param from offset to read from
677 * @param len number of bytes to read 677 * @param len number of bytes to read
@@ -680,8 +680,8 @@ out:
680 * 680 *
681 * OneNAND read out-of-band data from the spare area 681 * OneNAND read out-of-band data from the spare area
682 */ 682 */
683static int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, 683int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
684 size_t *retlen, u_char *buf) 684 size_t *retlen, u_char *buf)
685{ 685{
686 struct onenand_chip *this = mtd->priv; 686 struct onenand_chip *this = mtd->priv;
687 int read = 0, thislen, column; 687 int read = 0, thislen, column;
@@ -744,6 +744,21 @@ out:
744 return ret; 744 return ret;
745} 745}
746 746
747/**
748 * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band
749 * @mtd: MTD device structure
750 * @from: offset to read from
751 * @ops: oob operation description structure
752 */
753static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
754 struct mtd_oob_ops *ops)
755{
756 BUG_ON(ops->mode != MTD_OOB_PLACE);
757
758 return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->len,
759 &ops->retlen, ops->oobbuf);
760}
761
747#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE 762#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
748/** 763/**
749 * onenand_verify_oob - [GENERIC] verify the oob contents after a write 764 * onenand_verify_oob - [GENERIC] verify the oob contents after a write
@@ -894,7 +909,7 @@ out:
894} 909}
895 910
896/** 911/**
897 * onenand_write_oob - [MTD Interface] OneNAND write out-of-band 912 * onenand_do_write_oob - [Internal] OneNAND write out-of-band
898 * @param mtd MTD device structure 913 * @param mtd MTD device structure
899 * @param to offset to write to 914 * @param to offset to write to
900 * @param len number of bytes to write 915 * @param len number of bytes to write
@@ -903,8 +918,8 @@ out:
903 * 918 *
904 * OneNAND write out-of-band 919 * OneNAND write out-of-band
905 */ 920 */
906static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, 921static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
907 size_t *retlen, const u_char *buf) 922 size_t *retlen, const u_char *buf)
908{ 923{
909 struct onenand_chip *this = mtd->priv; 924 struct onenand_chip *this = mtd->priv;
910 int column, ret = 0; 925 int column, ret = 0;
@@ -973,6 +988,21 @@ out:
973} 988}
974 989
975/** 990/**
991 * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band
992 * @mtd: MTD device structure
993 * @from: offset to read from
994 * @ops: oob operation description structure
995 */
996static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
997 struct mtd_oob_ops *ops)
998{
999 BUG_ON(ops->mode != MTD_OOB_PLACE);
1000
1001 return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->len,
1002 &ops->retlen, ops->oobbuf);
1003}
1004
1005/**
976 * onenand_block_checkbad - [GENERIC] Check if a block is marked bad 1006 * onenand_block_checkbad - [GENERIC] Check if a block is marked bad
977 * @param mtd MTD device structure 1007 * @param mtd MTD device structure
978 * @param ofs offset from device start 1008 * @param ofs offset from device start
@@ -1138,7 +1168,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
1138 1168
1139 /* We write two bytes, so we dont have to mess with 16 bit access */ 1169 /* We write two bytes, so we dont have to mess with 16 bit access */
1140 ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); 1170 ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
1141 return mtd->write_oob(mtd, ofs , 2, &retlen, buf); 1171 return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf);
1142} 1172}
1143 1173
1144/** 1174/**
@@ -1328,7 +1358,7 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
1328 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); 1358 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
1329 this->wait(mtd, FL_OTPING); 1359 this->wait(mtd, FL_OTPING);
1330 1360
1331 ret = mtd->write_oob(mtd, from, len, retlen, buf); 1361 ret = onenand_do_write_oob(mtd, from, len, retlen, buf);
1332 1362
1333 /* Exit OTP access mode */ 1363 /* Exit OTP access mode */
1334 this->command(mtd, ONENAND_CMD_RESET, 0, 0); 1364 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c
index aafd7c2f7802..1b00dac3d7d6 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -17,6 +17,9 @@
17#include <linux/mtd/onenand.h> 17#include <linux/mtd/onenand.h>
18#include <linux/mtd/compatmac.h> 18#include <linux/mtd/compatmac.h>
19 19
20extern int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
21 size_t *retlen, u_char *buf);
22
20/** 23/**
21 * check_short_pattern - [GENERIC] check if a pattern is in the buffer 24 * check_short_pattern - [GENERIC] check if a pattern is in the buffer
22 * @param buf the buffer to search 25 * @param buf the buffer to search
@@ -87,8 +90,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
87 90
88 /* No need to read pages fully, 91 /* No need to read pages fully,
89 * just read required OOB bytes */ 92 * just read required OOB bytes */
90 ret = mtd->read_oob(mtd, from + j * mtd->writesize + bd->offs, 93 ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs,
91 readlen, &retlen, &buf[0]); 94 readlen, &retlen, &buf[0]);
92 95
93 if (ret) 96 if (ret)
94 return ret; 97 return ret;