019142b4e1e475f952825dcd315050946ee4bde3
[yaffs2.git] / patches / yaffs_mtdif2.c
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system. 
3  *
4  * Copyright (C) 2002-2010 Aleph One Ltd.
5  *   for Toby Churchill Ltd and Brightstar Engineering
6  *
7  * Created by Charles Manning <charles@aleph1.co.uk>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13
14 /* mtd interface for YAFFS2 */
15
16 const char *yaffs_mtdif2_c_version =
17     "$Id: yaffs_mtdif2.c,v 1.2 2007-03-07 08:05:58 colin Exp $";
18
19 #include "yportenv.h"
20
21
22 #include "yaffs_mtdif2.h"
23
24 #include "linux/mtd/mtd.h"
25 #include "linux/types.h"
26 #include "linux/time.h"
27
28 #include "yaffs_packedtags2.h"
29
30
31 void nandmtd2_pt2buf(yaffs_dev_t *dev, yaffs_PackedTags2 *pt, int is_raw)
32 {
33         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
34         u8 *ptab = (u8 *)pt; /* packed tags as bytes */
35         
36         int     i, j = 0, k, n;
37
38         /* Pack buffer with 0xff */
39         for (i = 0; i < mtd->oobsize; i++)
40                 dev->spareBuffer[i] = 0xff;
41                 
42         if(!is_raw){
43                 memcpy(dev->spareBuffer,pt,sizeof(yaffs_PackedTags2));
44         } else {
45                 j = 0;
46                 k = mtd->oobinfo.oobfree[j][0];
47                 n = mtd->oobinfo.oobfree[j][1];
48
49                 if (n == 0) {
50                         T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR)));
51                         YBUG();
52                 }
53
54                 for (i = 0; i < sizeof(yaffs_PackedTags2); i++) {
55                         if (n == 0) {
56                                 j++;
57                                 k = mtd->oobinfo.oobfree[j][0];
58                                 n = mtd->oobinfo.oobfree[j][1];
59                                 if (n == 0) {
60                                         T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR)));
61                                         YBUG();
62                                 }
63                         }
64                         dev->spareBuffer[k] = ptab[i];
65                         k++;
66                         n--;
67                 }
68         }
69
70 }
71
72 void nandmtd2_buf2pt(yaffs_dev_t *dev, yaffs_PackedTags2 *pt, int is_raw)
73 {
74         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
75         int     i, j = 0, k, n;
76         u8 *ptab = (u8 *)pt; /* packed tags as bytes */
77
78
79         if (!is_raw) {
80         
81                 memcpy(pt,dev->spareBuffer,sizeof(yaffs_PackedTags2));
82         } else {
83                 j = 0;
84                 k = mtd->oobinfo.oobfree[j][0];
85                 n = mtd->oobinfo.oobfree[j][1];
86
87                 if (n == 0) {
88                         T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR)));
89                         YBUG();
90                 }
91
92                 for (i = 0; i < sizeof(yaffs_PackedTags2); i++) {
93                         if (n == 0) {
94                                 j++;
95                                 k = mtd->oobinfo.oobfree[j][0];
96                                 n = mtd->oobinfo.oobfree[j][1];
97                                 if (n == 0) {
98                                         T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR)));
99                                         YBUG();
100                                 }
101                         }
102                         ptab[i] = dev->spareBuffer[k];
103                         k++;
104                         n--;
105                 }
106         }
107                 
108 }
109
110 int nandmtd2_WriteChunkWithTagsToNAND(yaffs_dev_t * dev, int nand_chunk,
111                                       const u8 * data,
112                                       const yaffs_ext_tags * tags)
113 {
114         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
115         size_t dummy;
116         int retval = 0;
117
118         loff_t addr = ((loff_t) nand_chunk) * dev->n_bytesPerChunk;
119
120         yaffs_PackedTags2 pt;
121
122         T(YAFFS_TRACE_MTD,
123           (TSTR
124            ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
125             TENDSTR), nand_chunk, data, tags));
126
127         if (tags) {
128                 yaffs_PackTags2(&pt, tags);
129         }
130
131         if (data && tags) {
132                         nandmtd2_pt2buf(dev, &pt, 0);
133                         retval =
134                             mtd->write_ecc(mtd, addr, dev->n_bytesPerChunk,
135                                            &dummy, data, dev->spareBuffer,
136                                            NULL);
137
138         } else {
139         
140                 T(YAFFS_TRACE_ALWAYS,
141                   (TSTR
142                   ("Write chunk with null tags or data!" TENDSTR)));
143                 YBUG();
144         }
145
146         if (retval == 0)
147                 return YAFFS_OK;
148         else
149                 return YAFFS_FAIL;
150 }
151
152 int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t * dev, int nand_chunk,
153                                        u8 * data, yaffs_ext_tags * tags)
154 {
155         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
156         size_t dummy;
157         int retval = 0;
158
159         loff_t addr = ((loff_t) nand_chunk) * dev->n_bytesPerChunk;
160
161         yaffs_PackedTags2 pt;
162
163         T(YAFFS_TRACE_MTD,
164           (TSTR
165            ("nandmtd2_ReadChunkWithTagsToNAND chunk %d data %p tags %p"
166             TENDSTR), nand_chunk, data, tags));
167
168         if (0 && data && tags) {
169                         retval =
170                             mtd->read_ecc(mtd, addr, dev->n_bytesPerChunk,
171                                           &dummy, data, dev->spareBuffer,
172                                           NULL);
173                         nandmtd2_buf2pt(dev, &pt, 0);
174         } else {
175                 if (data)
176                         retval =
177                             mtd->read(mtd, addr, dev->n_bytesPerChunk, &dummy,
178                                       data);
179                 if (tags) {
180                         retval =
181                             mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
182                                           dev->spareBuffer);
183                         nandmtd2_buf2pt(dev, &pt, 1);
184                 }
185         }
186
187         if (tags)
188                 yaffs_unpack_tags2(tags, &pt);
189
190         if (retval == 0)
191                 return YAFFS_OK;
192         else
193                 return YAFFS_FAIL;
194 }
195
196 int nandmtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no)
197 {
198         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
199         int retval;
200         T(YAFFS_TRACE_MTD,
201           (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), block_no));
202
203         retval =
204             mtd->block_markbad(mtd,
205                                block_no * dev->chunks_per_block *
206                                dev->n_bytesPerChunk);
207
208         if (retval == 0)
209                 return YAFFS_OK;
210         else
211                 return YAFFS_FAIL;
212
213 }
214
215 int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no,
216                             yaffs_block_state_t * state, int *seq_number)
217 {
218         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
219         int retval;
220
221         T(YAFFS_TRACE_MTD,
222           (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), block_no));
223         retval =
224             mtd->block_isbad(mtd,
225                              block_no * dev->chunks_per_block *
226                              dev->n_bytesPerChunk);
227
228         if (retval) {
229                 T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
230
231                 *state = YAFFS_BLOCK_STATE_DEAD;
232                 *seq_number = 0;
233         } else {
234                 yaffs_ext_tags t;
235                 nandmtd2_ReadChunkWithTagsFromNAND(dev,
236                                                    block_no *
237                                                    dev->chunks_per_block, NULL,
238                                                    &t);
239
240                 if (t.chunk_used) {
241                         *seq_number = t.seq_number;
242                         *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
243                 } else {
244                         *seq_number = 0;
245                         *state = YAFFS_BLOCK_STATE_EMPTY;
246                 }
247
248                 T(YAFFS_TRACE_MTD,
249                   (TSTR("block is OK seq %d state %d" TENDSTR), *seq_number,
250                    *state));
251         }
252
253         if (retval == 0)
254                 return YAFFS_OK;
255         else
256                 return YAFFS_FAIL;
257 }
258