1*753ac610SCharles Manning /*
2*753ac610SCharles Manning * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3*753ac610SCharles Manning *
4*753ac610SCharles Manning * Copyright (C) 2002-2011 Aleph One Ltd.
5*753ac610SCharles Manning * for Toby Churchill Ltd and Brightstar Engineering
6*753ac610SCharles Manning *
7*753ac610SCharles Manning * Created by Charles Manning <charles@aleph1.co.uk>
8*753ac610SCharles Manning *
9*753ac610SCharles Manning * This program is free software; you can redistribute it and/or modify
10*753ac610SCharles Manning * it under the terms of the GNU General Public License version 2 as
11*753ac610SCharles Manning * published by the Free Software Foundation.
12*753ac610SCharles Manning */
13*753ac610SCharles Manning
14*753ac610SCharles Manning #include "yportenv.h"
15*753ac610SCharles Manning #include "yaffs_guts.h"
16*753ac610SCharles Manning
17*753ac610SCharles Manning
18*753ac610SCharles Manning #include "yaffs_nandif.h"
19*753ac610SCharles Manning #include "yaffs_packedtags2.h"
20*753ac610SCharles Manning
21*753ac610SCharles Manning #include "yramsim.h"
22*753ac610SCharles Manning
23*753ac610SCharles Manning #include "yaffs_trace.h"
24*753ac610SCharles Manning #include "yaffsfs.h"
25*753ac610SCharles Manning
26*753ac610SCharles Manning
27*753ac610SCharles Manning /* NB For use with inband tags....
28*753ac610SCharles Manning * We assume that the data buffer is of size totalBytersPerChunk so that
29*753ac610SCharles Manning * we can also use it to load the tags.
30*753ac610SCharles Manning */
ynandif_WriteChunkWithTagsToNAND(struct yaffs_dev * dev,int nand_chunk,const u8 * data,const struct yaffs_ext_tags * tags)31*753ac610SCharles Manning int ynandif_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk,
32*753ac610SCharles Manning const u8 *data,
33*753ac610SCharles Manning const struct yaffs_ext_tags *tags)
34*753ac610SCharles Manning {
35*753ac610SCharles Manning
36*753ac610SCharles Manning int retval = 0;
37*753ac610SCharles Manning struct yaffs_packed_tags2 pt;
38*753ac610SCharles Manning void *spare;
39*753ac610SCharles Manning unsigned spareSize = 0;
40*753ac610SCharles Manning struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
41*753ac610SCharles Manning
42*753ac610SCharles Manning yaffs_trace(YAFFS_TRACE_MTD,
43*753ac610SCharles Manning "nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p",
44*753ac610SCharles Manning nand_chunk, data, tags);
45*753ac610SCharles Manning
46*753ac610SCharles Manning
47*753ac610SCharles Manning /* For yaffs2 writing there must be both data and tags.
48*753ac610SCharles Manning * If we're using inband tags, then the tags are stuffed into
49*753ac610SCharles Manning * the end of the data buffer.
50*753ac610SCharles Manning */
51*753ac610SCharles Manning
52*753ac610SCharles Manning if (dev->param.inband_tags) {
53*753ac610SCharles Manning struct yaffs_packed_tags2_tags_only *pt2tp;
54*753ac610SCharles Manning
55*753ac610SCharles Manning pt2tp = (struct yaffs_packed_tags2_tags_only *)
56*753ac610SCharles Manning (data + dev->data_bytes_per_chunk);
57*753ac610SCharles Manning yaffs_pack_tags2_tags_only(pt2tp, tags);
58*753ac610SCharles Manning spare = NULL;
59*753ac610SCharles Manning spareSize = 0;
60*753ac610SCharles Manning } else {
61*753ac610SCharles Manning yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
62*753ac610SCharles Manning spare = &pt;
63*753ac610SCharles Manning spareSize = sizeof(struct yaffs_packed_tags2);
64*753ac610SCharles Manning }
65*753ac610SCharles Manning
66*753ac610SCharles Manning retval = geometry->writeChunk(dev, nand_chunk,
67*753ac610SCharles Manning data, dev->param.total_bytes_per_chunk,
68*753ac610SCharles Manning spare, spareSize);
69*753ac610SCharles Manning
70*753ac610SCharles Manning return retval;
71*753ac610SCharles Manning }
72*753ac610SCharles Manning
ynandif_ReadChunkWithTagsFromNAND(struct yaffs_dev * dev,int nand_chunk,u8 * data,struct yaffs_ext_tags * tags)73*753ac610SCharles Manning int ynandif_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk,
74*753ac610SCharles Manning u8 *data, struct yaffs_ext_tags *tags)
75*753ac610SCharles Manning {
76*753ac610SCharles Manning struct yaffs_packed_tags2 pt;
77*753ac610SCharles Manning int localData = 0;
78*753ac610SCharles Manning void *spare = NULL;
79*753ac610SCharles Manning unsigned spareSize;
80*753ac610SCharles Manning int retval = 0;
81*753ac610SCharles Manning int eccStatus; /* 0 = ok, 1 = fixed, -1 = unfixed */
82*753ac610SCharles Manning struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
83*753ac610SCharles Manning
84*753ac610SCharles Manning yaffs_trace(YAFFS_TRACE_MTD,
85*753ac610SCharles Manning "nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p",
86*753ac610SCharles Manning nand_chunk, data, tags);
87*753ac610SCharles Manning
88*753ac610SCharles Manning if (!tags) {
89*753ac610SCharles Manning spare = NULL;
90*753ac610SCharles Manning spareSize = 0;
91*753ac610SCharles Manning } else if (dev->param.inband_tags) {
92*753ac610SCharles Manning
93*753ac610SCharles Manning if (!data) {
94*753ac610SCharles Manning localData = 1;
95*753ac610SCharles Manning data = yaffs_get_temp_buffer(dev);
96*753ac610SCharles Manning }
97*753ac610SCharles Manning spare = NULL;
98*753ac610SCharles Manning spareSize = 0;
99*753ac610SCharles Manning } else {
100*753ac610SCharles Manning spare = &pt;
101*753ac610SCharles Manning spareSize = sizeof(struct yaffs_packed_tags2);
102*753ac610SCharles Manning }
103*753ac610SCharles Manning
104*753ac610SCharles Manning retval = geometry->readChunk(dev, nand_chunk,
105*753ac610SCharles Manning data,
106*753ac610SCharles Manning data ? dev->param.total_bytes_per_chunk : 0,
107*753ac610SCharles Manning spare, spareSize,
108*753ac610SCharles Manning &eccStatus);
109*753ac610SCharles Manning
110*753ac610SCharles Manning if (dev->param.inband_tags) {
111*753ac610SCharles Manning if (tags) {
112*753ac610SCharles Manning struct yaffs_packed_tags2_tags_only *pt2tp;
113*753ac610SCharles Manning pt2tp = (struct yaffs_packed_tags2_tags_only *)
114*753ac610SCharles Manning &data[dev->data_bytes_per_chunk];
115*753ac610SCharles Manning yaffs_unpack_tags2_tags_only(tags, pt2tp);
116*753ac610SCharles Manning }
117*753ac610SCharles Manning } else {
118*753ac610SCharles Manning if (tags)
119*753ac610SCharles Manning yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
120*753ac610SCharles Manning }
121*753ac610SCharles Manning
122*753ac610SCharles Manning if (tags && tags->chunk_used) {
123*753ac610SCharles Manning if (eccStatus < 0 ||
124*753ac610SCharles Manning tags->ecc_result == YAFFS_ECC_RESULT_UNFIXED)
125*753ac610SCharles Manning tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
126*753ac610SCharles Manning else if (eccStatus > 0 ||
127*753ac610SCharles Manning tags->ecc_result == YAFFS_ECC_RESULT_FIXED)
128*753ac610SCharles Manning tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
129*753ac610SCharles Manning else
130*753ac610SCharles Manning tags->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
131*753ac610SCharles Manning }
132*753ac610SCharles Manning
133*753ac610SCharles Manning if (localData)
134*753ac610SCharles Manning yaffs_release_temp_buffer(dev, data);
135*753ac610SCharles Manning
136*753ac610SCharles Manning return retval;
137*753ac610SCharles Manning }
138*753ac610SCharles Manning
ynandif_MarkNANDBlockBad(struct yaffs_dev * dev,int blockId)139*753ac610SCharles Manning int ynandif_MarkNANDBlockBad(struct yaffs_dev *dev, int blockId)
140*753ac610SCharles Manning {
141*753ac610SCharles Manning struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
142*753ac610SCharles Manning
143*753ac610SCharles Manning return geometry->markBlockBad(dev, blockId);
144*753ac610SCharles Manning }
145*753ac610SCharles Manning
ynandif_EraseBlockInNAND(struct yaffs_dev * dev,int blockId)146*753ac610SCharles Manning int ynandif_EraseBlockInNAND(struct yaffs_dev *dev, int blockId)
147*753ac610SCharles Manning {
148*753ac610SCharles Manning struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
149*753ac610SCharles Manning
150*753ac610SCharles Manning return geometry->eraseBlock(dev, blockId);
151*753ac610SCharles Manning
152*753ac610SCharles Manning }
153*753ac610SCharles Manning
154*753ac610SCharles Manning
ynandif_IsBlockOk(struct yaffs_dev * dev,int blockId)155*753ac610SCharles Manning static int ynandif_IsBlockOk(struct yaffs_dev *dev, int blockId)
156*753ac610SCharles Manning {
157*753ac610SCharles Manning struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
158*753ac610SCharles Manning
159*753ac610SCharles Manning return geometry->checkBlockOk(dev, blockId);
160*753ac610SCharles Manning }
161*753ac610SCharles Manning
ynandif_QueryNANDBlock(struct yaffs_dev * dev,int blockId,enum yaffs_block_state * state,u32 * seq_number)162*753ac610SCharles Manning int ynandif_QueryNANDBlock(struct yaffs_dev *dev, int blockId,
163*753ac610SCharles Manning enum yaffs_block_state *state, u32 *seq_number)
164*753ac610SCharles Manning {
165*753ac610SCharles Manning unsigned chunkNo;
166*753ac610SCharles Manning struct yaffs_ext_tags tags;
167*753ac610SCharles Manning
168*753ac610SCharles Manning *seq_number = 0;
169*753ac610SCharles Manning
170*753ac610SCharles Manning chunkNo = blockId * dev->param.chunks_per_block;
171*753ac610SCharles Manning
172*753ac610SCharles Manning if (!ynandif_IsBlockOk(dev, blockId)) {
173*753ac610SCharles Manning *state = YAFFS_BLOCK_STATE_DEAD;
174*753ac610SCharles Manning } else {
175*753ac610SCharles Manning ynandif_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &tags);
176*753ac610SCharles Manning
177*753ac610SCharles Manning if (!tags.chunk_used) {
178*753ac610SCharles Manning *state = YAFFS_BLOCK_STATE_EMPTY;
179*753ac610SCharles Manning } else {
180*753ac610SCharles Manning *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
181*753ac610SCharles Manning *seq_number = tags.seq_number;
182*753ac610SCharles Manning }
183*753ac610SCharles Manning }
184*753ac610SCharles Manning
185*753ac610SCharles Manning return YAFFS_OK;
186*753ac610SCharles Manning }
187*753ac610SCharles Manning
188*753ac610SCharles Manning
ynandif_InitialiseNAND(struct yaffs_dev * dev)189*753ac610SCharles Manning int ynandif_InitialiseNAND(struct yaffs_dev *dev)
190*753ac610SCharles Manning {
191*753ac610SCharles Manning struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
192*753ac610SCharles Manning
193*753ac610SCharles Manning geometry->initialise(dev);
194*753ac610SCharles Manning
195*753ac610SCharles Manning return YAFFS_OK;
196*753ac610SCharles Manning }
197*753ac610SCharles Manning
ynandif_Deinitialise_flash_fn(struct yaffs_dev * dev)198*753ac610SCharles Manning int ynandif_Deinitialise_flash_fn(struct yaffs_dev *dev)
199*753ac610SCharles Manning {
200*753ac610SCharles Manning struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
201*753ac610SCharles Manning
202*753ac610SCharles Manning geometry->deinitialise(dev);
203*753ac610SCharles Manning
204*753ac610SCharles Manning return YAFFS_OK;
205*753ac610SCharles Manning }
206*753ac610SCharles Manning
207*753ac610SCharles Manning
208*753ac610SCharles Manning struct yaffs_dev *
yaffs_add_dev_from_geometry(const YCHAR * name,const struct ynandif_Geometry * geometry)209*753ac610SCharles Manning yaffs_add_dev_from_geometry(const YCHAR *name,
210*753ac610SCharles Manning const struct ynandif_Geometry *geometry)
211*753ac610SCharles Manning {
212*753ac610SCharles Manning YCHAR *clonedName = malloc(sizeof(YCHAR) *
213*753ac610SCharles Manning (strnlen(name, YAFFS_MAX_NAME_LENGTH)+1));
214*753ac610SCharles Manning struct yaffs_dev *dev = malloc(sizeof(struct yaffs_dev));
215*753ac610SCharles Manning struct yaffs_param *param;
216*753ac610SCharles Manning
217*753ac610SCharles Manning if (dev && clonedName) {
218*753ac610SCharles Manning memset(dev, 0, sizeof(struct yaffs_dev));
219*753ac610SCharles Manning strcpy(clonedName, name);
220*753ac610SCharles Manning
221*753ac610SCharles Manning param = &dev->param;
222*753ac610SCharles Manning
223*753ac610SCharles Manning param->name = clonedName;
224*753ac610SCharles Manning param->write_chunk_tags_fn = ynandif_WriteChunkWithTagsToNAND;
225*753ac610SCharles Manning param->read_chunk_tags_fn = ynandif_ReadChunkWithTagsFromNAND;
226*753ac610SCharles Manning param->erase_fn = ynandif_EraseBlockInNAND;
227*753ac610SCharles Manning param->initialise_flash_fn = ynandif_InitialiseNAND;
228*753ac610SCharles Manning param->query_block_fn = ynandif_QueryNANDBlock;
229*753ac610SCharles Manning param->bad_block_fn = ynandif_MarkNANDBlockBad;
230*753ac610SCharles Manning param->n_caches = 20;
231*753ac610SCharles Manning param->start_block = geometry->start_block;
232*753ac610SCharles Manning param->end_block = geometry->end_block;
233*753ac610SCharles Manning param->total_bytes_per_chunk = geometry->dataSize;
234*753ac610SCharles Manning param->spare_bytes_per_chunk = geometry->spareSize;
235*753ac610SCharles Manning param->inband_tags = geometry->inband_tags;
236*753ac610SCharles Manning param->chunks_per_block = geometry->pagesPerBlock;
237*753ac610SCharles Manning param->use_nand_ecc = geometry->hasECC;
238*753ac610SCharles Manning param->is_yaffs2 = geometry->useYaffs2;
239*753ac610SCharles Manning param->n_reserved_blocks = 5;
240*753ac610SCharles Manning dev->driver_context = (void *)geometry;
241*753ac610SCharles Manning
242*753ac610SCharles Manning yaffs_add_device(dev);
243*753ac610SCharles Manning
244*753ac610SCharles Manning return dev;
245*753ac610SCharles Manning }
246*753ac610SCharles Manning
247*753ac610SCharles Manning free(dev);
248*753ac610SCharles Manning free(clonedName);
249*753ac610SCharles Manning
250*753ac610SCharles Manning return NULL;
251*753ac610SCharles Manning }
252