aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@cruncher.tec.linutronix.de>2006-05-28 21:26:58 -0400
committerThomas Gleixner <tglx@cruncher.tec.linutronix.de>2006-05-29 09:06:51 -0400
commit8593fbc68b0df1168995de76d1af38eb62fd6b62 (patch)
treedd244def53d2be4f1fbff9f74eac404fab8e240f /drivers/mtd
parentf4a43cfcecfcaeeaa40a9dbc1d1378298c22446e (diff)
[MTD] Rework the out of band handling completely
Hopefully the last iteration on this! The handling of out of band data on NAND was accompanied by tons of fruitless discussions and halfarsed patches to make it work for a particular problem. Sufficiently annoyed by I all those "I know it better" mails and the resonable amount of discarded "it solves my problem" patches, I finally decided to go for the big rework. After removing the _ecc variants of mtd read/write functions the solution to satisfy the various requirements was to refactor the read/write _oob functions in mtd. The major change is that read/write_oob now takes a pointer to an operation descriptor structure "struct mtd_oob_ops".instead of having a function with at least seven arguments. read/write_oob which should probably renamed to a more descriptive name, can do the following tasks: - read/write out of band data - read/write data content and out of band data - read/write raw data content and out of band data (ecc disabled) struct mtd_oob_ops has a mode field, which determines the oob handling mode. Aside of the MTD_OOB_RAW mode, which is intended to be especially for diagnostic purposes and some internal functions e.g. bad block table creation, the other two modes are for mtd clients: MTD_OOB_PLACE puts/gets the given oob data exactly to/from the place which is described by the ooboffs and ooblen fields of the mtd_oob_ops strcuture. It's up to the caller to make sure that the byte positions are not used by the ECC placement algorithms. MTD_OOB_AUTO puts/gets the given oob data automaticaly to/from the places in the out of band area which are described by the oobfree tuples in the ecclayout data structre which is associated to the devicee. The decision whether data plus oob or oob only handling is done depends on the setting of the datbuf member of the data structure. When datbuf == NULL then the internal read/write_oob functions are selected, otherwise the read/write data routines are invoked. Tested on a few platforms with all variants. Please be aware of possible regressions for your particular device / application scenario Disclaimer: Any whining will be ignored from those who just contributed "hot air blurb" and never sat down to tackle the underlying problem of the mess in the NAND driver grown over time and the big chunk of work to fix up the existing users. The problem was not the holiness of the existing MTD interfaces. The problems was the lack of time to go for the big overhaul. It's easy to add more mess to the existing one, but it takes alot of effort to go for a real solution. Improvements and bugfixes are welcome! Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
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;