Add Sergey's patch
[yaffs2.git] / yaffs_mtdif2.c
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system. 
3  * yaffs_mtdif.c  NAND mtd wrapper functions.
4  *
5  * Copyright (C) 2002 Aleph One Ltd.
6  *   for Toby Churchill Ltd and Brightstar Engineering
7  *
8  * Created by Charles Manning <charles@aleph1.co.uk>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  */
15
16 /* mtd interface for YAFFS2 */
17
18 const char *yaffs_mtdif2_c_version =
19     "$Id: yaffs_mtdif2.c,v 1.11 2006-04-25 00:41:43 wookey Exp $";
20
21 #include "yportenv.h"
22
23
24 #include "yaffs_mtdif2.h"
25
26 #include "linux/mtd/mtd.h"
27 #include "linux/types.h"
28 #include "linux/time.h"
29
30 #include "yaffs_packedtags2.h"
31
32 int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
33                                       const __u8 * data,
34                                       const yaffs_ExtendedTags * tags)
35 {
36         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
37         size_t dummy;
38         int retval = 0;
39
40         loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk;
41
42         yaffs_PackedTags2 pt;
43
44         T(YAFFS_TRACE_MTD,
45           (TSTR
46            ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
47             TENDSTR), chunkInNAND, data, tags));
48
49         if (tags) {
50                 yaffs_PackTags2(&pt, tags);
51         }
52
53         if (data && tags) {
54                 if (dev->useNANDECC)
55                         retval =
56                             mtd->write_ecc(mtd, addr, dev->nBytesPerChunk,
57                                            &dummy, data, (__u8 *) & pt, NULL);
58                 else
59                         retval =
60                             mtd->write_ecc(mtd, addr, dev->nBytesPerChunk,
61                                            &dummy, data, (__u8 *) & pt, NULL);
62         } else {
63                 if (data)
64                         retval =
65                             mtd->write(mtd, addr, dev->nBytesPerChunk, &dummy,
66                                        data);
67                 if (tags)
68                         retval =
69                             mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
70                                            (__u8 *) & pt);
71
72         }
73
74         if (retval == 0)
75                 return YAFFS_OK;
76         else
77                 return YAFFS_FAIL;
78 }
79
80 int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
81                                        __u8 * data, yaffs_ExtendedTags * tags)
82 {
83         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
84         size_t dummy;
85         int retval = 0;
86
87         loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk;
88
89         yaffs_PackedTags2 pt;
90
91         T(YAFFS_TRACE_MTD,
92           (TSTR
93            ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
94             TENDSTR), chunkInNAND, data, tags));
95
96         if (data && tags) {
97                 if (dev->useNANDECC) {
98                         retval =
99                             mtd->read_ecc(mtd, addr, dev->nBytesPerChunk,
100                                           &dummy, data, dev->spareBuffer,
101                                           NULL);
102                 } else {
103                         retval =
104                             mtd->read_ecc(mtd, addr, dev->nBytesPerChunk,
105                                           &dummy, data, dev->spareBuffer,
106                                           NULL);
107                 }
108         } else {
109                 if (data)
110                         retval =
111                             mtd->read(mtd, addr, dev->nBytesPerChunk, &dummy,
112                                       data);
113                 if (tags)
114                         retval =
115                             mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
116                                           dev->spareBuffer);
117         }
118
119         memcpy(&pt, dev->spareBuffer, sizeof(pt));
120
121         if (tags)
122                 yaffs_UnpackTags2(tags, &pt);
123
124         if (retval == 0)
125                 return YAFFS_OK;
126         else
127                 return YAFFS_FAIL;
128 }
129
130 int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
131 {
132         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
133         int retval;
134         T(YAFFS_TRACE_MTD,
135           (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
136
137         retval =
138             mtd->block_markbad(mtd,
139                                blockNo * dev->nChunksPerBlock *
140                                dev->nBytesPerChunk);
141
142         if (retval == 0)
143                 return YAFFS_OK;
144         else
145                 return YAFFS_FAIL;
146
147 }
148
149 int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
150                             yaffs_BlockState * state, int *sequenceNumber)
151 {
152         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
153         int retval;
154
155         T(YAFFS_TRACE_MTD,
156           (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
157         retval =
158             mtd->block_isbad(mtd,
159                              blockNo * dev->nChunksPerBlock *
160                              dev->nBytesPerChunk);
161
162         if (retval) {
163                 T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
164
165                 *state = YAFFS_BLOCK_STATE_DEAD;
166                 *sequenceNumber = 0;
167         } else {
168                 yaffs_ExtendedTags t;
169                 nandmtd2_ReadChunkWithTagsFromNAND(dev,
170                                                    blockNo *
171                                                    dev->nChunksPerBlock, NULL,
172                                                    &t);
173
174                 if (t.chunkUsed) {
175                         *sequenceNumber = t.sequenceNumber;
176                         *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
177                 } else {
178                         *sequenceNumber = 0;
179                         *state = YAFFS_BLOCK_STATE_EMPTY;
180                 }
181         }
182         T(YAFFS_TRACE_MTD,
183           (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
184            *state));
185
186         if (retval == 0)
187                 return YAFFS_OK;
188         else
189                 return YAFFS_FAIL;
190 }
191