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