normalise licence headers and attributions
[yaffs2.git] / yaffs_mtdif2.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2007 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
15 /* mtd interface for YAFFS2 */
16
17 const char *yaffs_mtdif2_c_version =
18     "$Id: yaffs_mtdif2.c,v 1.16 2007-02-12 16:55:26 wookey Exp $";
19
20 #include "yportenv.h"
21
22
23 #include "yaffs_mtdif2.h"
24
25 #include "linux/mtd/mtd.h"
26 #include "linux/types.h"
27 #include "linux/time.h"
28
29 #include "yaffs_packedtags2.h"
30
31 int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
32                                       const __u8 * data,
33                                       const yaffs_ExtendedTags * tags)
34 {
35         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
36 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
37         struct mtd_oob_ops ops;
38 #else
39         size_t dummy;
40 #endif
41         int retval = 0;
42
43         loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
44
45         yaffs_PackedTags2 pt;
46
47         T(YAFFS_TRACE_MTD,
48           (TSTR
49            ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
50             TENDSTR), chunkInNAND, data, tags));
51
52 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
53         if (tags)
54                 yaffs_PackTags2(&pt, tags);
55         else
56                 BUG(); /* both tags and data should always be present */
57
58         if (data) {
59                 ops.mode = MTD_OOB_AUTO;
60                 ops.ooblen = sizeof(pt);
61                 ops.len = dev->nDataBytesPerChunk;
62                 ops.ooboffs = 0;
63                 ops.datbuf = (__u8 *)data;
64                 ops.oobbuf = (void *)&pt;
65                 retval = mtd->write_oob(mtd, addr, &ops);
66         } else
67                 BUG(); /* both tags and data should always be present */
68 #else
69         if (tags) {
70                 yaffs_PackTags2(&pt, tags);
71         }
72
73         if (data && tags) {
74                 if (dev->useNANDECC)
75                         retval =
76                             mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
77                                            &dummy, data, (__u8 *) & pt, NULL);
78                 else
79                         retval =
80                             mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
81                                            &dummy, data, (__u8 *) & pt, NULL);
82         } else {
83                 if (data)
84                         retval =
85                             mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
86                                        data);
87                 if (tags)
88                         retval =
89                             mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
90                                            (__u8 *) & pt);
91
92         }
93 #endif
94
95         if (retval == 0)
96                 return YAFFS_OK;
97         else
98                 return YAFFS_FAIL;
99 }
100
101 int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
102                                        __u8 * data, yaffs_ExtendedTags * tags)
103 {
104         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
105 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
106         struct mtd_oob_ops ops;
107 #endif
108         size_t dummy;
109         int retval = 0;
110
111         loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
112
113         yaffs_PackedTags2 pt;
114
115         T(YAFFS_TRACE_MTD,
116           (TSTR
117            ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
118             TENDSTR), chunkInNAND, data, tags));
119
120 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
121         if (data && !tags)
122                 retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
123                                 &dummy, data);
124         else if (tags) {
125                 ops.mode = MTD_OOB_AUTO;
126                 ops.ooblen = sizeof(pt);
127                 ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
128                 ops.ooboffs = 0;
129                 ops.datbuf = data;
130                 ops.oobbuf = dev->spareBuffer;
131                 retval = mtd->read_oob(mtd, addr, &ops);
132         }
133 #else
134         if (data && tags) {
135                 if (dev->useNANDECC) {
136                         retval =
137                             mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
138                                           &dummy, data, dev->spareBuffer,
139                                           NULL);
140                 } else {
141                         retval =
142                             mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
143                                           &dummy, data, dev->spareBuffer,
144                                           NULL);
145                 }
146         } else {
147                 if (data)
148                         retval =
149                             mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
150                                       data);
151                 if (tags)
152                         retval =
153                             mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
154                                           dev->spareBuffer);
155         }
156 #endif
157
158         memcpy(&pt, dev->spareBuffer, sizeof(pt));
159
160         if (tags)
161                 yaffs_UnpackTags2(tags, &pt);
162         
163         if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
164                 tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
165
166         if (retval == 0)
167                 return YAFFS_OK;
168         else
169                 return YAFFS_FAIL;
170 }
171
172 int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
173 {
174         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
175         int retval;
176         T(YAFFS_TRACE_MTD,
177           (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
178
179         retval =
180             mtd->block_markbad(mtd,
181                                blockNo * dev->nChunksPerBlock *
182                                dev->nDataBytesPerChunk);
183
184         if (retval == 0)
185                 return YAFFS_OK;
186         else
187                 return YAFFS_FAIL;
188
189 }
190
191 int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
192                             yaffs_BlockState * state, int *sequenceNumber)
193 {
194         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
195         int retval;
196
197         T(YAFFS_TRACE_MTD,
198           (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
199         retval =
200             mtd->block_isbad(mtd,
201                              blockNo * dev->nChunksPerBlock *
202                              dev->nDataBytesPerChunk);
203
204         if (retval) {
205                 T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
206
207                 *state = YAFFS_BLOCK_STATE_DEAD;
208                 *sequenceNumber = 0;
209         } else {
210                 yaffs_ExtendedTags t;
211                 nandmtd2_ReadChunkWithTagsFromNAND(dev,
212                                                    blockNo *
213                                                    dev->nChunksPerBlock, NULL,
214                                                    &t);
215
216                 if (t.chunkUsed) {
217                         *sequenceNumber = t.sequenceNumber;
218                         *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
219                 } else {
220                         *sequenceNumber = 0;
221                         *state = YAFFS_BLOCK_STATE_EMPTY;
222                 }
223         }
224         T(YAFFS_TRACE_MTD,
225           (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
226            *state));
227
228         if (retval == 0)
229                 return YAFFS_OK;
230         else
231                 return YAFFS_FAIL;
232 }
233