2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4 * Copyright (C) 2002-2011 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
7 * Created by Charles Manning <charles@aleph1.co.uk>
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.
14 #include "yaffs_guts.h"
15 #include "yaffs_trace.h"
16 #include "yaffs_packedtags2.h"
18 static int yaffs_tags_marshall_write(struct yaffs_dev
*dev
,
19 int nand_chunk
, const u8
*data
,
20 const struct yaffs_ext_tags
*tags
)
22 struct yaffs_packed_tags2 pt
;
25 int packed_tags_size
=
26 dev
->param
.no_tags_ecc
? sizeof(pt
.t
) : sizeof(pt
);
27 void *packed_tags_ptr
=
28 dev
->param
.no_tags_ecc
? (void *)&pt
.t
: (void *)&pt
;
30 yaffs_trace(YAFFS_TRACE_MTD
,
31 "yaffs_tags_marshall_write chunk %d data %p tags %p",
32 nand_chunk
, data
, tags
);
34 /* For yaffs2 writing there must be both data and tags.
35 * If we're using inband tags, then the tags are stuffed into
36 * the end of the data buffer.
40 else if (dev
->param
.inband_tags
) {
41 struct yaffs_packed_tags2_tags_only
*pt2tp
;
43 (struct yaffs_packed_tags2_tags_only
*)(data
+
45 data_bytes_per_chunk
);
46 yaffs_pack_tags2_tags_only(pt2tp
, tags
);
48 yaffs_pack_tags2(&pt
, tags
, !dev
->param
.no_tags_ecc
);
51 retval
= dev
->drv
.drv_write_chunk_fn(dev
, nand_chunk
,
52 data
, dev
->param
.total_bytes_per_chunk
,
53 (dev
->param
.inband_tags
) ? NULL
: packed_tags_ptr
,
54 (dev
->param
.inband_tags
) ? 0 : packed_tags_size
);
59 static int yaffs_tags_marshall_read(struct yaffs_dev
*dev
,
60 int nand_chunk
, u8
*data
,
61 struct yaffs_ext_tags
*tags
)
66 enum yaffs_ecc_result ecc_result
;
68 struct yaffs_packed_tags2 pt
;
70 int packed_tags_size
=
71 dev
->param
.no_tags_ecc
? sizeof(pt
.t
) : sizeof(pt
);
72 void *packed_tags_ptr
=
73 dev
->param
.no_tags_ecc
? (void *)&pt
.t
: (void *)&pt
;
75 yaffs_trace(YAFFS_TRACE_MTD
,
76 "yaffs_tags_marshall_read chunk %d data %p tags %p",
77 nand_chunk
, data
, tags
);
79 if (dev
->param
.inband_tags
) {
82 data
= yaffs_get_temp_buffer(dev
);
86 if (dev
->param
.inband_tags
|| (data
&& !tags
))
87 retval
= dev
->drv
.drv_read_chunk_fn(dev
, nand_chunk
,
88 data
, dev
->param
.total_bytes_per_chunk
,
92 retval
= dev
->drv
.drv_read_chunk_fn(dev
, nand_chunk
,
93 data
, dev
->param
.total_bytes_per_chunk
,
94 spare_buffer
, packed_tags_size
,
100 if (dev
->param
.inband_tags
) {
102 struct yaffs_packed_tags2_tags_only
*pt2tp
;
104 (struct yaffs_packed_tags2_tags_only
*)
105 &data
[dev
->data_bytes_per_chunk
];
106 yaffs_unpack_tags2_tags_only(tags
, pt2tp
);
109 memcpy(packed_tags_ptr
, spare_buffer
, packed_tags_size
);
110 yaffs_unpack_tags2(tags
, &pt
, !dev
->param
.no_tags_ecc
);
114 yaffs_release_temp_buffer(dev
, data
);
116 if (tags
&& ecc_result
== YAFFS_ECC_RESULT_UNFIXED
) {
117 tags
->ecc_result
= YAFFS_ECC_RESULT_UNFIXED
;
118 dev
->n_ecc_unfixed
++;
121 if (tags
&& ecc_result
== -YAFFS_ECC_RESULT_FIXED
) {
122 if (tags
->ecc_result
<= YAFFS_ECC_RESULT_NO_ERROR
)
123 tags
->ecc_result
= YAFFS_ECC_RESULT_FIXED
;
127 if (ecc_result
< YAFFS_ECC_RESULT_UNFIXED
)
133 static int yaffs_tags_marshall_query_block(struct yaffs_dev
*dev
, int block_no
,
134 enum yaffs_block_state
*state
,
139 yaffs_trace(YAFFS_TRACE_MTD
, "yaffs_tags_marshall_query_block %d",
142 retval
= dev
->drv
.drv_check_bad_fn(dev
, block_no
);
144 if (retval
== YAFFS_FAIL
) {
145 yaffs_trace(YAFFS_TRACE_MTD
, "block is bad");
147 *state
= YAFFS_BLOCK_STATE_DEAD
;
150 struct yaffs_ext_tags t
;
152 yaffs_tags_marshall_read(dev
,
153 block_no
* dev
->param
.chunks_per_block
,
157 *seq_number
= t
.seq_number
;
158 *state
= YAFFS_BLOCK_STATE_NEEDS_SCAN
;
161 *state
= YAFFS_BLOCK_STATE_EMPTY
;
165 yaffs_trace(YAFFS_TRACE_MTD
,
166 "block query returns seq %d state %d",
167 *seq_number
, *state
);
175 static int yaffs_tags_marshall_mark_bad(struct yaffs_dev
*dev
, int block_no
)
177 return dev
->drv
.drv_mark_bad_fn(dev
, block_no
);
182 void yaffs_tags_marshall_install(struct yaffs_dev
*dev
)
184 if (!dev
->param
.is_yaffs2
)
187 if (!dev
->tagger
.write_chunk_tags_fn
)
188 dev
->tagger
.write_chunk_tags_fn
= yaffs_tags_marshall_write
;
190 if (!dev
->tagger
.read_chunk_tags_fn
)
191 dev
->tagger
.read_chunk_tags_fn
= yaffs_tags_marshall_read
;
193 if (!dev
->tagger
.query_block_fn
)
194 dev
->tagger
.query_block_fn
= yaffs_tags_marshall_query_block
;
196 if (!dev
->tagger
.mark_bad_fn
)
197 dev
->tagger
.mark_bad_fn
= yaffs_tags_marshall_mark_bad
;