1*0a6a1f1dSLionel Sambuc /* $NetBSD: ebh.c,v 1.6 2015/02/07 04:21:11 christos Exp $ */
2d65f6f70SBen Gras
3d65f6f70SBen Gras /*-
4d65f6f70SBen Gras * Copyright (c) 2010 Department of Software Engineering,
5d65f6f70SBen Gras * University of Szeged, Hungary
6d65f6f70SBen Gras * Copyright (C) 2009 Ferenc Havasi <havasi@inf.u-szeged.hu>
7d65f6f70SBen Gras * Copyright (C) 2009 Zoltan Sogor <weth@inf.u-szeged.hu>
8d65f6f70SBen Gras * Copyright (C) 2009 David Tengeri <dtengeri@inf.u-szeged.hu>
9d65f6f70SBen Gras * Copyright (C) 2009 Tamas Toth <ttoth@inf.u-szeged.hu>
10d65f6f70SBen Gras * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
11d65f6f70SBen Gras * All rights reserved.
12d65f6f70SBen Gras *
13d65f6f70SBen Gras * This code is derived from software contributed to The NetBSD Foundation
14d65f6f70SBen Gras * by the Department of Software Engineering, University of Szeged, Hungary
15d65f6f70SBen Gras *
16d65f6f70SBen Gras * Redistribution and use in source and binary forms, with or without
17d65f6f70SBen Gras * modification, are permitted provided that the following conditions
18d65f6f70SBen Gras * are met:
19d65f6f70SBen Gras * 1. Redistributions of source code must retain the above copyright
20d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer.
21d65f6f70SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
22d65f6f70SBen Gras * notice, this list of conditions and the following disclaimer in the
23d65f6f70SBen Gras * documentation and/or other materials provided with the distribution.
24d65f6f70SBen Gras *
25d65f6f70SBen Gras * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26d65f6f70SBen Gras * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27d65f6f70SBen Gras * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28d65f6f70SBen Gras * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29d65f6f70SBen Gras * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30d65f6f70SBen Gras * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31d65f6f70SBen Gras * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32d65f6f70SBen Gras * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33d65f6f70SBen Gras * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34d65f6f70SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35d65f6f70SBen Gras * SUCH DAMAGE.
36d65f6f70SBen Gras */
37d65f6f70SBen Gras
38d65f6f70SBen Gras #include "ebh.h"
39d65f6f70SBen Gras
40d65f6f70SBen Gras /*****************************************************************************/
41d65f6f70SBen Gras /* Flash specific operations */
42d65f6f70SBen Gras /*****************************************************************************/
43d65f6f70SBen Gras int nor_create_eb_hdr(struct chfs_eb_hdr *ebhdr, int lnr);
44d65f6f70SBen Gras int nand_create_eb_hdr(struct chfs_eb_hdr *ebhdr, int lnr);
45d65f6f70SBen Gras int nor_calc_data_offs(struct chfs_ebh *ebh, int pebnr, int offset);
46d65f6f70SBen Gras int nand_calc_data_offs(struct chfs_ebh *ebh, int pebnr, int offset);
47d65f6f70SBen Gras int nor_read_eb_hdr(struct chfs_ebh *ebh, int pebnr, struct chfs_eb_hdr *ebhdr);
48d65f6f70SBen Gras int nand_read_eb_hdr(struct chfs_ebh *ebh, int pebnr, struct chfs_eb_hdr *ebhdr);
49d65f6f70SBen Gras int nor_write_eb_hdr(struct chfs_ebh *ebh, int pebnr, struct chfs_eb_hdr *ebhdr);
50d65f6f70SBen Gras int nand_write_eb_hdr(struct chfs_ebh *ebh, int pebnr,struct chfs_eb_hdr *ebhdr);
51d65f6f70SBen Gras int nor_check_eb_hdr(struct chfs_ebh *ebh, void *buf);
52d65f6f70SBen Gras int nand_check_eb_hdr(struct chfs_ebh *ebh, void *buf);
53d65f6f70SBen Gras int nor_mark_eb_hdr_dirty_flash(struct chfs_ebh *ebh, int pebnr, int lid);
54d65f6f70SBen Gras int nor_invalidate_eb_hdr(struct chfs_ebh *ebh, int pebnr);
55d65f6f70SBen Gras int mark_eb_hdr_free(struct chfs_ebh *ebh, int pebnr, int ec);
56d65f6f70SBen Gras
57d65f6f70SBen Gras int ltree_entry_cmp(struct chfs_ltree_entry *le1, struct chfs_ltree_entry *le2);
58d65f6f70SBen Gras int peb_in_use_cmp(struct chfs_peb *peb1, struct chfs_peb *peb2);
59d65f6f70SBen Gras int peb_free_cmp(struct chfs_peb *peb1, struct chfs_peb *peb2);
60d65f6f70SBen Gras int add_peb_to_erase_queue(struct chfs_ebh *ebh, int pebnr, int ec,struct peb_queue *queue);
61d65f6f70SBen Gras struct chfs_peb * find_peb_in_use(struct chfs_ebh *ebh, int pebnr);
62d65f6f70SBen Gras int add_peb_to_free(struct chfs_ebh *ebh, int pebnr, int ec);
63d65f6f70SBen Gras int add_peb_to_in_use(struct chfs_ebh *ebh, int pebnr, int ec);
64d65f6f70SBen Gras void erase_callback(struct flash_erase_instruction *ei);
65d65f6f70SBen Gras int free_peb(struct chfs_ebh *ebh);
66d65f6f70SBen Gras int release_peb(struct chfs_ebh *ebh, int pebnr);
67d65f6f70SBen Gras void erase_thread(void *data);
68d65f6f70SBen Gras static void erase_thread_start(struct chfs_ebh *ebh);
69d65f6f70SBen Gras static void erase_thread_stop(struct chfs_ebh *ebh);
70d65f6f70SBen Gras int scan_leb_used_cmp(struct chfs_scan_leb *sleb1, struct chfs_scan_leb *sleb2);
71d65f6f70SBen Gras int nor_scan_add_to_used(struct chfs_ebh *ebh, struct chfs_scan_info *si,struct chfs_eb_hdr *ebhdr, int pebnr, int leb_status);
72d65f6f70SBen Gras int nor_process_eb(struct chfs_ebh *ebh, struct chfs_scan_info *si,
73d65f6f70SBen Gras int pebnr, struct chfs_eb_hdr *ebhdr);
74d65f6f70SBen Gras int nand_scan_add_to_used(struct chfs_ebh *ebh, struct chfs_scan_info *si,struct chfs_eb_hdr *ebhdr, int pebnr);
75d65f6f70SBen Gras int nand_process_eb(struct chfs_ebh *ebh, struct chfs_scan_info *si,
76d65f6f70SBen Gras int pebnr, struct chfs_eb_hdr *ebhdr);
77d65f6f70SBen Gras struct chfs_scan_info *chfs_scan(struct chfs_ebh *ebh);
78d65f6f70SBen Gras void scan_info_destroy(struct chfs_scan_info *si);
79d65f6f70SBen Gras int scan_media(struct chfs_ebh *ebh);
80d65f6f70SBen Gras int get_peb(struct chfs_ebh *ebh);
81d65f6f70SBen Gras /**
82d65f6f70SBen Gras * nor_create_eb_hdr - creates an eraseblock header for NOR flash
83d65f6f70SBen Gras * @ebhdr: ebhdr to set
84d65f6f70SBen Gras * @lnr: LEB number
85d65f6f70SBen Gras */
86d65f6f70SBen Gras int
nor_create_eb_hdr(struct chfs_eb_hdr * ebhdr,int lnr)87d65f6f70SBen Gras nor_create_eb_hdr(struct chfs_eb_hdr *ebhdr, int lnr)
88d65f6f70SBen Gras {
89d65f6f70SBen Gras ebhdr->u.nor_hdr.lid = htole32(lnr);
90d65f6f70SBen Gras return 0;
91d65f6f70SBen Gras }
92d65f6f70SBen Gras
93d65f6f70SBen Gras /**
94d65f6f70SBen Gras * nand_create_eb_hdr - creates an eraseblock header for NAND flash
95d65f6f70SBen Gras * @ebhdr: ebhdr to set
96d65f6f70SBen Gras * @lnr: LEB number
97d65f6f70SBen Gras */
98d65f6f70SBen Gras int
nand_create_eb_hdr(struct chfs_eb_hdr * ebhdr,int lnr)99d65f6f70SBen Gras nand_create_eb_hdr(struct chfs_eb_hdr *ebhdr, int lnr)
100d65f6f70SBen Gras {
101d65f6f70SBen Gras ebhdr->u.nand_hdr.lid = htole32(lnr);
102d65f6f70SBen Gras return 0;
103d65f6f70SBen Gras }
104d65f6f70SBen Gras
105d65f6f70SBen Gras /**
106d65f6f70SBen Gras * nor_calc_data_offs - calculates data offset on NOR flash
107d65f6f70SBen Gras * @ebh: chfs eraseblock handler
108d65f6f70SBen Gras * @pebnr: eraseblock number
109d65f6f70SBen Gras * @offset: offset within the eraseblock
110d65f6f70SBen Gras */
111d65f6f70SBen Gras int
nor_calc_data_offs(struct chfs_ebh * ebh,int pebnr,int offset)112d65f6f70SBen Gras nor_calc_data_offs(struct chfs_ebh *ebh, int pebnr, int offset)
113d65f6f70SBen Gras {
114d65f6f70SBen Gras return pebnr * ebh->flash_if->erasesize + offset +
115d65f6f70SBen Gras CHFS_EB_EC_HDR_SIZE + CHFS_EB_HDR_NOR_SIZE;
116d65f6f70SBen Gras }
117d65f6f70SBen Gras
118d65f6f70SBen Gras /**
119d65f6f70SBen Gras * nand_calc_data_offs - calculates data offset on NAND flash
120d65f6f70SBen Gras * @ebh: chfs eraseblock handler
121d65f6f70SBen Gras * @pebnr: eraseblock number
122d65f6f70SBen Gras * @offset: offset within the eraseblock
123d65f6f70SBen Gras */
124d65f6f70SBen Gras int
nand_calc_data_offs(struct chfs_ebh * ebh,int pebnr,int offset)125d65f6f70SBen Gras nand_calc_data_offs(struct chfs_ebh *ebh, int pebnr, int offset)
126d65f6f70SBen Gras {
127d65f6f70SBen Gras return pebnr * ebh->flash_if->erasesize + offset +
128d65f6f70SBen Gras 2 * ebh->flash_if->page_size;
129d65f6f70SBen Gras }
130d65f6f70SBen Gras
131d65f6f70SBen Gras /**
132d65f6f70SBen Gras * nor_read_eb_hdr - read ereaseblock header from NOR flash
133d65f6f70SBen Gras *
134d65f6f70SBen Gras * @ebh: chfs eraseblock handler
135d65f6f70SBen Gras * @pebnr: eraseblock number
136d65f6f70SBen Gras * @ebhdr: whereto store the data
137d65f6f70SBen Gras *
138d65f6f70SBen Gras * Reads the eraseblock header from media.
139d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
140d65f6f70SBen Gras */
141d65f6f70SBen Gras int
nor_read_eb_hdr(struct chfs_ebh * ebh,int pebnr,struct chfs_eb_hdr * ebhdr)142d65f6f70SBen Gras nor_read_eb_hdr(struct chfs_ebh *ebh,
143d65f6f70SBen Gras int pebnr, struct chfs_eb_hdr *ebhdr)
144d65f6f70SBen Gras {
145d65f6f70SBen Gras int ret;
146d65f6f70SBen Gras size_t retlen;
147d65f6f70SBen Gras off_t ofs = pebnr * ebh->flash_if->erasesize;
148d65f6f70SBen Gras
149d65f6f70SBen Gras KASSERT(pebnr >= 0 && pebnr < ebh->peb_nr);
150d65f6f70SBen Gras
151d65f6f70SBen Gras ret = flash_read(ebh->flash_dev,
152d65f6f70SBen Gras ofs, CHFS_EB_EC_HDR_SIZE,
153d65f6f70SBen Gras &retlen, (unsigned char *) &ebhdr->ec_hdr);
154d65f6f70SBen Gras
155d65f6f70SBen Gras if (ret || retlen != CHFS_EB_EC_HDR_SIZE)
156d65f6f70SBen Gras return ret;
157d65f6f70SBen Gras
158d65f6f70SBen Gras ofs += CHFS_EB_EC_HDR_SIZE;
159d65f6f70SBen Gras ret = flash_read(ebh->flash_dev,
160d65f6f70SBen Gras ofs, CHFS_EB_HDR_NOR_SIZE,
161d65f6f70SBen Gras &retlen, (unsigned char *) &ebhdr->u.nor_hdr);
162d65f6f70SBen Gras
163d65f6f70SBen Gras if (ret || retlen != CHFS_EB_HDR_NOR_SIZE)
164d65f6f70SBen Gras return ret;
165d65f6f70SBen Gras
166d65f6f70SBen Gras return 0;
167d65f6f70SBen Gras }
168d65f6f70SBen Gras
169d65f6f70SBen Gras /**
170d65f6f70SBen Gras * nand_read_eb_hdr - read ereaseblock header from NAND flash
171d65f6f70SBen Gras *
172d65f6f70SBen Gras * @ebh: chfs eraseblock handler
173d65f6f70SBen Gras * @pebnr: eraseblock number
174d65f6f70SBen Gras * @ebhdr: whereto store the data
175d65f6f70SBen Gras *
176d65f6f70SBen Gras * Reads the eraseblock header from media. It is on the first two page.
177d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
178d65f6f70SBen Gras */
179d65f6f70SBen Gras int
nand_read_eb_hdr(struct chfs_ebh * ebh,int pebnr,struct chfs_eb_hdr * ebhdr)180d65f6f70SBen Gras nand_read_eb_hdr(struct chfs_ebh *ebh, int pebnr,
181d65f6f70SBen Gras struct chfs_eb_hdr *ebhdr)
182d65f6f70SBen Gras {
183d65f6f70SBen Gras int ret;
184d65f6f70SBen Gras size_t retlen;
185d65f6f70SBen Gras off_t ofs;
186d65f6f70SBen Gras
187d65f6f70SBen Gras KASSERT(pebnr >= 0 && pebnr < ebh->peb_nr);
188d65f6f70SBen Gras
189d65f6f70SBen Gras /* Read erase counter header from the first page. */
190d65f6f70SBen Gras ofs = pebnr * ebh->flash_if->erasesize;
191d65f6f70SBen Gras ret = flash_read(ebh->flash_dev,
192d65f6f70SBen Gras ofs, CHFS_EB_EC_HDR_SIZE, &retlen,
193d65f6f70SBen Gras (unsigned char *) &ebhdr->ec_hdr);
194d65f6f70SBen Gras if (ret || retlen != CHFS_EB_EC_HDR_SIZE)
195d65f6f70SBen Gras return ret;
196d65f6f70SBen Gras
197d65f6f70SBen Gras /* Read NAND eraseblock header from the second page */
198d65f6f70SBen Gras ofs += ebh->flash_if->page_size;
199d65f6f70SBen Gras ret = flash_read(ebh->flash_dev,
200d65f6f70SBen Gras ofs, CHFS_EB_HDR_NAND_SIZE, &retlen,
201d65f6f70SBen Gras (unsigned char *) &ebhdr->u.nand_hdr);
202d65f6f70SBen Gras if (ret || retlen != CHFS_EB_HDR_NAND_SIZE)
203d65f6f70SBen Gras return ret;
204d65f6f70SBen Gras
205d65f6f70SBen Gras return 0;
206d65f6f70SBen Gras }
207d65f6f70SBen Gras
208d65f6f70SBen Gras /**
209d65f6f70SBen Gras * nor_write_eb_hdr - write ereaseblock header to NOR flash
210d65f6f70SBen Gras *
211d65f6f70SBen Gras * @ebh: chfs eraseblock handler
212d65f6f70SBen Gras * @pebnr: eraseblock number whereto write
213d65f6f70SBen Gras * @ebh: ebh to write
214d65f6f70SBen Gras *
215d65f6f70SBen Gras * Writes the eraseblock header to media.
216d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
217d65f6f70SBen Gras */
218d65f6f70SBen Gras int
nor_write_eb_hdr(struct chfs_ebh * ebh,int pebnr,struct chfs_eb_hdr * ebhdr)219d65f6f70SBen Gras nor_write_eb_hdr(struct chfs_ebh *ebh, int pebnr, struct chfs_eb_hdr *ebhdr)
220d65f6f70SBen Gras {
221d65f6f70SBen Gras int ret, crc;
222d65f6f70SBen Gras size_t retlen;
223d65f6f70SBen Gras
224d65f6f70SBen Gras off_t ofs = pebnr * ebh->flash_if->erasesize + CHFS_EB_EC_HDR_SIZE;
225d65f6f70SBen Gras
226d65f6f70SBen Gras ebhdr->u.nor_hdr.lid = ebhdr->u.nor_hdr.lid
227d65f6f70SBen Gras | htole32(CHFS_LID_NOT_DIRTY_BIT);
228d65f6f70SBen Gras
229d65f6f70SBen Gras crc = crc32(0, (uint8_t *)&ebhdr->u.nor_hdr + 4,
230d65f6f70SBen Gras CHFS_EB_HDR_NOR_SIZE - 4);
231d65f6f70SBen Gras ebhdr->u.nand_hdr.crc = htole32(crc);
232d65f6f70SBen Gras
233d65f6f70SBen Gras KASSERT(pebnr >= 0 && pebnr < ebh->peb_nr);
234d65f6f70SBen Gras
235d65f6f70SBen Gras ret = flash_write(ebh->flash_dev,
236d65f6f70SBen Gras ofs, CHFS_EB_HDR_NOR_SIZE, &retlen,
237d65f6f70SBen Gras (unsigned char *) &ebhdr->u.nor_hdr);
238d65f6f70SBen Gras
239d65f6f70SBen Gras if (ret || retlen != CHFS_EB_HDR_NOR_SIZE)
240d65f6f70SBen Gras return ret;
241d65f6f70SBen Gras
242d65f6f70SBen Gras return 0;
243d65f6f70SBen Gras }
244d65f6f70SBen Gras
245d65f6f70SBen Gras /**
246d65f6f70SBen Gras * nand_write_eb_hdr - write ereaseblock header to NAND flash
247d65f6f70SBen Gras *
248d65f6f70SBen Gras * @ebh: chfs eraseblock handler
249d65f6f70SBen Gras * @pebnr: eraseblock number whereto write
250d65f6f70SBen Gras * @ebh: ebh to write
251d65f6f70SBen Gras *
252d65f6f70SBen Gras * Writes the eraseblock header to media.
253d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
254d65f6f70SBen Gras */
255d65f6f70SBen Gras int
nand_write_eb_hdr(struct chfs_ebh * ebh,int pebnr,struct chfs_eb_hdr * ebhdr)256d65f6f70SBen Gras nand_write_eb_hdr(struct chfs_ebh *ebh, int pebnr,
257d65f6f70SBen Gras struct chfs_eb_hdr *ebhdr)
258d65f6f70SBen Gras {
259d65f6f70SBen Gras int ret, crc;
260d65f6f70SBen Gras size_t retlen;
261d65f6f70SBen Gras flash_off_t ofs;
262d65f6f70SBen Gras
263d65f6f70SBen Gras KASSERT(pebnr >= 0 && pebnr < ebh->peb_nr);
264d65f6f70SBen Gras
265d65f6f70SBen Gras ofs = pebnr * ebh->flash_if->erasesize +
266d65f6f70SBen Gras ebh->flash_if->page_size;
267d65f6f70SBen Gras
268d65f6f70SBen Gras ebhdr->u.nand_hdr.serial = htole64(++(*ebh->max_serial));
269d65f6f70SBen Gras
270d65f6f70SBen Gras crc = crc32(0, (uint8_t *)&ebhdr->u.nand_hdr + 4,
271d65f6f70SBen Gras CHFS_EB_HDR_NAND_SIZE - 4);
272d65f6f70SBen Gras ebhdr->u.nand_hdr.crc = htole32(crc);
273d65f6f70SBen Gras
274d65f6f70SBen Gras ret = flash_write(ebh->flash_dev, ofs,
275d65f6f70SBen Gras CHFS_EB_HDR_NAND_SIZE, &retlen,
276d65f6f70SBen Gras (unsigned char *) &ebhdr->u.nand_hdr);
277d65f6f70SBen Gras
278d65f6f70SBen Gras if (ret || retlen != CHFS_EB_HDR_NAND_SIZE)
279d65f6f70SBen Gras return ret;
280d65f6f70SBen Gras
281d65f6f70SBen Gras return 0;
282d65f6f70SBen Gras }
283d65f6f70SBen Gras
284d65f6f70SBen Gras /**
285d65f6f70SBen Gras * nor_check_eb_hdr - check ereaseblock header read from NOR flash
286d65f6f70SBen Gras *
287d65f6f70SBen Gras * @ebh: chfs eraseblock handler
288d65f6f70SBen Gras * @buf: eraseblock header to check
289d65f6f70SBen Gras *
290d65f6f70SBen Gras * Returns eraseblock header status.
291d65f6f70SBen Gras */
292d65f6f70SBen Gras int
nor_check_eb_hdr(struct chfs_ebh * ebh,void * buf)293d65f6f70SBen Gras nor_check_eb_hdr(struct chfs_ebh *ebh, void *buf)
294d65f6f70SBen Gras {
295d65f6f70SBen Gras uint32_t magic, crc, hdr_crc;
296d65f6f70SBen Gras struct chfs_eb_hdr *ebhdr = buf;
297d65f6f70SBen Gras le32 lid_save;
298d65f6f70SBen Gras
299d65f6f70SBen Gras //check is there a header
300d65f6f70SBen Gras if (check_pattern((void *) &ebhdr->ec_hdr,
301d65f6f70SBen Gras 0xFF, 0, CHFS_EB_EC_HDR_SIZE)) {
302d65f6f70SBen Gras dbg_ebh("no header found\n");
303d65f6f70SBen Gras return EBHDR_LEB_NO_HDR;
304d65f6f70SBen Gras }
305d65f6f70SBen Gras
306d65f6f70SBen Gras // check magic
307d65f6f70SBen Gras magic = le32toh(ebhdr->ec_hdr.magic);
308d65f6f70SBen Gras if (magic != CHFS_MAGIC_BITMASK) {
309d65f6f70SBen Gras dbg_ebh("bad magic bitmask(exp: %x found %x)\n",
310d65f6f70SBen Gras CHFS_MAGIC_BITMASK, magic);
311d65f6f70SBen Gras return EBHDR_LEB_BADMAGIC;
312d65f6f70SBen Gras }
313d65f6f70SBen Gras
314d65f6f70SBen Gras // check CRC_EC
315d65f6f70SBen Gras hdr_crc = le32toh(ebhdr->ec_hdr.crc_ec);
316d65f6f70SBen Gras crc = crc32(0, (uint8_t *) &ebhdr->ec_hdr + 8, 4);
317d65f6f70SBen Gras if (hdr_crc != crc) {
318d65f6f70SBen Gras dbg_ebh("bad crc_ec found\n");
319d65f6f70SBen Gras return EBHDR_LEB_BADCRC;
320d65f6f70SBen Gras }
321d65f6f70SBen Gras
322d65f6f70SBen Gras /* check if the PEB is free: magic, crc_ec and erase_cnt is good and
323d65f6f70SBen Gras * everything else is FFF..
324d65f6f70SBen Gras */
325d65f6f70SBen Gras if (check_pattern((void *) &ebhdr->u.nor_hdr, 0xFF, 0,
326d65f6f70SBen Gras CHFS_EB_HDR_NOR_SIZE)) {
327d65f6f70SBen Gras dbg_ebh("free peb found\n");
328d65f6f70SBen Gras return EBHDR_LEB_FREE;
329d65f6f70SBen Gras }
330d65f6f70SBen Gras
331d65f6f70SBen Gras // check invalidated (CRC == LID == 0)
332d65f6f70SBen Gras if (ebhdr->u.nor_hdr.crc == 0 && ebhdr->u.nor_hdr.lid == 0) {
333d65f6f70SBen Gras dbg_ebh("invalidated ebhdr found\n");
334d65f6f70SBen Gras return EBHDR_LEB_INVALIDATED;
335d65f6f70SBen Gras }
336d65f6f70SBen Gras
337d65f6f70SBen Gras // check CRC
338d65f6f70SBen Gras hdr_crc = le32toh(ebhdr->u.nor_hdr.crc);
339d65f6f70SBen Gras lid_save = ebhdr->u.nor_hdr.lid;
340d65f6f70SBen Gras
341d65f6f70SBen Gras // mark lid as not dirty for crc calc
342d65f6f70SBen Gras ebhdr->u.nor_hdr.lid = ebhdr->u.nor_hdr.lid | htole32(
343d65f6f70SBen Gras CHFS_LID_NOT_DIRTY_BIT);
344d65f6f70SBen Gras crc = crc32(0, (uint8_t *) &ebhdr->u.nor_hdr + 4,
345d65f6f70SBen Gras CHFS_EB_HDR_NOR_SIZE - 4);
346d65f6f70SBen Gras // restore the original lid value in ebh
347d65f6f70SBen Gras ebhdr->u.nor_hdr.lid = lid_save;
348d65f6f70SBen Gras
349d65f6f70SBen Gras if (crc != hdr_crc) {
350d65f6f70SBen Gras dbg_ebh("bad crc found\n");
351d65f6f70SBen Gras return EBHDR_LEB_BADCRC;
352d65f6f70SBen Gras }
353d65f6f70SBen Gras
354d65f6f70SBen Gras // check dirty
355d65f6f70SBen Gras if (!(le32toh(lid_save) & CHFS_LID_NOT_DIRTY_BIT)) {
356d65f6f70SBen Gras dbg_ebh("dirty ebhdr found\n");
357d65f6f70SBen Gras return EBHDR_LEB_DIRTY;
358d65f6f70SBen Gras }
359d65f6f70SBen Gras
360d65f6f70SBen Gras return EBHDR_LEB_OK;
361d65f6f70SBen Gras }
362d65f6f70SBen Gras
363d65f6f70SBen Gras /**
364d65f6f70SBen Gras * nand_check_eb_hdr - check ereaseblock header read from NAND flash
365d65f6f70SBen Gras *
366d65f6f70SBen Gras * @ebh: chfs eraseblock handler
367d65f6f70SBen Gras * @buf: eraseblock header to check
368d65f6f70SBen Gras *
369d65f6f70SBen Gras * Returns eraseblock header status.
370d65f6f70SBen Gras */
371d65f6f70SBen Gras int
nand_check_eb_hdr(struct chfs_ebh * ebh,void * buf)372d65f6f70SBen Gras nand_check_eb_hdr(struct chfs_ebh *ebh, void *buf)
373d65f6f70SBen Gras {
374d65f6f70SBen Gras uint32_t magic, crc, hdr_crc;
375d65f6f70SBen Gras struct chfs_eb_hdr *ebhdr = buf;
376d65f6f70SBen Gras
377d65f6f70SBen Gras //check is there a header
378d65f6f70SBen Gras if (check_pattern((void *) &ebhdr->ec_hdr,
379d65f6f70SBen Gras 0xFF, 0, CHFS_EB_EC_HDR_SIZE)) {
380d65f6f70SBen Gras dbg_ebh("no header found\n");
381d65f6f70SBen Gras return EBHDR_LEB_NO_HDR;
382d65f6f70SBen Gras }
383d65f6f70SBen Gras
384d65f6f70SBen Gras // check magic
385d65f6f70SBen Gras magic = le32toh(ebhdr->ec_hdr.magic);
386d65f6f70SBen Gras if (magic != CHFS_MAGIC_BITMASK) {
387d65f6f70SBen Gras dbg_ebh("bad magic bitmask(exp: %x found %x)\n",
388d65f6f70SBen Gras CHFS_MAGIC_BITMASK, magic);
389d65f6f70SBen Gras return EBHDR_LEB_BADMAGIC;
390d65f6f70SBen Gras }
391d65f6f70SBen Gras
392d65f6f70SBen Gras // check CRC_EC
393d65f6f70SBen Gras hdr_crc = le32toh(ebhdr->ec_hdr.crc_ec);
394d65f6f70SBen Gras crc = crc32(0, (uint8_t *) &ebhdr->ec_hdr + 8, 4);
395d65f6f70SBen Gras if (hdr_crc != crc) {
396d65f6f70SBen Gras dbg_ebh("bad crc_ec found\n");
397d65f6f70SBen Gras return EBHDR_LEB_BADCRC;
398d65f6f70SBen Gras }
399d65f6f70SBen Gras
400d65f6f70SBen Gras /* check if the PEB is free: magic, crc_ec and erase_cnt is good and
401d65f6f70SBen Gras * everything else is FFF..
402d65f6f70SBen Gras */
403d65f6f70SBen Gras if (check_pattern((void *) &ebhdr->u.nand_hdr, 0xFF, 0,
404d65f6f70SBen Gras CHFS_EB_HDR_NAND_SIZE)) {
405d65f6f70SBen Gras dbg_ebh("free peb found\n");
406d65f6f70SBen Gras return EBHDR_LEB_FREE;
407d65f6f70SBen Gras }
408d65f6f70SBen Gras
409d65f6f70SBen Gras // check CRC
410d65f6f70SBen Gras hdr_crc = le32toh(ebhdr->u.nand_hdr.crc);
411d65f6f70SBen Gras
412d65f6f70SBen Gras crc = crc32(0, (uint8_t *) &ebhdr->u.nand_hdr + 4,
413d65f6f70SBen Gras CHFS_EB_HDR_NAND_SIZE - 4);
414d65f6f70SBen Gras
415d65f6f70SBen Gras if (crc != hdr_crc) {
416d65f6f70SBen Gras dbg_ebh("bad crc found\n");
417d65f6f70SBen Gras return EBHDR_LEB_BADCRC;
418d65f6f70SBen Gras }
419d65f6f70SBen Gras
420d65f6f70SBen Gras return EBHDR_LEB_OK;
421d65f6f70SBen Gras }
422d65f6f70SBen Gras
423d65f6f70SBen Gras /**
424d65f6f70SBen Gras * nor_mark_eb_hdr_dirty_flash- mark ereaseblock header dirty on NOR flash
425d65f6f70SBen Gras *
426d65f6f70SBen Gras * @ebh: chfs eraseblock handler
427d65f6f70SBen Gras * @pebnr: eraseblock number
428*0a6a1f1dSLionel Sambuc * @lid: leb id (its bit number 31 will be set to 0)
429d65f6f70SBen Gras *
430d65f6f70SBen Gras * It pulls the CHFS_LID_NOT_DIRTY_BIT to zero on flash.
431d65f6f70SBen Gras *
432d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
433d65f6f70SBen Gras */
434d65f6f70SBen Gras int
nor_mark_eb_hdr_dirty_flash(struct chfs_ebh * ebh,int pebnr,int lid)435d65f6f70SBen Gras nor_mark_eb_hdr_dirty_flash(struct chfs_ebh *ebh, int pebnr, int lid)
436d65f6f70SBen Gras {
437d65f6f70SBen Gras int ret;
438d65f6f70SBen Gras size_t retlen;
439d65f6f70SBen Gras off_t ofs;
440d65f6f70SBen Gras
441d65f6f70SBen Gras /* mark leb id dirty */
442d65f6f70SBen Gras lid = htole32(lid & CHFS_LID_DIRTY_BIT_MASK);
443d65f6f70SBen Gras
444d65f6f70SBen Gras /* calculate position */
445d65f6f70SBen Gras ofs = pebnr * ebh->flash_if->erasesize + CHFS_EB_EC_HDR_SIZE
446d65f6f70SBen Gras + CHFS_GET_MEMBER_POS(struct chfs_nor_eb_hdr , lid);
447d65f6f70SBen Gras
448d65f6f70SBen Gras ret = flash_write(ebh->flash_dev, ofs, sizeof(lid), &retlen,
449d65f6f70SBen Gras (unsigned char *) &lid);
450d65f6f70SBen Gras if (ret || retlen != sizeof(lid)) {
451d65f6f70SBen Gras chfs_err("can't mark peb dirty");
452d65f6f70SBen Gras return ret;
453d65f6f70SBen Gras }
454d65f6f70SBen Gras
455d65f6f70SBen Gras return 0;
456d65f6f70SBen Gras }
457d65f6f70SBen Gras
458d65f6f70SBen Gras /**
459d65f6f70SBen Gras * nor_invalidate_eb_hdr - invalidate ereaseblock header on NOR flash
460d65f6f70SBen Gras *
461d65f6f70SBen Gras * @ebh: chfs eraseblock handler
462d65f6f70SBen Gras * @pebnr: eraseblock number
463d65f6f70SBen Gras *
464d65f6f70SBen Gras * Sets crc and lip field to zero.
465d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
466d65f6f70SBen Gras */
467d65f6f70SBen Gras int
nor_invalidate_eb_hdr(struct chfs_ebh * ebh,int pebnr)468d65f6f70SBen Gras nor_invalidate_eb_hdr(struct chfs_ebh *ebh, int pebnr)
469d65f6f70SBen Gras {
470d65f6f70SBen Gras int ret;
471d65f6f70SBen Gras size_t retlen;
472d65f6f70SBen Gras off_t ofs;
473d65f6f70SBen Gras char zero_buf[CHFS_INVALIDATE_SIZE];
474d65f6f70SBen Gras
475d65f6f70SBen Gras /* fill with zero */
476d65f6f70SBen Gras memset(zero_buf, 0x0, CHFS_INVALIDATE_SIZE);
477d65f6f70SBen Gras
478d65f6f70SBen Gras /* calculate position (!!! lid is directly behind crc !!!) */
479d65f6f70SBen Gras ofs = pebnr * ebh->flash_if->erasesize + CHFS_EB_EC_HDR_SIZE
480d65f6f70SBen Gras + CHFS_GET_MEMBER_POS(struct chfs_nor_eb_hdr, crc);
481d65f6f70SBen Gras
482d65f6f70SBen Gras ret = flash_write(ebh->flash_dev,
483d65f6f70SBen Gras ofs, CHFS_INVALIDATE_SIZE, &retlen,
484d65f6f70SBen Gras (unsigned char *) &zero_buf);
485d65f6f70SBen Gras if (ret || retlen != CHFS_INVALIDATE_SIZE) {
486d65f6f70SBen Gras chfs_err("can't invalidate peb");
487d65f6f70SBen Gras return ret;
488d65f6f70SBen Gras }
489d65f6f70SBen Gras
490d65f6f70SBen Gras return 0;
491d65f6f70SBen Gras }
492d65f6f70SBen Gras
493d65f6f70SBen Gras /**
494d65f6f70SBen Gras * mark_eb_hdr_free - free ereaseblock header on NOR or NAND flash
495d65f6f70SBen Gras *
496d65f6f70SBen Gras * @ebh: chfs eraseblock handler
497d65f6f70SBen Gras * @pebnr: eraseblock number
498d65f6f70SBen Gras * @ec: erase counter of PEB
499d65f6f70SBen Gras *
500d65f6f70SBen Gras * Write out the magic and erase counter to the physical eraseblock.
501d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
502d65f6f70SBen Gras */
503d65f6f70SBen Gras int
mark_eb_hdr_free(struct chfs_ebh * ebh,int pebnr,int ec)504d65f6f70SBen Gras mark_eb_hdr_free(struct chfs_ebh *ebh, int pebnr, int ec)
505d65f6f70SBen Gras {
506d65f6f70SBen Gras int ret, crc;
507d65f6f70SBen Gras size_t retlen;
508d65f6f70SBen Gras off_t ofs;
509d65f6f70SBen Gras struct chfs_eb_hdr *ebhdr;
510d65f6f70SBen Gras ebhdr = kmem_alloc(sizeof(struct chfs_eb_hdr), KM_SLEEP);
511d65f6f70SBen Gras
512d65f6f70SBen Gras ebhdr->ec_hdr.magic = htole32(CHFS_MAGIC_BITMASK);
513d65f6f70SBen Gras ebhdr->ec_hdr.erase_cnt = htole32(ec);
514d65f6f70SBen Gras crc = crc32(0, (uint8_t *) &ebhdr->ec_hdr + 8, 4);
515d65f6f70SBen Gras ebhdr->ec_hdr.crc_ec = htole32(crc);
516d65f6f70SBen Gras
517d65f6f70SBen Gras ofs = pebnr * ebh->flash_if->erasesize;
518d65f6f70SBen Gras
519d65f6f70SBen Gras KASSERT(sizeof(ebhdr->ec_hdr) == CHFS_EB_EC_HDR_SIZE);
520d65f6f70SBen Gras
521d65f6f70SBen Gras ret = flash_write(ebh->flash_dev,
522d65f6f70SBen Gras ofs, CHFS_EB_EC_HDR_SIZE, &retlen,
523d65f6f70SBen Gras (unsigned char *) &ebhdr->ec_hdr);
524d65f6f70SBen Gras
525d65f6f70SBen Gras if (ret || retlen != CHFS_EB_EC_HDR_SIZE) {
526d65f6f70SBen Gras chfs_err("can't mark peb as free: %d\n", pebnr);
527d65f6f70SBen Gras kmem_free(ebhdr, sizeof(struct chfs_eb_hdr));
528d65f6f70SBen Gras return ret;
529d65f6f70SBen Gras }
530d65f6f70SBen Gras
531d65f6f70SBen Gras kmem_free(ebhdr, sizeof(struct chfs_eb_hdr));
532d65f6f70SBen Gras return 0;
533d65f6f70SBen Gras }
534d65f6f70SBen Gras
535d65f6f70SBen Gras /*****************************************************************************/
536d65f6f70SBen Gras /* End of Flash specific operations */
537d65f6f70SBen Gras /*****************************************************************************/
538d65f6f70SBen Gras
539d65f6f70SBen Gras /*****************************************************************************/
540d65f6f70SBen Gras /* Lock Tree */
541d65f6f70SBen Gras /*****************************************************************************/
542d65f6f70SBen Gras
543d65f6f70SBen Gras int
ltree_entry_cmp(struct chfs_ltree_entry * le1,struct chfs_ltree_entry * le2)544d65f6f70SBen Gras ltree_entry_cmp(struct chfs_ltree_entry *le1,
545d65f6f70SBen Gras struct chfs_ltree_entry *le2)
546d65f6f70SBen Gras {
547d65f6f70SBen Gras return (le1->lnr - le2->lnr);
548d65f6f70SBen Gras }
549d65f6f70SBen Gras
550d65f6f70SBen Gras /* Generate functions for Lock tree's red-black tree */
551d65f6f70SBen Gras RB_PROTOTYPE( ltree_rbtree, chfs_ltree_entry, rb, ltree_entry_cmp);
552d65f6f70SBen Gras RB_GENERATE( ltree_rbtree, chfs_ltree_entry, rb, ltree_entry_cmp);
553d65f6f70SBen Gras
554d65f6f70SBen Gras
555d65f6f70SBen Gras /**
556d65f6f70SBen Gras * ltree_lookup - looks up a logical eraseblock in the lock tree
557d65f6f70SBen Gras * @ebh: chfs eraseblock handler
558d65f6f70SBen Gras * @lid: identifier of the logical eraseblock
559d65f6f70SBen Gras *
560d65f6f70SBen Gras * This function returns a pointer to the wanted &struct chfs_ltree_entry
561d65f6f70SBen Gras * if the logical eraseblock is in the lock tree, so it is locked, NULL
562d65f6f70SBen Gras * otherwise.
563d65f6f70SBen Gras * @ebh->ltree_lock has to be locked!
564d65f6f70SBen Gras */
565d65f6f70SBen Gras static struct chfs_ltree_entry *
ltree_lookup(struct chfs_ebh * ebh,int lnr)566d65f6f70SBen Gras ltree_lookup(struct chfs_ebh *ebh, int lnr)
567d65f6f70SBen Gras {
568d65f6f70SBen Gras struct chfs_ltree_entry le, *result;
569d65f6f70SBen Gras le.lnr = lnr;
570d65f6f70SBen Gras result = RB_FIND(ltree_rbtree, &ebh->ltree, &le);
571d65f6f70SBen Gras return result;
572d65f6f70SBen Gras }
573d65f6f70SBen Gras
574d65f6f70SBen Gras /**
575d65f6f70SBen Gras * ltree_add_entry - add an entry to the lock tree
576d65f6f70SBen Gras * @ebh: chfs eraseblock handler
577d65f6f70SBen Gras * @lnr: identifier of the logical eraseblock
578d65f6f70SBen Gras *
579d65f6f70SBen Gras * This function adds a new logical eraseblock entry identified with @lnr to the
580d65f6f70SBen Gras * lock tree. If the entry is already in the tree, it increases the user
581d65f6f70SBen Gras * counter.
582d65f6f70SBen Gras * Returns NULL if can not allocate memory for lock tree entry, or a pointer
583d65f6f70SBen Gras * to the inserted entry otherwise.
584d65f6f70SBen Gras */
585d65f6f70SBen Gras static struct chfs_ltree_entry *
ltree_add_entry(struct chfs_ebh * ebh,int lnr)586d65f6f70SBen Gras ltree_add_entry(struct chfs_ebh *ebh, int lnr)
587d65f6f70SBen Gras {
588d65f6f70SBen Gras struct chfs_ltree_entry *le, *result;
589d65f6f70SBen Gras
590d65f6f70SBen Gras le = kmem_alloc(sizeof(struct chfs_ltree_entry), KM_SLEEP);
591d65f6f70SBen Gras
592d65f6f70SBen Gras le->lnr = lnr;
593d65f6f70SBen Gras le->users = 1;
594d65f6f70SBen Gras rw_init(&le->mutex);
595d65f6f70SBen Gras
596d65f6f70SBen Gras //dbg_ebh("enter ltree lock\n");
597d65f6f70SBen Gras mutex_enter(&ebh->ltree_lock);
598d65f6f70SBen Gras //dbg_ebh("insert\n");
599d65f6f70SBen Gras result = RB_INSERT(ltree_rbtree, &ebh->ltree, le);
600d65f6f70SBen Gras //dbg_ebh("inserted\n");
601d65f6f70SBen Gras if (result) {
602d65f6f70SBen Gras //The entry is already in the tree
603d65f6f70SBen Gras result->users++;
604d65f6f70SBen Gras kmem_free(le, sizeof(struct chfs_ltree_entry));
605d65f6f70SBen Gras }
606d65f6f70SBen Gras else {
607d65f6f70SBen Gras result = le;
608d65f6f70SBen Gras }
609d65f6f70SBen Gras mutex_exit(&ebh->ltree_lock);
610d65f6f70SBen Gras
611d65f6f70SBen Gras return result;
612d65f6f70SBen Gras }
613d65f6f70SBen Gras
614d65f6f70SBen Gras /**
615d65f6f70SBen Gras * leb_read_lock - lock a logical eraseblock for read
616d65f6f70SBen Gras * @ebh: chfs eraseblock handler
617d65f6f70SBen Gras * @lnr: identifier of the logical eraseblock
618d65f6f70SBen Gras *
619d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
620d65f6f70SBen Gras */
621d65f6f70SBen Gras static int
leb_read_lock(struct chfs_ebh * ebh,int lnr)622d65f6f70SBen Gras leb_read_lock(struct chfs_ebh *ebh, int lnr)
623d65f6f70SBen Gras {
624d65f6f70SBen Gras struct chfs_ltree_entry *le;
625d65f6f70SBen Gras
626d65f6f70SBen Gras le = ltree_add_entry(ebh, lnr);
627d65f6f70SBen Gras if (!le)
628d65f6f70SBen Gras return ENOMEM;
629d65f6f70SBen Gras
630d65f6f70SBen Gras rw_enter(&le->mutex, RW_READER);
631d65f6f70SBen Gras return 0;
632d65f6f70SBen Gras }
633d65f6f70SBen Gras
634d65f6f70SBen Gras /**
635d65f6f70SBen Gras * leb_read_unlock - unlock a logical eraseblock from read
636d65f6f70SBen Gras * @ebh: chfs eraseblock handler
637d65f6f70SBen Gras * @lnr: identifier of the logical eraseblock
638d65f6f70SBen Gras *
639d65f6f70SBen Gras * This function unlocks a logical eraseblock from read and delete it from the
640d65f6f70SBen Gras * lock tree is there are no more users of it.
641d65f6f70SBen Gras */
642d65f6f70SBen Gras static void
leb_read_unlock(struct chfs_ebh * ebh,int lnr)643d65f6f70SBen Gras leb_read_unlock(struct chfs_ebh *ebh, int lnr)
644d65f6f70SBen Gras {
645d65f6f70SBen Gras struct chfs_ltree_entry *le;
646d65f6f70SBen Gras
647d65f6f70SBen Gras mutex_enter(&ebh->ltree_lock);
648d65f6f70SBen Gras //dbg_ebh("LOCK: ebh->ltree_lock spin locked in leb_read_unlock()\n");
649d65f6f70SBen Gras le = ltree_lookup(ebh, lnr);
650d65f6f70SBen Gras if (!le)
651d65f6f70SBen Gras goto out;
652d65f6f70SBen Gras
653d65f6f70SBen Gras le->users -= 1;
654d65f6f70SBen Gras KASSERT(le->users >= 0);
655d65f6f70SBen Gras rw_exit(&le->mutex);
656d65f6f70SBen Gras if (le->users == 0) {
657d65f6f70SBen Gras le = RB_REMOVE(ltree_rbtree, &ebh->ltree, le);
658d65f6f70SBen Gras if (le) {
659d65f6f70SBen Gras KASSERT(!rw_lock_held(&le->mutex));
660d65f6f70SBen Gras rw_destroy(&le->mutex);
661d65f6f70SBen Gras
662d65f6f70SBen Gras kmem_free(le, sizeof(struct chfs_ltree_entry));
663d65f6f70SBen Gras }
664d65f6f70SBen Gras }
665d65f6f70SBen Gras
666d65f6f70SBen Gras out:
667d65f6f70SBen Gras mutex_exit(&ebh->ltree_lock);
668d65f6f70SBen Gras //dbg_ebh("UNLOCK: ebh->ltree_lock spin unlocked in leb_read_unlock()\n");
669d65f6f70SBen Gras }
670d65f6f70SBen Gras
671d65f6f70SBen Gras /**
672d65f6f70SBen Gras * leb_write_lock - lock a logical eraseblock for write
673d65f6f70SBen Gras * @ebh: chfs eraseblock handler
674d65f6f70SBen Gras * @lnr: identifier of the logical eraseblock
675d65f6f70SBen Gras *
676d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
677d65f6f70SBen Gras */
678d65f6f70SBen Gras static int
leb_write_lock(struct chfs_ebh * ebh,int lnr)679d65f6f70SBen Gras leb_write_lock(struct chfs_ebh *ebh, int lnr)
680d65f6f70SBen Gras {
681d65f6f70SBen Gras struct chfs_ltree_entry *le;
682d65f6f70SBen Gras
683d65f6f70SBen Gras le = ltree_add_entry(ebh, lnr);
684d65f6f70SBen Gras if (!le)
685d65f6f70SBen Gras return ENOMEM;
686d65f6f70SBen Gras
687d65f6f70SBen Gras rw_enter(&le->mutex, RW_WRITER);
688d65f6f70SBen Gras return 0;
689d65f6f70SBen Gras }
690d65f6f70SBen Gras
691d65f6f70SBen Gras /**
692d65f6f70SBen Gras * leb_write_unlock - unlock a logical eraseblock from write
693d65f6f70SBen Gras * @ebh: chfs eraseblock handler
694d65f6f70SBen Gras * @lnr: identifier of the logical eraseblock
695d65f6f70SBen Gras *
696d65f6f70SBen Gras * This function unlocks a logical eraseblock from write and delete it from the
697d65f6f70SBen Gras * lock tree is there are no more users of it.
698d65f6f70SBen Gras */
699d65f6f70SBen Gras static void
leb_write_unlock(struct chfs_ebh * ebh,int lnr)700d65f6f70SBen Gras leb_write_unlock(struct chfs_ebh *ebh, int lnr)
701d65f6f70SBen Gras {
702d65f6f70SBen Gras struct chfs_ltree_entry *le;
703d65f6f70SBen Gras
704d65f6f70SBen Gras mutex_enter(&ebh->ltree_lock);
705d65f6f70SBen Gras //dbg_ebh("LOCK: ebh->ltree_lock spin locked in leb_write_unlock()\n");
706d65f6f70SBen Gras le = ltree_lookup(ebh, lnr);
707d65f6f70SBen Gras if (!le)
708d65f6f70SBen Gras goto out;
709d65f6f70SBen Gras
710d65f6f70SBen Gras le->users -= 1;
711d65f6f70SBen Gras KASSERT(le->users >= 0);
712d65f6f70SBen Gras rw_exit(&le->mutex);
713d65f6f70SBen Gras if (le->users == 0) {
714d65f6f70SBen Gras RB_REMOVE(ltree_rbtree, &ebh->ltree, le);
715d65f6f70SBen Gras
716d65f6f70SBen Gras KASSERT(!rw_lock_held(&le->mutex));
717d65f6f70SBen Gras rw_destroy(&le->mutex);
718d65f6f70SBen Gras
719d65f6f70SBen Gras kmem_free(le, sizeof(struct chfs_ltree_entry));
720d65f6f70SBen Gras }
721d65f6f70SBen Gras
722d65f6f70SBen Gras out:
723d65f6f70SBen Gras mutex_exit(&ebh->ltree_lock);
724d65f6f70SBen Gras //dbg_ebh("UNLOCK: ebh->ltree_lock spin unlocked in leb_write_unlock()\n");
725d65f6f70SBen Gras }
726d65f6f70SBen Gras
727d65f6f70SBen Gras /*****************************************************************************/
728d65f6f70SBen Gras /* End of Lock Tree */
729d65f6f70SBen Gras /*****************************************************************************/
730d65f6f70SBen Gras
731d65f6f70SBen Gras /*****************************************************************************/
732d65f6f70SBen Gras /* Erase related operations */
733d65f6f70SBen Gras /*****************************************************************************/
734d65f6f70SBen Gras
735d65f6f70SBen Gras /**
736d65f6f70SBen Gras * If the first argument is smaller than the second, the function
737d65f6f70SBen Gras * returns a value smaller than zero. If they are equal, the function re-
738d65f6f70SBen Gras * turns zero. Otherwise, it should return a value greater than zero.
739d65f6f70SBen Gras */
740d65f6f70SBen Gras int
peb_in_use_cmp(struct chfs_peb * peb1,struct chfs_peb * peb2)741d65f6f70SBen Gras peb_in_use_cmp(struct chfs_peb *peb1, struct chfs_peb *peb2)
742d65f6f70SBen Gras {
743d65f6f70SBen Gras return (peb1->pebnr - peb2->pebnr);
744d65f6f70SBen Gras }
745d65f6f70SBen Gras
746d65f6f70SBen Gras int
peb_free_cmp(struct chfs_peb * peb1,struct chfs_peb * peb2)747d65f6f70SBen Gras peb_free_cmp(struct chfs_peb *peb1, struct chfs_peb *peb2)
748d65f6f70SBen Gras {
749d65f6f70SBen Gras int comp;
750d65f6f70SBen Gras
751d65f6f70SBen Gras comp = peb1->erase_cnt - peb2->erase_cnt;
752d65f6f70SBen Gras if (0 == comp)
753d65f6f70SBen Gras comp = peb1->pebnr - peb2->pebnr;
754d65f6f70SBen Gras
755d65f6f70SBen Gras return comp;
756d65f6f70SBen Gras }
757d65f6f70SBen Gras
758d65f6f70SBen Gras /* Generate functions for in use PEB's red-black tree */
759d65f6f70SBen Gras RB_PROTOTYPE(peb_in_use_rbtree, chfs_peb, u.rb, peb_in_use_cmp);
760d65f6f70SBen Gras RB_GENERATE(peb_in_use_rbtree, chfs_peb, u.rb, peb_in_use_cmp);
761d65f6f70SBen Gras RB_PROTOTYPE(peb_free_rbtree, chfs_peb, u.rb, peb_free_cmp);
762d65f6f70SBen Gras RB_GENERATE(peb_free_rbtree, chfs_peb, u.rb, peb_free_cmp);
763d65f6f70SBen Gras
764d65f6f70SBen Gras /**
765d65f6f70SBen Gras * add_peb_to_erase_queue: adds a PEB to to_erase/fully_erased queue
766d65f6f70SBen Gras * @ebh - chfs eraseblock handler
767d65f6f70SBen Gras * @pebnr - physical eraseblock's number
768d65f6f70SBen Gras * @ec - erase counter of PEB
769d65f6f70SBen Gras * @queue: the queue to add to
770d65f6f70SBen Gras *
771d65f6f70SBen Gras * This function adds a PEB to the erase queue specified by @queue.
772d65f6f70SBen Gras * The @ebh->erase_lock must be locked before using this.
773d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
774d65f6f70SBen Gras */
775d65f6f70SBen Gras int
add_peb_to_erase_queue(struct chfs_ebh * ebh,int pebnr,int ec,struct peb_queue * queue)776d65f6f70SBen Gras add_peb_to_erase_queue(struct chfs_ebh *ebh, int pebnr, int ec,
777d65f6f70SBen Gras struct peb_queue *queue)
778d65f6f70SBen Gras {
779d65f6f70SBen Gras struct chfs_peb *peb;
780d65f6f70SBen Gras
781d65f6f70SBen Gras peb = kmem_alloc(sizeof(struct chfs_peb), KM_SLEEP);
782d65f6f70SBen Gras
783d65f6f70SBen Gras peb->erase_cnt = ec;
784d65f6f70SBen Gras peb->pebnr = pebnr;
785d65f6f70SBen Gras
786d65f6f70SBen Gras TAILQ_INSERT_TAIL(queue, peb, u.queue);
787d65f6f70SBen Gras
788d65f6f70SBen Gras return 0;
789d65f6f70SBen Gras
790d65f6f70SBen Gras }
791d65f6f70SBen Gras //TODO
792d65f6f70SBen Gras /**
793d65f6f70SBen Gras * find_peb_in_use - looks up a PEB in the RB-tree of used blocks
794d65f6f70SBen Gras * @ebh - chfs eraseblock handler
795d65f6f70SBen Gras *
796d65f6f70SBen Gras * This function returns a pointer to the PEB found in the tree,
797d65f6f70SBen Gras * NULL otherwise.
798d65f6f70SBen Gras * The @ebh->erase_lock must be locked before using this.
799d65f6f70SBen Gras */
800d65f6f70SBen Gras struct chfs_peb *
find_peb_in_use(struct chfs_ebh * ebh,int pebnr)801d65f6f70SBen Gras find_peb_in_use(struct chfs_ebh *ebh, int pebnr)
802d65f6f70SBen Gras {
803d65f6f70SBen Gras struct chfs_peb peb, *result;
804d65f6f70SBen Gras peb.pebnr = pebnr;
805d65f6f70SBen Gras result = RB_FIND(peb_in_use_rbtree, &ebh->in_use, &peb);
806d65f6f70SBen Gras return result;
807d65f6f70SBen Gras }
808d65f6f70SBen Gras
809d65f6f70SBen Gras /**
810d65f6f70SBen Gras * add_peb_to_free - adds a PEB to the RB-tree of free PEBs
811d65f6f70SBen Gras * @ebh - chfs eraseblock handler
812d65f6f70SBen Gras * @pebnr - physical eraseblock's number
813d65f6f70SBen Gras * @ec - erase counter of PEB
814d65f6f70SBen Gras *
815d65f6f70SBen Gras *
816d65f6f70SBen Gras * This function adds a physical eraseblock to the RB-tree of free PEBs
817d65f6f70SBen Gras * stored in the @ebh. The key is the erase counter and pebnr.
818d65f6f70SBen Gras * The @ebh->erase_lock must be locked before using this.
819d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
820d65f6f70SBen Gras */
821d65f6f70SBen Gras int
add_peb_to_free(struct chfs_ebh * ebh,int pebnr,int ec)822d65f6f70SBen Gras add_peb_to_free(struct chfs_ebh *ebh, int pebnr, int ec)
823d65f6f70SBen Gras {
824d65f6f70SBen Gras struct chfs_peb *peb, *result;
825d65f6f70SBen Gras
826d65f6f70SBen Gras peb = kmem_alloc(sizeof(struct chfs_peb), KM_SLEEP);
827d65f6f70SBen Gras
828d65f6f70SBen Gras peb->erase_cnt = ec;
829d65f6f70SBen Gras peb->pebnr = pebnr;
830d65f6f70SBen Gras result = RB_INSERT(peb_free_rbtree, &ebh->free, peb);
831*0a6a1f1dSLionel Sambuc if (result) {
832*0a6a1f1dSLionel Sambuc kmem_free(peb, sizeof(struct chfs_peb));
833d65f6f70SBen Gras return 1;
834*0a6a1f1dSLionel Sambuc }
835d65f6f70SBen Gras
836d65f6f70SBen Gras return 0;
837d65f6f70SBen Gras }
838d65f6f70SBen Gras
839d65f6f70SBen Gras /**
840d65f6f70SBen Gras * add_peb_to_in_use - adds a PEB to the RB-tree of used PEBs
841d65f6f70SBen Gras * @ebh - chfs eraseblock handler
842d65f6f70SBen Gras * @pebnr - physical eraseblock's number
843d65f6f70SBen Gras * @ec - erase counter of PEB
844d65f6f70SBen Gras *
845d65f6f70SBen Gras *
846d65f6f70SBen Gras * This function adds a physical eraseblock to the RB-tree of used PEBs
847d65f6f70SBen Gras * stored in the @ebh. The key is pebnr.
848d65f6f70SBen Gras * The @ebh->erase_lock must be locked before using this.
849d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
850d65f6f70SBen Gras */
851d65f6f70SBen Gras int
add_peb_to_in_use(struct chfs_ebh * ebh,int pebnr,int ec)852d65f6f70SBen Gras add_peb_to_in_use(struct chfs_ebh *ebh, int pebnr, int ec)
853d65f6f70SBen Gras {
854d65f6f70SBen Gras struct chfs_peb *peb, *result;
855d65f6f70SBen Gras
856d65f6f70SBen Gras peb = kmem_alloc(sizeof(struct chfs_peb), KM_SLEEP);
857d65f6f70SBen Gras
858d65f6f70SBen Gras peb->erase_cnt = ec;
859d65f6f70SBen Gras peb->pebnr = pebnr;
860d65f6f70SBen Gras result = RB_INSERT(peb_in_use_rbtree, &ebh->in_use, peb);
861*0a6a1f1dSLionel Sambuc if (result) {
862*0a6a1f1dSLionel Sambuc kmem_free(peb, sizeof(struct chfs_peb));
863d65f6f70SBen Gras return 1;
864*0a6a1f1dSLionel Sambuc }
865d65f6f70SBen Gras
866d65f6f70SBen Gras return 0;
867d65f6f70SBen Gras }
868d65f6f70SBen Gras
869d65f6f70SBen Gras /**
870d65f6f70SBen Gras * erase_callback - callback function for flash erase
871d65f6f70SBen Gras * @ei: erase information
872d65f6f70SBen Gras */
873d65f6f70SBen Gras void
erase_callback(struct flash_erase_instruction * ei)874d65f6f70SBen Gras erase_callback(struct flash_erase_instruction *ei)
875d65f6f70SBen Gras {
876d65f6f70SBen Gras int err;
877d65f6f70SBen Gras struct chfs_erase_info_priv *priv = (void *) ei->ei_priv;
878d65f6f70SBen Gras //dbg_ebh("ERASE_CALLBACK() CALLED\n");
879d65f6f70SBen Gras struct chfs_ebh *ebh = priv->ebh;
880d65f6f70SBen Gras struct chfs_peb *peb = priv->peb;
881d65f6f70SBen Gras
882d65f6f70SBen Gras peb->erase_cnt += 1;
883d65f6f70SBen Gras
884d65f6f70SBen Gras if (ei->ei_state == FLASH_ERASE_DONE) {
885d65f6f70SBen Gras
886d65f6f70SBen Gras /* Write out erase counter */
887d65f6f70SBen Gras err = ebh->ops->mark_eb_hdr_free(ebh,
888d65f6f70SBen Gras peb->pebnr, peb->erase_cnt);
889d65f6f70SBen Gras if (err) {
890d65f6f70SBen Gras /* cannot mark PEB as free,so erase it again */
891d65f6f70SBen Gras chfs_err(
892d65f6f70SBen Gras "cannot mark eraseblock as free, PEB: %d\n",
893d65f6f70SBen Gras peb->pebnr);
894d65f6f70SBen Gras mutex_enter(&ebh->erase_lock);
895d65f6f70SBen Gras /*dbg_ebh("LOCK: ebh->erase_lock spin locked in erase_callback() "
896d65f6f70SBen Gras "after mark ebhdr free\n");*/
897d65f6f70SBen Gras add_peb_to_erase_queue(ebh, peb->pebnr, peb->erase_cnt,
898d65f6f70SBen Gras &ebh->to_erase);
899d65f6f70SBen Gras mutex_exit(&ebh->erase_lock);
900d65f6f70SBen Gras /*dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in erase_callback() "
901d65f6f70SBen Gras "after mark ebhdr free\n");*/
902d65f6f70SBen Gras kmem_free(peb, sizeof(struct chfs_peb));
903d65f6f70SBen Gras return;
904d65f6f70SBen Gras }
905d65f6f70SBen Gras
906d65f6f70SBen Gras mutex_enter(&ebh->erase_lock);
907d65f6f70SBen Gras /*dbg_ebh("LOCK: ebh->erase_lock spin locked in erase_callback()\n");*/
908d65f6f70SBen Gras err = add_peb_to_free(ebh, peb->pebnr, peb->erase_cnt);
909d65f6f70SBen Gras mutex_exit(&ebh->erase_lock);
910d65f6f70SBen Gras /*dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in erase_callback()\n");*/
911d65f6f70SBen Gras kmem_free(peb, sizeof(struct chfs_peb));
912d65f6f70SBen Gras } else {
913d65f6f70SBen Gras /*
914d65f6f70SBen Gras * Erase is finished, but there was a problem,
915d65f6f70SBen Gras * so erase PEB again
916d65f6f70SBen Gras */
917d65f6f70SBen Gras chfs_err("erase failed, state is: 0x%x\n", ei->ei_state);
918d65f6f70SBen Gras add_peb_to_erase_queue(ebh, peb->pebnr, peb->erase_cnt, &ebh->to_erase);
919d65f6f70SBen Gras kmem_free(peb, sizeof(struct chfs_peb));
920d65f6f70SBen Gras }
921d65f6f70SBen Gras }
922d65f6f70SBen Gras
923d65f6f70SBen Gras /**
924d65f6f70SBen Gras * free_peb: free a PEB
925d65f6f70SBen Gras * @ebh: chfs eraseblock handler
926d65f6f70SBen Gras *
927d65f6f70SBen Gras * This function erases the first physical eraseblock from one of the erase
928d65f6f70SBen Gras * lists and adds to the RB-tree of free PEBs.
929d65f6f70SBen Gras * Returns zero in case of succes, error code in case of fail.
930d65f6f70SBen Gras */
931d65f6f70SBen Gras int
free_peb(struct chfs_ebh * ebh)932d65f6f70SBen Gras free_peb(struct chfs_ebh *ebh)
933d65f6f70SBen Gras {
934d65f6f70SBen Gras int err, retries = 0;
935d65f6f70SBen Gras off_t ofs;
936d65f6f70SBen Gras struct chfs_peb *peb = NULL;
937d65f6f70SBen Gras struct flash_erase_instruction *ei;
938d65f6f70SBen Gras
939d65f6f70SBen Gras KASSERT(mutex_owned(&ebh->erase_lock));
940d65f6f70SBen Gras
941d65f6f70SBen Gras if (!TAILQ_EMPTY(&ebh->fully_erased)) {
942d65f6f70SBen Gras //dbg_ebh("[FREE PEB] got a fully erased block\n");
943d65f6f70SBen Gras peb = TAILQ_FIRST(&ebh->fully_erased);
944d65f6f70SBen Gras TAILQ_REMOVE(&ebh->fully_erased, peb, u.queue);
945d65f6f70SBen Gras err = ebh->ops->mark_eb_hdr_free(ebh,
946d65f6f70SBen Gras peb->pebnr, peb->erase_cnt);
947d65f6f70SBen Gras if (err) {
948d65f6f70SBen Gras goto out_free;
949d65f6f70SBen Gras }
950d65f6f70SBen Gras err = add_peb_to_free(ebh, peb->pebnr, peb->erase_cnt);
951d65f6f70SBen Gras goto out_free;
952d65f6f70SBen Gras }
953d65f6f70SBen Gras /* Erase PEB */
954d65f6f70SBen Gras //dbg_ebh("[FREE PEB] eraseing a block\n");
955d65f6f70SBen Gras peb = TAILQ_FIRST(&ebh->to_erase);
956d65f6f70SBen Gras TAILQ_REMOVE(&ebh->to_erase, peb, u.queue);
957d65f6f70SBen Gras mutex_exit(&ebh->erase_lock);
958d65f6f70SBen Gras //dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in free_peb()\n");
959d65f6f70SBen Gras ofs = peb->pebnr * ebh->flash_if->erasesize;
960d65f6f70SBen Gras
961d65f6f70SBen Gras /* XXX where do we free this? */
962d65f6f70SBen Gras ei = kmem_alloc(sizeof(struct flash_erase_instruction)
963d65f6f70SBen Gras + sizeof(struct chfs_erase_info_priv), KM_SLEEP);
964d65f6f70SBen Gras retry:
965d65f6f70SBen Gras memset(ei, 0, sizeof(*ei));
966d65f6f70SBen Gras
967d65f6f70SBen Gras // ei->ei_if = ebh->flash_if;
968d65f6f70SBen Gras ei->ei_addr = ofs;
969d65f6f70SBen Gras ei->ei_len = ebh->flash_if->erasesize;
970d65f6f70SBen Gras ei->ei_callback = erase_callback;
971d65f6f70SBen Gras ei->ei_priv = (unsigned long) (&ei[1]);
972d65f6f70SBen Gras
973d65f6f70SBen Gras ((struct chfs_erase_info_priv *) ei->ei_priv)->ebh = ebh;
974d65f6f70SBen Gras ((struct chfs_erase_info_priv *) ei->ei_priv)->peb = peb;
975d65f6f70SBen Gras
976d65f6f70SBen Gras err = flash_erase(ebh->flash_dev, ei);
977d65f6f70SBen Gras dbg_ebh("erased peb: %d\n", peb->pebnr);
978d65f6f70SBen Gras
979d65f6f70SBen Gras /* einval would mean we did something wrong */
980d65f6f70SBen Gras KASSERT(err != EINVAL);
981d65f6f70SBen Gras
982d65f6f70SBen Gras if (err) {
983d65f6f70SBen Gras dbg_ebh("errno: %d, ei->ei_state: %d\n", err, ei->ei_state);
984d65f6f70SBen Gras if (CHFS_MAX_GET_PEB_RETRIES < ++retries &&
985d65f6f70SBen Gras ei->ei_state == FLASH_ERASE_FAILED) {
986d65f6f70SBen Gras /* The block went bad mark it */
987d65f6f70SBen Gras dbg_ebh("ebh markbad! 0x%jx\n", (uintmax_t )ofs);
988d65f6f70SBen Gras err = flash_block_markbad(ebh->flash_dev, ofs);
989d65f6f70SBen Gras if (!err) {
990d65f6f70SBen Gras ebh->peb_nr--;
991d65f6f70SBen Gras }
992d65f6f70SBen Gras
993d65f6f70SBen Gras goto out;
994d65f6f70SBen Gras }
995d65f6f70SBen Gras chfs_err("can not erase PEB: %d, try again\n", peb->pebnr);
996d65f6f70SBen Gras goto retry;
997d65f6f70SBen Gras }
998d65f6f70SBen Gras
999d65f6f70SBen Gras out:
1000d65f6f70SBen Gras /* lock the erase_lock, because it was locked
1001d65f6f70SBen Gras * when the function was called */
1002d65f6f70SBen Gras mutex_enter(&ebh->erase_lock);
1003d65f6f70SBen Gras return err;
1004d65f6f70SBen Gras
1005d65f6f70SBen Gras out_free:
1006d65f6f70SBen Gras kmem_free(peb, sizeof(struct chfs_peb));
1007d65f6f70SBen Gras return err;
1008d65f6f70SBen Gras }
1009d65f6f70SBen Gras
1010d65f6f70SBen Gras /**
1011d65f6f70SBen Gras * release_peb - schedule an erase for the PEB
1012d65f6f70SBen Gras * @ebh: chfs eraseblock handler
1013d65f6f70SBen Gras * @pebnr: physical eraseblock number
1014d65f6f70SBen Gras *
1015d65f6f70SBen Gras * This function get the peb identified by @pebnr from the in_use RB-tree of
1016d65f6f70SBen Gras * @ebh, removes it and schedule an erase for it.
1017d65f6f70SBen Gras *
1018d65f6f70SBen Gras * Returns zero on success, error code in case of fail.
1019d65f6f70SBen Gras */
1020d65f6f70SBen Gras int
release_peb(struct chfs_ebh * ebh,int pebnr)1021d65f6f70SBen Gras release_peb(struct chfs_ebh *ebh, int pebnr)
1022d65f6f70SBen Gras {
1023d65f6f70SBen Gras int err = 0;
1024d65f6f70SBen Gras struct chfs_peb *peb;
1025d65f6f70SBen Gras
1026d65f6f70SBen Gras mutex_enter(&ebh->erase_lock);
1027d65f6f70SBen Gras
1028d65f6f70SBen Gras //dbg_ebh("LOCK: ebh->erase_lock spin locked in release_peb()\n");
1029d65f6f70SBen Gras peb = find_peb_in_use(ebh, pebnr);
1030d65f6f70SBen Gras if (!peb) {
1031d65f6f70SBen Gras chfs_err("LEB is mapped, but is not in the 'in_use' "
1032d65f6f70SBen Gras "tree of ebh\n");
1033d65f6f70SBen Gras goto out_unlock;
1034d65f6f70SBen Gras }
1035d65f6f70SBen Gras err = add_peb_to_erase_queue(ebh, peb->pebnr, peb->erase_cnt,
1036d65f6f70SBen Gras &ebh->to_erase);
1037d65f6f70SBen Gras
1038d65f6f70SBen Gras if (err)
1039d65f6f70SBen Gras goto out_unlock;
1040d65f6f70SBen Gras
1041d65f6f70SBen Gras RB_REMOVE(peb_in_use_rbtree, &ebh->in_use, peb);
1042d65f6f70SBen Gras out_unlock:
1043d65f6f70SBen Gras mutex_exit(&ebh->erase_lock);
1044d65f6f70SBen Gras //dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in release_peb()"
1045d65f6f70SBen Gras // " at out_unlock\n");
1046d65f6f70SBen Gras return err;
1047d65f6f70SBen Gras }
1048d65f6f70SBen Gras
1049d65f6f70SBen Gras /**
1050d65f6f70SBen Gras * erase_thread - background thread for erasing PEBs
1051d65f6f70SBen Gras * @data: pointer to the eraseblock handler
1052d65f6f70SBen Gras */
1053d65f6f70SBen Gras /*void
1054d65f6f70SBen Gras erase_thread(void *data)
1055d65f6f70SBen Gras {
1056d65f6f70SBen Gras struct chfs_ebh *ebh = data;
1057d65f6f70SBen Gras
1058d65f6f70SBen Gras dbg_ebh("erase thread started\n");
1059d65f6f70SBen Gras while (ebh->bg_erase.eth_running) {
1060d65f6f70SBen Gras int err;
1061d65f6f70SBen Gras
1062d65f6f70SBen Gras mutex_enter(&ebh->erase_lock);
1063d65f6f70SBen Gras dbg_ebh("LOCK: ebh->erase_lock spin locked in erase_thread()\n");
1064d65f6f70SBen Gras if (TAILQ_EMPTY(&ebh->to_erase) && TAILQ_EMPTY(&ebh->fully_erased)) {
1065d65f6f70SBen Gras dbg_ebh("thread has nothing to do\n");
1066d65f6f70SBen Gras mutex_exit(&ebh->erase_lock);
1067d65f6f70SBen Gras mutex_enter(&ebh->bg_erase.eth_thread_mtx);
1068d65f6f70SBen Gras cv_timedwait_sig(&ebh->bg_erase.eth_wakeup,
1069d65f6f70SBen Gras &ebh->bg_erase.eth_thread_mtx, mstohz(100));
1070d65f6f70SBen Gras mutex_exit(&ebh->bg_erase.eth_thread_mtx);
1071d65f6f70SBen Gras
1072d65f6f70SBen Gras dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in erase_thread()\n");
1073d65f6f70SBen Gras continue;
1074d65f6f70SBen Gras }
1075d65f6f70SBen Gras mutex_exit(&ebh->erase_lock);
1076d65f6f70SBen Gras dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in erase_thread()\n");
1077d65f6f70SBen Gras
1078d65f6f70SBen Gras err = free_peb(ebh);
1079d65f6f70SBen Gras if (err)
1080d65f6f70SBen Gras chfs_err("freeing PEB failed in the background thread: %d\n", err);
1081d65f6f70SBen Gras
1082d65f6f70SBen Gras }
1083d65f6f70SBen Gras dbg_ebh("erase thread stopped\n");
1084d65f6f70SBen Gras kthread_exit(0);
1085d65f6f70SBen Gras }*/
1086d65f6f70SBen Gras
1087d65f6f70SBen Gras /**
1088d65f6f70SBen Gras * erase_thread - background thread for erasing PEBs
1089d65f6f70SBen Gras * @data: pointer to the eraseblock handler
1090d65f6f70SBen Gras */
1091d65f6f70SBen Gras void
erase_thread(void * data)1092d65f6f70SBen Gras erase_thread(void *data) {
1093d65f6f70SBen Gras dbg_ebh("[EBH THREAD] erase thread started\n");
1094d65f6f70SBen Gras
1095d65f6f70SBen Gras struct chfs_ebh *ebh = data;
1096d65f6f70SBen Gras int err;
1097d65f6f70SBen Gras
1098d65f6f70SBen Gras mutex_enter(&ebh->erase_lock);
1099d65f6f70SBen Gras while (ebh->bg_erase.eth_running) {
1100d65f6f70SBen Gras if (TAILQ_EMPTY(&ebh->to_erase) &&
1101d65f6f70SBen Gras TAILQ_EMPTY(&ebh->fully_erased)) {
1102d65f6f70SBen Gras cv_timedwait_sig(&ebh->bg_erase.eth_wakeup,
1103d65f6f70SBen Gras &ebh->erase_lock, mstohz(100));
1104d65f6f70SBen Gras } else {
1105d65f6f70SBen Gras /* XXX exiting this mutex is a bit odd here as
1106d65f6f70SBen Gras * free_peb instantly reenters it...
1107d65f6f70SBen Gras */
1108d65f6f70SBen Gras err = free_peb(ebh);
1109d65f6f70SBen Gras mutex_exit(&ebh->erase_lock);
1110d65f6f70SBen Gras if (err) {
1111d65f6f70SBen Gras chfs_err("freeing PEB failed in the"
1112d65f6f70SBen Gras " background thread: %d\n", err);
1113d65f6f70SBen Gras }
1114d65f6f70SBen Gras mutex_enter(&ebh->erase_lock);
1115d65f6f70SBen Gras }
1116d65f6f70SBen Gras }
1117d65f6f70SBen Gras mutex_exit(&ebh->erase_lock);
1118d65f6f70SBen Gras
1119d65f6f70SBen Gras dbg_ebh("[EBH THREAD] erase thread stopped\n");
1120d65f6f70SBen Gras kthread_exit(0);
1121d65f6f70SBen Gras }
1122d65f6f70SBen Gras
1123d65f6f70SBen Gras /**
1124d65f6f70SBen Gras * erase_thread_start - init and start erase thread
1125d65f6f70SBen Gras * @ebh: eraseblock handler
1126d65f6f70SBen Gras */
1127d65f6f70SBen Gras static void
erase_thread_start(struct chfs_ebh * ebh)1128d65f6f70SBen Gras erase_thread_start(struct chfs_ebh *ebh)
1129d65f6f70SBen Gras {
1130d65f6f70SBen Gras cv_init(&ebh->bg_erase.eth_wakeup, "ebheracv");
1131d65f6f70SBen Gras
1132d65f6f70SBen Gras ebh->bg_erase.eth_running = true;
1133d65f6f70SBen Gras kthread_create(PRI_NONE, KTHREAD_MPSAFE | KTHREAD_MUSTJOIN, NULL,
1134d65f6f70SBen Gras erase_thread, ebh, &ebh->bg_erase.eth_thread, "ebherase");
1135d65f6f70SBen Gras }
1136d65f6f70SBen Gras
1137d65f6f70SBen Gras /**
1138d65f6f70SBen Gras * erase_thread_stop - stop background erase thread
1139d65f6f70SBen Gras * @ebh: eraseblock handler
1140d65f6f70SBen Gras */
1141d65f6f70SBen Gras static void
erase_thread_stop(struct chfs_ebh * ebh)1142d65f6f70SBen Gras erase_thread_stop(struct chfs_ebh *ebh)
1143d65f6f70SBen Gras {
1144d65f6f70SBen Gras ebh->bg_erase.eth_running = false;
1145d65f6f70SBen Gras cv_signal(&ebh->bg_erase.eth_wakeup);
1146d65f6f70SBen Gras dbg_ebh("[EBH THREAD STOP] signaled\n");
1147d65f6f70SBen Gras
1148d65f6f70SBen Gras kthread_join(ebh->bg_erase.eth_thread);
1149d65f6f70SBen Gras #ifdef BROKEN_KTH_JOIN
1150d65f6f70SBen Gras kpause("chfsebhjointh", false, mstohz(1000), NULL);
1151d65f6f70SBen Gras #endif
1152d65f6f70SBen Gras
1153d65f6f70SBen Gras cv_destroy(&ebh->bg_erase.eth_wakeup);
1154d65f6f70SBen Gras }
1155d65f6f70SBen Gras
1156d65f6f70SBen Gras /*****************************************************************************/
1157d65f6f70SBen Gras /* End of Erase related operations */
1158d65f6f70SBen Gras /*****************************************************************************/
1159d65f6f70SBen Gras
1160d65f6f70SBen Gras /*****************************************************************************/
1161d65f6f70SBen Gras /* Scan related operations */
1162d65f6f70SBen Gras /*****************************************************************************/
1163d65f6f70SBen Gras int
scan_leb_used_cmp(struct chfs_scan_leb * sleb1,struct chfs_scan_leb * sleb2)1164d65f6f70SBen Gras scan_leb_used_cmp(struct chfs_scan_leb *sleb1, struct chfs_scan_leb *sleb2)
1165d65f6f70SBen Gras {
1166d65f6f70SBen Gras return (sleb1->lnr - sleb2->lnr);
1167d65f6f70SBen Gras }
1168d65f6f70SBen Gras
1169d65f6f70SBen Gras RB_PROTOTYPE(scan_leb_used_rbtree, chfs_scan_leb, u.rb, scan_leb_used_cmp);
1170d65f6f70SBen Gras RB_GENERATE(scan_leb_used_rbtree, chfs_scan_leb, u.rb, scan_leb_used_cmp);
1171d65f6f70SBen Gras
1172d65f6f70SBen Gras /**
1173d65f6f70SBen Gras * scan_add_to_queue - adds a physical eraseblock to one of the
1174d65f6f70SBen Gras * eraseblock queue
1175d65f6f70SBen Gras * @si: chfs scanning information
1176d65f6f70SBen Gras * @pebnr: physical eraseblock number
1177d65f6f70SBen Gras * @erase_cnt: erase counter of the physical eraseblock
1178d65f6f70SBen Gras * @list: the list to add to
1179d65f6f70SBen Gras *
1180d65f6f70SBen Gras * This function adds a physical eraseblock to one of the lists in the scanning
1181d65f6f70SBen Gras * information.
1182d65f6f70SBen Gras * Returns zero in case of success, negative error code in case of fail.
1183d65f6f70SBen Gras */
1184d65f6f70SBen Gras static int
scan_add_to_queue(struct chfs_scan_info * si,int pebnr,int erase_cnt,struct scan_leb_queue * queue)1185d65f6f70SBen Gras scan_add_to_queue(struct chfs_scan_info *si, int pebnr, int erase_cnt,
1186d65f6f70SBen Gras struct scan_leb_queue *queue)
1187d65f6f70SBen Gras {
1188d65f6f70SBen Gras struct chfs_scan_leb *sleb;
1189d65f6f70SBen Gras
1190d65f6f70SBen Gras sleb = kmem_alloc(sizeof(struct chfs_scan_leb), KM_SLEEP);
1191d65f6f70SBen Gras
1192d65f6f70SBen Gras sleb->pebnr = pebnr;
1193d65f6f70SBen Gras sleb->erase_cnt = erase_cnt;
1194d65f6f70SBen Gras TAILQ_INSERT_TAIL(queue, sleb, u.queue);
1195d65f6f70SBen Gras return 0;
1196d65f6f70SBen Gras }
1197d65f6f70SBen Gras
1198d65f6f70SBen Gras /*
1199d65f6f70SBen Gras * nor_scan_add_to_used - add a physical eraseblock to the
1200d65f6f70SBen Gras * used tree of scan info
1201d65f6f70SBen Gras * @ebh: chfs eraseblock handler
1202d65f6f70SBen Gras * @si: chfs scanning information
1203d65f6f70SBen Gras * @ebhdr: eraseblock header
1204d65f6f70SBen Gras * @pebnr: physical eraseblock number
1205d65f6f70SBen Gras * @leb_status: the status of the PEB's eraseblock header
1206d65f6f70SBen Gras *
1207d65f6f70SBen Gras * This function adds a PEB to the used tree of the scanning information.
1208d65f6f70SBen Gras * It handles the situations if there are more physical eraseblock referencing
1209d65f6f70SBen Gras * to the same logical eraseblock.
1210d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
1211d65f6f70SBen Gras */
1212d65f6f70SBen Gras int
nor_scan_add_to_used(struct chfs_ebh * ebh,struct chfs_scan_info * si,struct chfs_eb_hdr * ebhdr,int pebnr,int leb_status)1213d65f6f70SBen Gras nor_scan_add_to_used(struct chfs_ebh *ebh, struct chfs_scan_info *si,
1214d65f6f70SBen Gras struct chfs_eb_hdr *ebhdr, int pebnr, int leb_status)
1215d65f6f70SBen Gras {
1216d65f6f70SBen Gras int err, lnr, ec;
1217d65f6f70SBen Gras struct chfs_scan_leb *sleb, *old;
1218d65f6f70SBen Gras
1219d65f6f70SBen Gras lnr = CHFS_GET_LID(ebhdr->u.nor_hdr.lid);
1220d65f6f70SBen Gras ec = le32toh(ebhdr->ec_hdr.erase_cnt);
1221d65f6f70SBen Gras
1222d65f6f70SBen Gras sleb = kmem_alloc(sizeof(struct chfs_scan_leb), KM_SLEEP);
1223d65f6f70SBen Gras
1224d65f6f70SBen Gras sleb->erase_cnt = ec;
1225d65f6f70SBen Gras sleb->lnr = lnr;
1226d65f6f70SBen Gras sleb->pebnr = pebnr;
1227d65f6f70SBen Gras sleb->info = leb_status;
1228d65f6f70SBen Gras
1229d65f6f70SBen Gras old = RB_INSERT(scan_leb_used_rbtree, &si->used, sleb);
1230d65f6f70SBen Gras if (old) {
1231d65f6f70SBen Gras kmem_free(sleb, sizeof(struct chfs_scan_leb));
1232d65f6f70SBen Gras /* There is already an eraseblock in the used tree */
1233d65f6f70SBen Gras /* If the new one is bad */
1234d65f6f70SBen Gras if (EBHDR_LEB_DIRTY == leb_status &&
1235d65f6f70SBen Gras EBHDR_LEB_OK == old->info) {
1236d65f6f70SBen Gras return scan_add_to_queue(si, pebnr, ec, &si->erase);
1237d65f6f70SBen Gras } else {
1238d65f6f70SBen Gras err = scan_add_to_queue(si, old->pebnr,
1239d65f6f70SBen Gras old->erase_cnt, &si->erase);
1240d65f6f70SBen Gras if (err) {
1241d65f6f70SBen Gras return err;
1242d65f6f70SBen Gras }
1243d65f6f70SBen Gras
1244d65f6f70SBen Gras old->erase_cnt = ec;
1245d65f6f70SBen Gras old->lnr = lnr;
1246d65f6f70SBen Gras old->pebnr = pebnr;
1247d65f6f70SBen Gras old->info = leb_status;
1248d65f6f70SBen Gras return 0;
1249d65f6f70SBen Gras }
1250d65f6f70SBen Gras }
1251d65f6f70SBen Gras return 0;
1252d65f6f70SBen Gras }
1253d65f6f70SBen Gras
1254d65f6f70SBen Gras /**
1255d65f6f70SBen Gras * nor_process eb -read the headers from NOR flash, check them and add to
1256d65f6f70SBen Gras * the scanning information
1257d65f6f70SBen Gras * @ebh: chfs eraseblock handler
1258d65f6f70SBen Gras * @si: chfs scanning information
1259d65f6f70SBen Gras * @pebnr: physical eraseblock number
1260d65f6f70SBen Gras *
1261d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
1262d65f6f70SBen Gras */
1263d65f6f70SBen Gras int
nor_process_eb(struct chfs_ebh * ebh,struct chfs_scan_info * si,int pebnr,struct chfs_eb_hdr * ebhdr)1264d65f6f70SBen Gras nor_process_eb(struct chfs_ebh *ebh, struct chfs_scan_info *si,
1265d65f6f70SBen Gras int pebnr, struct chfs_eb_hdr *ebhdr)
1266d65f6f70SBen Gras {
1267d65f6f70SBen Gras int err, erase_cnt, leb_status;
1268d65f6f70SBen Gras
1269d65f6f70SBen Gras err = ebh->ops->read_eb_hdr(ebh, pebnr, ebhdr);
1270d65f6f70SBen Gras if (err)
1271d65f6f70SBen Gras return err;
1272d65f6f70SBen Gras
1273d65f6f70SBen Gras erase_cnt = le32toh(ebhdr->ec_hdr.erase_cnt);
1274d65f6f70SBen Gras dbg_ebh("erase_cnt: %d\n", erase_cnt);
1275d65f6f70SBen Gras leb_status = ebh->ops->check_eb_hdr(ebh, ebhdr);
1276d65f6f70SBen Gras if (EBHDR_LEB_BADMAGIC == leb_status ||
1277d65f6f70SBen Gras EBHDR_LEB_BADCRC == leb_status) {
1278d65f6f70SBen Gras err = scan_add_to_queue(si, pebnr, erase_cnt, &si->corrupted);
1279d65f6f70SBen Gras return err;
1280d65f6f70SBen Gras }
1281d65f6f70SBen Gras else if (EBHDR_LEB_FREE == leb_status) {
1282d65f6f70SBen Gras err = scan_add_to_queue(si, pebnr, erase_cnt, &si->free);
1283d65f6f70SBen Gras goto count_mean;
1284d65f6f70SBen Gras }
1285d65f6f70SBen Gras else if (EBHDR_LEB_NO_HDR == leb_status) {
1286d65f6f70SBen Gras err = scan_add_to_queue(si, pebnr, erase_cnt, &si->erased);
1287d65f6f70SBen Gras return err;
1288d65f6f70SBen Gras }
1289d65f6f70SBen Gras else if (EBHDR_LEB_INVALIDATED == leb_status) {
1290d65f6f70SBen Gras err = scan_add_to_queue(si, pebnr, erase_cnt, &si->erase);
1291d65f6f70SBen Gras return err;
1292d65f6f70SBen Gras }
1293d65f6f70SBen Gras
1294d65f6f70SBen Gras err = nor_scan_add_to_used(ebh, si, ebhdr, pebnr, leb_status);
1295d65f6f70SBen Gras if (err)
1296d65f6f70SBen Gras return err;
1297d65f6f70SBen Gras
1298d65f6f70SBen Gras
1299d65f6f70SBen Gras count_mean:
1300d65f6f70SBen Gras si->sum_of_ec += erase_cnt;
1301d65f6f70SBen Gras si->num_of_eb++;
1302d65f6f70SBen Gras
1303d65f6f70SBen Gras return err;
1304d65f6f70SBen Gras }
1305d65f6f70SBen Gras
1306d65f6f70SBen Gras /*
1307d65f6f70SBen Gras * nand_scan_add_to_used - add a physical eraseblock to the
1308d65f6f70SBen Gras * used tree of scan info
1309d65f6f70SBen Gras * @ebh: chfs eraseblock handler
1310d65f6f70SBen Gras * @si: chfs scanning information
1311d65f6f70SBen Gras * @ebhdr: eraseblock header
1312d65f6f70SBen Gras * @pebnr: physical eraseblock number
1313d65f6f70SBen Gras * @leb_status: the status of the PEB's eraseblock header
1314d65f6f70SBen Gras *
1315d65f6f70SBen Gras * This function adds a PEB to the used tree of the scanning information.
1316d65f6f70SBen Gras * It handles the situations if there are more physical eraseblock referencing
1317d65f6f70SBen Gras * to the same logical eraseblock.
1318d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
1319d65f6f70SBen Gras */
1320d65f6f70SBen Gras int
nand_scan_add_to_used(struct chfs_ebh * ebh,struct chfs_scan_info * si,struct chfs_eb_hdr * ebhdr,int pebnr)1321d65f6f70SBen Gras nand_scan_add_to_used(struct chfs_ebh *ebh, struct chfs_scan_info *si,
1322d65f6f70SBen Gras struct chfs_eb_hdr *ebhdr, int pebnr)
1323d65f6f70SBen Gras {
1324d65f6f70SBen Gras int err, lnr, ec;
1325d65f6f70SBen Gras struct chfs_scan_leb *sleb, *old;
1326d65f6f70SBen Gras uint64_t serial = le64toh(ebhdr->u.nand_hdr.serial);
1327d65f6f70SBen Gras
1328d65f6f70SBen Gras lnr = CHFS_GET_LID(ebhdr->u.nor_hdr.lid);
1329d65f6f70SBen Gras ec = le32toh(ebhdr->ec_hdr.erase_cnt);
1330d65f6f70SBen Gras
1331d65f6f70SBen Gras sleb = kmem_alloc(sizeof(struct chfs_scan_leb), KM_SLEEP);
1332d65f6f70SBen Gras
1333d65f6f70SBen Gras sleb->erase_cnt = ec;
1334d65f6f70SBen Gras sleb->lnr = lnr;
1335d65f6f70SBen Gras sleb->pebnr = pebnr;
1336d65f6f70SBen Gras sleb->info = serial;
1337d65f6f70SBen Gras
1338d65f6f70SBen Gras old = RB_INSERT(scan_leb_used_rbtree, &si->used, sleb);
1339d65f6f70SBen Gras if (old) {
1340d65f6f70SBen Gras kmem_free(sleb, sizeof(struct chfs_scan_leb));
1341d65f6f70SBen Gras /* There is already an eraseblock in the used tree */
1342d65f6f70SBen Gras /* If the new one is bad */
1343d65f6f70SBen Gras if (serial < old->info)
1344d65f6f70SBen Gras return scan_add_to_queue(si, pebnr, ec, &si->erase);
1345d65f6f70SBen Gras else {
1346d65f6f70SBen Gras err = scan_add_to_queue(si,
1347d65f6f70SBen Gras old->pebnr, old->erase_cnt, &si->erase);
1348d65f6f70SBen Gras if (err)
1349d65f6f70SBen Gras return err;
1350d65f6f70SBen Gras
1351d65f6f70SBen Gras old->erase_cnt = ec;
1352d65f6f70SBen Gras old->lnr = lnr;
1353d65f6f70SBen Gras old->pebnr = pebnr;
1354d65f6f70SBen Gras old->info = serial;
1355d65f6f70SBen Gras return 0;
1356d65f6f70SBen Gras }
1357d65f6f70SBen Gras }
1358d65f6f70SBen Gras return 0;
1359d65f6f70SBen Gras }
1360d65f6f70SBen Gras
1361d65f6f70SBen Gras /**
1362d65f6f70SBen Gras * nand_process eb -read the headers from NAND flash, check them and add to the
1363d65f6f70SBen Gras * scanning information
1364d65f6f70SBen Gras * @ebh: chfs eraseblock handler
1365d65f6f70SBen Gras * @si: chfs scanning information
1366d65f6f70SBen Gras * @pebnr: physical eraseblock number
1367d65f6f70SBen Gras *
1368d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
1369d65f6f70SBen Gras */
1370d65f6f70SBen Gras int
nand_process_eb(struct chfs_ebh * ebh,struct chfs_scan_info * si,int pebnr,struct chfs_eb_hdr * ebhdr)1371d65f6f70SBen Gras nand_process_eb(struct chfs_ebh *ebh, struct chfs_scan_info *si,
1372d65f6f70SBen Gras int pebnr, struct chfs_eb_hdr *ebhdr)
1373d65f6f70SBen Gras {
1374d65f6f70SBen Gras int err, erase_cnt, leb_status;
1375d65f6f70SBen Gras uint64_t max_serial;
1376d65f6f70SBen Gras /* isbad() is defined on some ancient platforms, heh */
1377d65f6f70SBen Gras bool is_bad;
1378d65f6f70SBen Gras
1379d65f6f70SBen Gras /* Check block is bad */
1380d65f6f70SBen Gras err = flash_block_isbad(ebh->flash_dev,
1381d65f6f70SBen Gras pebnr * ebh->flash_if->erasesize, &is_bad);
1382d65f6f70SBen Gras if (err) {
1383d65f6f70SBen Gras chfs_err("checking block is bad failed\n");
1384d65f6f70SBen Gras return err;
1385d65f6f70SBen Gras }
1386d65f6f70SBen Gras if (is_bad) {
1387d65f6f70SBen Gras si->bad_peb_cnt++;
1388d65f6f70SBen Gras return 0;
1389d65f6f70SBen Gras }
1390d65f6f70SBen Gras
1391d65f6f70SBen Gras err = ebh->ops->read_eb_hdr(ebh, pebnr, ebhdr);
1392d65f6f70SBen Gras if (err)
1393d65f6f70SBen Gras return err;
1394d65f6f70SBen Gras
1395d65f6f70SBen Gras erase_cnt = le32toh(ebhdr->ec_hdr.erase_cnt);
1396d65f6f70SBen Gras leb_status = ebh->ops->check_eb_hdr(ebh, ebhdr);
1397d65f6f70SBen Gras if (EBHDR_LEB_BADMAGIC == leb_status ||
1398d65f6f70SBen Gras EBHDR_LEB_BADCRC == leb_status) {
1399d65f6f70SBen Gras err = scan_add_to_queue(si, pebnr, erase_cnt, &si->corrupted);
1400d65f6f70SBen Gras return err;
1401d65f6f70SBen Gras }
1402d65f6f70SBen Gras else if (EBHDR_LEB_FREE == leb_status) {
1403d65f6f70SBen Gras err = scan_add_to_queue(si, pebnr, erase_cnt, &si->free);
1404d65f6f70SBen Gras goto count_mean;
1405d65f6f70SBen Gras }
1406d65f6f70SBen Gras else if (EBHDR_LEB_NO_HDR == leb_status) {
1407d65f6f70SBen Gras err = scan_add_to_queue(si, pebnr, erase_cnt, &si->erased);
1408d65f6f70SBen Gras return err;
1409d65f6f70SBen Gras }
1410d65f6f70SBen Gras
1411d65f6f70SBen Gras err = nand_scan_add_to_used(ebh, si, ebhdr, pebnr);
1412d65f6f70SBen Gras if (err)
1413d65f6f70SBen Gras return err;
1414d65f6f70SBen Gras
1415d65f6f70SBen Gras max_serial = le64toh(ebhdr->u.nand_hdr.serial);
1416d65f6f70SBen Gras if (max_serial > *ebh->max_serial) {
1417d65f6f70SBen Gras *ebh->max_serial = max_serial;
1418d65f6f70SBen Gras }
1419d65f6f70SBen Gras
1420d65f6f70SBen Gras count_mean:
1421d65f6f70SBen Gras si->sum_of_ec += erase_cnt;
1422d65f6f70SBen Gras si->num_of_eb++;
1423d65f6f70SBen Gras
1424d65f6f70SBen Gras return err;
1425d65f6f70SBen Gras }
1426d65f6f70SBen Gras
1427d65f6f70SBen Gras /**
1428d65f6f70SBen Gras * chfs_scan - scans the media and returns informations about it
1429d65f6f70SBen Gras * @ebh: chfs eraseblock handler
1430d65f6f70SBen Gras *
1431d65f6f70SBen Gras * This function scans through the media and returns information about it or if
1432d65f6f70SBen Gras * it fails NULL will be returned.
1433d65f6f70SBen Gras */
1434d65f6f70SBen Gras struct chfs_scan_info *
chfs_scan(struct chfs_ebh * ebh)1435d65f6f70SBen Gras chfs_scan(struct chfs_ebh *ebh)
1436d65f6f70SBen Gras {
1437d65f6f70SBen Gras struct chfs_scan_info *si;
1438d65f6f70SBen Gras struct chfs_eb_hdr *ebhdr;
1439d65f6f70SBen Gras int pebnr, err;
1440d65f6f70SBen Gras
1441d65f6f70SBen Gras si = kmem_alloc(sizeof(*si), KM_SLEEP);
1442d65f6f70SBen Gras
1443d65f6f70SBen Gras TAILQ_INIT(&si->corrupted);
1444d65f6f70SBen Gras TAILQ_INIT(&si->free);
1445d65f6f70SBen Gras TAILQ_INIT(&si->erase);
1446d65f6f70SBen Gras TAILQ_INIT(&si->erased);
1447d65f6f70SBen Gras RB_INIT(&si->used);
1448d65f6f70SBen Gras si->bad_peb_cnt = 0;
1449d65f6f70SBen Gras si->num_of_eb = 0;
1450d65f6f70SBen Gras si->sum_of_ec = 0;
1451d65f6f70SBen Gras
1452d65f6f70SBen Gras ebhdr = kmem_alloc(sizeof(*ebhdr), KM_SLEEP);
1453d65f6f70SBen Gras
1454d65f6f70SBen Gras for (pebnr = 0; pebnr < ebh->peb_nr; pebnr++) {
1455d65f6f70SBen Gras dbg_ebh("processing PEB %d\n", pebnr);
1456d65f6f70SBen Gras err = ebh->ops->process_eb(ebh, si, pebnr, ebhdr);
1457d65f6f70SBen Gras if (err < 0)
1458d65f6f70SBen Gras goto out_ebhdr;
1459d65f6f70SBen Gras }
1460d65f6f70SBen Gras kmem_free(ebhdr, sizeof(*ebhdr));
1461d65f6f70SBen Gras dbg_ebh("[CHFS_SCAN] scanning information collected\n");
1462d65f6f70SBen Gras return si;
1463d65f6f70SBen Gras
1464d65f6f70SBen Gras out_ebhdr:
1465d65f6f70SBen Gras kmem_free(ebhdr, sizeof(*ebhdr));
1466d65f6f70SBen Gras kmem_free(si, sizeof(*si));
1467d65f6f70SBen Gras return NULL;
1468d65f6f70SBen Gras }
1469d65f6f70SBen Gras
1470d65f6f70SBen Gras /**
1471d65f6f70SBen Gras * scan_info_destroy - frees all lists and trees in the scanning information
1472d65f6f70SBen Gras * @si: the scanning information
1473d65f6f70SBen Gras */
1474d65f6f70SBen Gras void
scan_info_destroy(struct chfs_scan_info * si)1475d65f6f70SBen Gras scan_info_destroy(struct chfs_scan_info *si)
1476d65f6f70SBen Gras {
1477d65f6f70SBen Gras EBH_QUEUE_DESTROY(&si->corrupted,
1478d65f6f70SBen Gras struct chfs_scan_leb, u.queue);
1479d65f6f70SBen Gras
1480d65f6f70SBen Gras EBH_QUEUE_DESTROY(&si->erase,
1481d65f6f70SBen Gras struct chfs_scan_leb, u.queue);
1482d65f6f70SBen Gras
1483d65f6f70SBen Gras EBH_QUEUE_DESTROY(&si->erased,
1484d65f6f70SBen Gras struct chfs_scan_leb, u.queue);
1485d65f6f70SBen Gras
1486d65f6f70SBen Gras EBH_QUEUE_DESTROY(&si->free,
1487d65f6f70SBen Gras struct chfs_scan_leb, u.queue);
1488d65f6f70SBen Gras
1489d65f6f70SBen Gras EBH_TREE_DESTROY(scan_leb_used_rbtree,
1490d65f6f70SBen Gras &si->used, struct chfs_scan_leb);
1491d65f6f70SBen Gras
1492d65f6f70SBen Gras kmem_free(si, sizeof(*si));
1493d65f6f70SBen Gras dbg_ebh("[SCAN_INFO_DESTROY] scanning information destroyed\n");
1494d65f6f70SBen Gras }
1495d65f6f70SBen Gras
1496d65f6f70SBen Gras /**
1497d65f6f70SBen Gras * scan_media - scan media
1498d65f6f70SBen Gras *
1499d65f6f70SBen Gras * @ebh - chfs eraseblock handler
1500d65f6f70SBen Gras *
1501d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
1502d65f6f70SBen Gras */
1503d65f6f70SBen Gras
1504d65f6f70SBen Gras int
scan_media(struct chfs_ebh * ebh)1505d65f6f70SBen Gras scan_media(struct chfs_ebh *ebh)
1506d65f6f70SBen Gras {
1507d65f6f70SBen Gras int err, i, avg_ec;
1508d65f6f70SBen Gras struct chfs_scan_info *si;
1509d65f6f70SBen Gras struct chfs_scan_leb *sleb;
1510d65f6f70SBen Gras
1511d65f6f70SBen Gras si = chfs_scan(ebh);
1512d65f6f70SBen Gras /*
1513d65f6f70SBen Gras * Process the scan info, manage the eraseblock lists
1514d65f6f70SBen Gras */
1515d65f6f70SBen Gras mutex_init(&ebh->ltree_lock, MUTEX_DEFAULT, IPL_NONE);
1516d65f6f70SBen Gras mutex_init(&ebh->erase_lock, MUTEX_DEFAULT, IPL_NONE);
1517d65f6f70SBen Gras RB_INIT(&ebh->ltree);
1518d65f6f70SBen Gras RB_INIT(&ebh->free);
1519d65f6f70SBen Gras RB_INIT(&ebh->in_use);
1520d65f6f70SBen Gras TAILQ_INIT(&ebh->to_erase);
1521d65f6f70SBen Gras TAILQ_INIT(&ebh->fully_erased);
1522d65f6f70SBen Gras mutex_init(&ebh->alc_mutex, MUTEX_DEFAULT, IPL_NONE);
1523d65f6f70SBen Gras
1524d65f6f70SBen Gras ebh->peb_nr -= si->bad_peb_cnt;
1525d65f6f70SBen Gras
1526d65f6f70SBen Gras /*
1527d65f6f70SBen Gras * Create background thread for erasing
1528d65f6f70SBen Gras */
1529d65f6f70SBen Gras erase_thread_start(ebh);
1530d65f6f70SBen Gras
1531d65f6f70SBen Gras ebh->lmap = kmem_alloc(ebh->peb_nr * sizeof(int), KM_SLEEP);
1532d65f6f70SBen Gras
1533d65f6f70SBen Gras for (i = 0; i < ebh->peb_nr; i++) {
1534d65f6f70SBen Gras ebh->lmap[i] = EBH_LEB_UNMAPPED;
1535d65f6f70SBen Gras }
1536d65f6f70SBen Gras
1537d65f6f70SBen Gras if (si->num_of_eb == 0) {
1538d65f6f70SBen Gras /* The flash contains no data. */
1539d65f6f70SBen Gras avg_ec = 0;
1540d65f6f70SBen Gras }
1541d65f6f70SBen Gras else {
1542d65f6f70SBen Gras avg_ec = (int) (si->sum_of_ec / si->num_of_eb);
1543d65f6f70SBen Gras }
1544d65f6f70SBen Gras dbg_ebh("num_of_eb: %d\n", si->num_of_eb);
1545d65f6f70SBen Gras
1546d65f6f70SBen Gras mutex_enter(&ebh->erase_lock);
1547d65f6f70SBen Gras
1548d65f6f70SBen Gras RB_FOREACH(sleb, scan_leb_used_rbtree, &si->used) {
1549d65f6f70SBen Gras ebh->lmap[sleb->lnr] = sleb->pebnr;
1550d65f6f70SBen Gras err = add_peb_to_in_use(ebh, sleb->pebnr, sleb->erase_cnt);
1551d65f6f70SBen Gras if (err)
1552d65f6f70SBen Gras goto out_free;
1553d65f6f70SBen Gras }
1554d65f6f70SBen Gras
1555d65f6f70SBen Gras TAILQ_FOREACH(sleb, &si->erased, u.queue) {
1556d65f6f70SBen Gras err = add_peb_to_erase_queue(ebh, sleb->pebnr, avg_ec,
1557d65f6f70SBen Gras &ebh->fully_erased);
1558d65f6f70SBen Gras if (err)
1559d65f6f70SBen Gras goto out_free;
1560d65f6f70SBen Gras }
1561d65f6f70SBen Gras
1562d65f6f70SBen Gras TAILQ_FOREACH(sleb, &si->erase, u.queue) {
1563d65f6f70SBen Gras err = add_peb_to_erase_queue(ebh, sleb->pebnr, avg_ec,
1564d65f6f70SBen Gras &ebh->to_erase);
1565d65f6f70SBen Gras if (err)
1566d65f6f70SBen Gras goto out_free;
1567d65f6f70SBen Gras }
1568d65f6f70SBen Gras
1569d65f6f70SBen Gras TAILQ_FOREACH(sleb, &si->free, u.queue) {
1570d65f6f70SBen Gras err = add_peb_to_free(ebh, sleb->pebnr, sleb->erase_cnt);
1571d65f6f70SBen Gras if (err)
1572d65f6f70SBen Gras goto out_free;
1573d65f6f70SBen Gras }
1574d65f6f70SBen Gras
1575d65f6f70SBen Gras TAILQ_FOREACH(sleb, &si->corrupted, u.queue) {
1576d65f6f70SBen Gras err = add_peb_to_erase_queue(ebh, sleb->pebnr, avg_ec,
1577d65f6f70SBen Gras &ebh->to_erase);
1578d65f6f70SBen Gras if (err)
1579d65f6f70SBen Gras goto out_free;
1580d65f6f70SBen Gras }
1581d65f6f70SBen Gras mutex_exit(&ebh->erase_lock);
1582d65f6f70SBen Gras scan_info_destroy(si);
1583d65f6f70SBen Gras return 0;
1584d65f6f70SBen Gras
1585d65f6f70SBen Gras out_free:
1586d65f6f70SBen Gras mutex_exit(&ebh->erase_lock);
1587d65f6f70SBen Gras kmem_free(ebh->lmap, ebh->peb_nr * sizeof(int));
1588d65f6f70SBen Gras scan_info_destroy(si);
1589d65f6f70SBen Gras dbg_ebh("[SCAN_MEDIA] returning with error: %d\n", err);
1590d65f6f70SBen Gras return err;
1591d65f6f70SBen Gras }
1592d65f6f70SBen Gras
1593d65f6f70SBen Gras /*****************************************************************************/
1594d65f6f70SBen Gras /* End of Scan related operations */
1595d65f6f70SBen Gras /*****************************************************************************/
1596d65f6f70SBen Gras
1597d65f6f70SBen Gras /**
1598d65f6f70SBen Gras * ebh_open - opens mtd device and init ereaseblock header
1599d65f6f70SBen Gras * @ebh: eraseblock handler
1600d65f6f70SBen Gras * @flash_nr: flash device number to use
1601d65f6f70SBen Gras *
1602d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
1603d65f6f70SBen Gras */
1604d65f6f70SBen Gras int
ebh_open(struct chfs_ebh * ebh,dev_t dev)1605d65f6f70SBen Gras ebh_open(struct chfs_ebh *ebh, dev_t dev)
1606d65f6f70SBen Gras {
1607d65f6f70SBen Gras int err;
1608d65f6f70SBen Gras
1609d65f6f70SBen Gras ebh->flash_dev = flash_get_device(dev);
1610d65f6f70SBen Gras if (!ebh->flash_dev) {
1611d65f6f70SBen Gras aprint_error("ebh_open: cant get flash device\n");
1612d65f6f70SBen Gras return ENODEV;
1613d65f6f70SBen Gras }
1614d65f6f70SBen Gras
1615d65f6f70SBen Gras ebh->flash_if = flash_get_interface(dev);
1616d65f6f70SBen Gras if (!ebh->flash_if) {
1617d65f6f70SBen Gras aprint_error("ebh_open: cant get flash interface\n");
1618d65f6f70SBen Gras return ENODEV;
1619d65f6f70SBen Gras }
1620d65f6f70SBen Gras
1621d65f6f70SBen Gras ebh->flash_size = flash_get_size(dev);
1622d65f6f70SBen Gras ebh->peb_nr = ebh->flash_size / ebh->flash_if->erasesize;
1623d65f6f70SBen Gras // ebh->peb_nr = ebh->flash_if->size / ebh->flash_if->erasesize;
1624d65f6f70SBen Gras /* Set up flash operations based on flash type */
1625d65f6f70SBen Gras ebh->ops = kmem_alloc(sizeof(struct chfs_ebh_ops), KM_SLEEP);
1626d65f6f70SBen Gras
1627d65f6f70SBen Gras switch (ebh->flash_if->type) {
1628d65f6f70SBen Gras case FLASH_TYPE_NOR:
1629d65f6f70SBen Gras ebh->eb_size = ebh->flash_if->erasesize -
1630d65f6f70SBen Gras CHFS_EB_EC_HDR_SIZE - CHFS_EB_HDR_NOR_SIZE;
1631d65f6f70SBen Gras
1632d65f6f70SBen Gras ebh->ops->read_eb_hdr = nor_read_eb_hdr;
1633d65f6f70SBen Gras ebh->ops->write_eb_hdr = nor_write_eb_hdr;
1634d65f6f70SBen Gras ebh->ops->check_eb_hdr = nor_check_eb_hdr;
1635d65f6f70SBen Gras ebh->ops->mark_eb_hdr_dirty_flash =
1636d65f6f70SBen Gras nor_mark_eb_hdr_dirty_flash;
1637d65f6f70SBen Gras ebh->ops->invalidate_eb_hdr = nor_invalidate_eb_hdr;
1638d65f6f70SBen Gras ebh->ops->mark_eb_hdr_free = mark_eb_hdr_free;
1639d65f6f70SBen Gras
1640d65f6f70SBen Gras ebh->ops->process_eb = nor_process_eb;
1641d65f6f70SBen Gras
1642d65f6f70SBen Gras ebh->ops->create_eb_hdr = nor_create_eb_hdr;
1643d65f6f70SBen Gras ebh->ops->calc_data_offs = nor_calc_data_offs;
1644d65f6f70SBen Gras
1645d65f6f70SBen Gras ebh->max_serial = NULL;
1646d65f6f70SBen Gras break;
1647d65f6f70SBen Gras case FLASH_TYPE_NAND:
1648d65f6f70SBen Gras ebh->eb_size = ebh->flash_if->erasesize -
1649d65f6f70SBen Gras 2 * ebh->flash_if->page_size;
1650d65f6f70SBen Gras
1651d65f6f70SBen Gras ebh->ops->read_eb_hdr = nand_read_eb_hdr;
1652d65f6f70SBen Gras ebh->ops->write_eb_hdr = nand_write_eb_hdr;
1653d65f6f70SBen Gras ebh->ops->check_eb_hdr = nand_check_eb_hdr;
1654d65f6f70SBen Gras ebh->ops->mark_eb_hdr_free = mark_eb_hdr_free;
1655d65f6f70SBen Gras ebh->ops->mark_eb_hdr_dirty_flash = NULL;
1656d65f6f70SBen Gras ebh->ops->invalidate_eb_hdr = NULL;
1657d65f6f70SBen Gras
1658d65f6f70SBen Gras ebh->ops->process_eb = nand_process_eb;
1659d65f6f70SBen Gras
1660d65f6f70SBen Gras ebh->ops->create_eb_hdr = nand_create_eb_hdr;
1661d65f6f70SBen Gras ebh->ops->calc_data_offs = nand_calc_data_offs;
1662d65f6f70SBen Gras
1663d65f6f70SBen Gras ebh->max_serial = kmem_alloc(sizeof(uint64_t), KM_SLEEP);
1664d65f6f70SBen Gras
1665d65f6f70SBen Gras *ebh->max_serial = 0;
1666d65f6f70SBen Gras break;
1667d65f6f70SBen Gras default:
1668d65f6f70SBen Gras return 1;
1669d65f6f70SBen Gras }
1670d65f6f70SBen Gras printf("opening ebh: eb_size: %zu\n", ebh->eb_size);
1671d65f6f70SBen Gras err = scan_media(ebh);
1672d65f6f70SBen Gras if (err) {
1673d65f6f70SBen Gras dbg_ebh("Scan failed.");
1674d65f6f70SBen Gras kmem_free(ebh->ops, sizeof(struct chfs_ebh_ops));
1675d65f6f70SBen Gras kmem_free(ebh, sizeof(struct chfs_ebh));
1676d65f6f70SBen Gras return err;
1677d65f6f70SBen Gras }
1678d65f6f70SBen Gras return 0;
1679d65f6f70SBen Gras }
1680d65f6f70SBen Gras
1681d65f6f70SBen Gras /**
1682d65f6f70SBen Gras * ebh_close - close ebh
1683d65f6f70SBen Gras * @ebh: eraseblock handler
1684d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
1685d65f6f70SBen Gras */
1686d65f6f70SBen Gras int
ebh_close(struct chfs_ebh * ebh)1687d65f6f70SBen Gras ebh_close(struct chfs_ebh *ebh)
1688d65f6f70SBen Gras {
1689d65f6f70SBen Gras erase_thread_stop(ebh);
1690d65f6f70SBen Gras
1691d65f6f70SBen Gras EBH_TREE_DESTROY(peb_free_rbtree, &ebh->free, struct chfs_peb);
1692d65f6f70SBen Gras EBH_TREE_DESTROY(peb_in_use_rbtree, &ebh->in_use, struct chfs_peb);
1693d65f6f70SBen Gras
1694d65f6f70SBen Gras EBH_QUEUE_DESTROY(&ebh->fully_erased, struct chfs_peb, u.queue);
1695d65f6f70SBen Gras EBH_QUEUE_DESTROY(&ebh->to_erase, struct chfs_peb, u.queue);
1696d65f6f70SBen Gras
1697d65f6f70SBen Gras /* XXX HACK, see ebh.h */
1698d65f6f70SBen Gras EBH_TREE_DESTROY_MUTEX(ltree_rbtree, &ebh->ltree,
1699d65f6f70SBen Gras struct chfs_ltree_entry);
1700d65f6f70SBen Gras
1701d65f6f70SBen Gras KASSERT(!mutex_owned(&ebh->ltree_lock));
1702d65f6f70SBen Gras KASSERT(!mutex_owned(&ebh->alc_mutex));
1703d65f6f70SBen Gras KASSERT(!mutex_owned(&ebh->erase_lock));
1704d65f6f70SBen Gras
1705d65f6f70SBen Gras mutex_destroy(&ebh->ltree_lock);
1706d65f6f70SBen Gras mutex_destroy(&ebh->alc_mutex);
1707d65f6f70SBen Gras mutex_destroy(&ebh->erase_lock);
1708d65f6f70SBen Gras
1709d65f6f70SBen Gras kmem_free(ebh->ops, sizeof(struct chfs_ebh_ops));
1710d65f6f70SBen Gras kmem_free(ebh, sizeof(struct chfs_ebh));
1711d65f6f70SBen Gras
1712d65f6f70SBen Gras return 0;
1713d65f6f70SBen Gras }
1714d65f6f70SBen Gras
1715d65f6f70SBen Gras /**
1716d65f6f70SBen Gras * ebh_read_leb - read data from leb
1717d65f6f70SBen Gras * @ebh: eraseblock handler
1718d65f6f70SBen Gras * @lnr: logical eraseblock number
1719d65f6f70SBen Gras * @buf: buffer to read to
1720d65f6f70SBen Gras * @offset: offset from where to read
1721d65f6f70SBen Gras * @len: bytes number to read
1722d65f6f70SBen Gras *
1723d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
1724d65f6f70SBen Gras */
1725d65f6f70SBen Gras int
ebh_read_leb(struct chfs_ebh * ebh,int lnr,char * buf,uint32_t offset,size_t len,size_t * retlen)1726d65f6f70SBen Gras ebh_read_leb(struct chfs_ebh *ebh, int lnr, char *buf, uint32_t offset,
1727d65f6f70SBen Gras size_t len, size_t *retlen)
1728d65f6f70SBen Gras {
1729d65f6f70SBen Gras int err, pebnr;
1730d65f6f70SBen Gras off_t data_offset;
1731d65f6f70SBen Gras
1732d65f6f70SBen Gras KASSERT(offset + len <= ebh->eb_size);
1733d65f6f70SBen Gras
1734d65f6f70SBen Gras err = leb_read_lock(ebh, lnr);
1735d65f6f70SBen Gras if (err)
1736d65f6f70SBen Gras return err;
173784d9c625SLionel Sambuc
1738d65f6f70SBen Gras pebnr = ebh->lmap[lnr];
1739d65f6f70SBen Gras /* If PEB is not mapped the buffer is filled with 0xFF */
1740d65f6f70SBen Gras if (EBH_LEB_UNMAPPED == pebnr) {
1741d65f6f70SBen Gras leb_read_unlock(ebh, lnr);
1742d65f6f70SBen Gras memset(buf, 0xFF, len);
1743d65f6f70SBen Gras return 0;
1744d65f6f70SBen Gras }
1745d65f6f70SBen Gras
1746d65f6f70SBen Gras /* Read data */
1747d65f6f70SBen Gras data_offset = ebh->ops->calc_data_offs(ebh, pebnr, offset);
1748d65f6f70SBen Gras err = flash_read(ebh->flash_dev, data_offset, len, retlen,
1749d65f6f70SBen Gras (unsigned char *) buf);
1750d65f6f70SBen Gras if (err)
1751d65f6f70SBen Gras goto out_free;
1752d65f6f70SBen Gras
1753d65f6f70SBen Gras KASSERT(len == *retlen);
1754d65f6f70SBen Gras
1755d65f6f70SBen Gras out_free:
1756d65f6f70SBen Gras leb_read_unlock(ebh, lnr);
1757d65f6f70SBen Gras return err;
1758d65f6f70SBen Gras }
1759d65f6f70SBen Gras
1760d65f6f70SBen Gras /**
1761d65f6f70SBen Gras * get_peb: get a free physical eraseblock
1762d65f6f70SBen Gras * @ebh - chfs eraseblock handler
1763d65f6f70SBen Gras *
1764d65f6f70SBen Gras * This function gets a free eraseblock from the ebh->free RB-tree.
1765d65f6f70SBen Gras * The fist entry will be returned and deleted from the tree.
1766d65f6f70SBen Gras * The entries sorted by the erase counters, so the PEB with the smallest
1767d65f6f70SBen Gras * erase counter will be added back.
1768d65f6f70SBen Gras * If something goes bad a negative value will be returned.
1769d65f6f70SBen Gras */
1770d65f6f70SBen Gras int
get_peb(struct chfs_ebh * ebh)1771d65f6f70SBen Gras get_peb(struct chfs_ebh *ebh)
1772d65f6f70SBen Gras {
1773d65f6f70SBen Gras int err, pebnr;
1774d65f6f70SBen Gras struct chfs_peb *peb;
1775d65f6f70SBen Gras
1776d65f6f70SBen Gras retry:
1777d65f6f70SBen Gras mutex_enter(&ebh->erase_lock);
1778d65f6f70SBen Gras //dbg_ebh("LOCK: ebh->erase_lock spin locked in get_peb()\n");
1779d65f6f70SBen Gras if (RB_EMPTY(&ebh->free)) {
1780d65f6f70SBen Gras /*There is no more free PEBs in the tree*/
1781d65f6f70SBen Gras if (TAILQ_EMPTY(&ebh->to_erase) &&
1782d65f6f70SBen Gras TAILQ_EMPTY(&ebh->fully_erased)) {
1783d65f6f70SBen Gras mutex_exit(&ebh->erase_lock);
1784d65f6f70SBen Gras //dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in get_peb()\n");
1785d65f6f70SBen Gras return ENOSPC;
1786d65f6f70SBen Gras }
1787d65f6f70SBen Gras err = free_peb(ebh);
1788d65f6f70SBen Gras
1789d65f6f70SBen Gras mutex_exit(&ebh->erase_lock);
1790d65f6f70SBen Gras //dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in get_peb()\n");
1791d65f6f70SBen Gras
1792d65f6f70SBen Gras if (err)
1793d65f6f70SBen Gras return err;
1794d65f6f70SBen Gras goto retry;
1795d65f6f70SBen Gras }
1796d65f6f70SBen Gras peb = RB_MIN(peb_free_rbtree, &ebh->free);
1797d65f6f70SBen Gras pebnr = peb->pebnr;
1798d65f6f70SBen Gras RB_REMOVE(peb_free_rbtree, &ebh->free, peb);
1799d65f6f70SBen Gras err = add_peb_to_in_use(ebh, peb->pebnr, peb->erase_cnt);
1800d65f6f70SBen Gras if (err)
1801d65f6f70SBen Gras pebnr = err;
1802d65f6f70SBen Gras
1803d65f6f70SBen Gras kmem_free(peb, sizeof(struct chfs_peb));
1804d65f6f70SBen Gras
1805d65f6f70SBen Gras mutex_exit(&ebh->erase_lock);
1806d65f6f70SBen Gras //dbg_ebh("UNLOCK: ebh->erase_lock spin unlocked in get_peb()\n");
1807d65f6f70SBen Gras
1808d65f6f70SBen Gras return pebnr;
1809d65f6f70SBen Gras }
1810d65f6f70SBen Gras
1811d65f6f70SBen Gras /**
1812d65f6f70SBen Gras * ebh_write_leb - write data to leb
1813d65f6f70SBen Gras * @ebh: eraseblock handler
1814d65f6f70SBen Gras * @lnr: logical eraseblock number
1815d65f6f70SBen Gras * @buf: data to write
1816d65f6f70SBen Gras * @offset: offset where to write
1817d65f6f70SBen Gras * @len: bytes number to write
1818d65f6f70SBen Gras *
1819d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
1820d65f6f70SBen Gras */
1821d65f6f70SBen Gras int
ebh_write_leb(struct chfs_ebh * ebh,int lnr,char * buf,uint32_t offset,size_t len,size_t * retlen)1822d65f6f70SBen Gras ebh_write_leb(struct chfs_ebh *ebh, int lnr, char *buf, uint32_t offset,
1823d65f6f70SBen Gras size_t len, size_t *retlen)
1824d65f6f70SBen Gras {
1825d65f6f70SBen Gras int err, pebnr, retries = 0;
1826d65f6f70SBen Gras off_t data_offset;
1827d65f6f70SBen Gras struct chfs_eb_hdr *ebhdr;
1828d65f6f70SBen Gras
1829d65f6f70SBen Gras dbg("offset: %d | len: %zu | (offset+len): %zu "
1830d65f6f70SBen Gras " | ebsize: %zu\n", offset, len, (offset+len), ebh->eb_size);
1831d65f6f70SBen Gras
1832d65f6f70SBen Gras KASSERT(offset + len <= ebh->eb_size);
1833d65f6f70SBen Gras
1834d65f6f70SBen Gras err = leb_write_lock(ebh, lnr);
1835d65f6f70SBen Gras if (err)
1836d65f6f70SBen Gras return err;
1837d65f6f70SBen Gras
1838d65f6f70SBen Gras pebnr = ebh->lmap[lnr];
1839d65f6f70SBen Gras /* If the LEB is mapped write out data */
1840d65f6f70SBen Gras if (pebnr != EBH_LEB_UNMAPPED) {
1841d65f6f70SBen Gras data_offset = ebh->ops->calc_data_offs(ebh, pebnr, offset);
1842d65f6f70SBen Gras err = flash_write(ebh->flash_dev, data_offset, len, retlen,
1843d65f6f70SBen Gras (unsigned char *) buf);
1844d65f6f70SBen Gras
1845d65f6f70SBen Gras if (err) {
1846d65f6f70SBen Gras chfs_err("error %d while writing %zu bytes to PEB "
1847d65f6f70SBen Gras "%d:%ju, written %zu bytes\n",
1848d65f6f70SBen Gras err, len, pebnr, (uintmax_t )offset, *retlen);
1849d65f6f70SBen Gras } else {
1850d65f6f70SBen Gras KASSERT(len == *retlen);
1851d65f6f70SBen Gras }
1852d65f6f70SBen Gras
1853d65f6f70SBen Gras leb_write_unlock(ebh, lnr);
1854d65f6f70SBen Gras return err;
1855d65f6f70SBen Gras }
1856d65f6f70SBen Gras
1857d65f6f70SBen Gras /*
1858d65f6f70SBen Gras * If the LEB is unmapped, get a free PEB and write the
1859d65f6f70SBen Gras * eraseblock header first
1860d65f6f70SBen Gras */
1861d65f6f70SBen Gras ebhdr = kmem_alloc(sizeof(struct chfs_eb_hdr), KM_SLEEP);
1862d65f6f70SBen Gras
1863d65f6f70SBen Gras /* Setting up eraseblock header properties */
1864d65f6f70SBen Gras ebh->ops->create_eb_hdr(ebhdr, lnr);
1865d65f6f70SBen Gras
1866d65f6f70SBen Gras retry:
1867d65f6f70SBen Gras /* Getting a physical eraseblock from the wear leveling system */
1868d65f6f70SBen Gras pebnr = get_peb(ebh);
1869d65f6f70SBen Gras if (pebnr < 0) {
1870d65f6f70SBen Gras leb_write_unlock(ebh, lnr);
1871d65f6f70SBen Gras kmem_free(ebhdr, sizeof(struct chfs_eb_hdr));
1872d65f6f70SBen Gras return pebnr;
1873d65f6f70SBen Gras }
1874d65f6f70SBen Gras
1875d65f6f70SBen Gras /* Write the eraseblock header to the media */
1876d65f6f70SBen Gras err = ebh->ops->write_eb_hdr(ebh, pebnr, ebhdr);
1877d65f6f70SBen Gras if (err) {
1878d65f6f70SBen Gras chfs_warn(
1879d65f6f70SBen Gras "error writing eraseblock header: LEB %d , PEB %d\n",
1880d65f6f70SBen Gras lnr, pebnr);
1881d65f6f70SBen Gras goto write_error;
1882d65f6f70SBen Gras }
1883d65f6f70SBen Gras
1884d65f6f70SBen Gras /* Write out data */
1885d65f6f70SBen Gras if (len) {
1886d65f6f70SBen Gras data_offset = ebh->ops->calc_data_offs(ebh, pebnr, offset);
1887d65f6f70SBen Gras err = flash_write(ebh->flash_dev,
1888d65f6f70SBen Gras data_offset, len, retlen, (unsigned char *) buf);
1889d65f6f70SBen Gras if (err) {
1890d65f6f70SBen Gras chfs_err("error %d while writing %zu bytes to PEB "
1891d65f6f70SBen Gras " %d:%ju, written %zu bytes\n",
1892d65f6f70SBen Gras err, len, pebnr, (uintmax_t )offset, *retlen);
1893d65f6f70SBen Gras goto write_error;
1894d65f6f70SBen Gras }
1895d65f6f70SBen Gras }
1896d65f6f70SBen Gras
1897d65f6f70SBen Gras ebh->lmap[lnr] = pebnr;
1898d65f6f70SBen Gras leb_write_unlock(ebh, lnr);
1899d65f6f70SBen Gras kmem_free(ebhdr, sizeof(struct chfs_eb_hdr));
1900d65f6f70SBen Gras
1901d65f6f70SBen Gras return 0;
1902d65f6f70SBen Gras
1903d65f6f70SBen Gras write_error: err = release_peb(ebh, pebnr);
1904d65f6f70SBen Gras // max retries (NOW: 2)
1905d65f6f70SBen Gras if (err || CHFS_MAX_GET_PEB_RETRIES < ++retries) {
1906d65f6f70SBen Gras leb_write_unlock(ebh, lnr);
1907d65f6f70SBen Gras kmem_free(ebhdr, sizeof(struct chfs_eb_hdr));
1908d65f6f70SBen Gras return err;
1909d65f6f70SBen Gras }
1910d65f6f70SBen Gras goto retry;
1911d65f6f70SBen Gras }
1912d65f6f70SBen Gras
1913d65f6f70SBen Gras /**
1914d65f6f70SBen Gras * ebh_erase_leb - erase a leb
1915d65f6f70SBen Gras * @ebh: eraseblock handler
1916d65f6f70SBen Gras * @lnr: leb number
1917d65f6f70SBen Gras *
1918d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
1919d65f6f70SBen Gras */
1920d65f6f70SBen Gras int
ebh_erase_leb(struct chfs_ebh * ebh,int lnr)1921d65f6f70SBen Gras ebh_erase_leb(struct chfs_ebh *ebh, int lnr)
1922d65f6f70SBen Gras {
1923d65f6f70SBen Gras int err, pebnr;
1924d65f6f70SBen Gras
1925d65f6f70SBen Gras leb_write_lock(ebh, lnr);
1926d65f6f70SBen Gras
1927d65f6f70SBen Gras pebnr = ebh->lmap[lnr];
1928d65f6f70SBen Gras if (pebnr < 0) {
1929d65f6f70SBen Gras leb_write_unlock(ebh, lnr);
1930d65f6f70SBen Gras return EBH_LEB_UNMAPPED;
1931d65f6f70SBen Gras }
1932d65f6f70SBen Gras err = release_peb(ebh, pebnr);
1933d65f6f70SBen Gras if (err)
1934d65f6f70SBen Gras goto out_unlock;
1935d65f6f70SBen Gras
1936d65f6f70SBen Gras ebh->lmap[lnr] = EBH_LEB_UNMAPPED;
1937d65f6f70SBen Gras cv_signal(&ebh->bg_erase.eth_wakeup);
1938d65f6f70SBen Gras out_unlock:
1939d65f6f70SBen Gras leb_write_unlock(ebh, lnr);
1940d65f6f70SBen Gras return err;
1941d65f6f70SBen Gras }
1942d65f6f70SBen Gras
1943d65f6f70SBen Gras /**
1944d65f6f70SBen Gras * ebh_map_leb - maps a PEB to LEB
1945d65f6f70SBen Gras * @ebh: eraseblock handler
1946d65f6f70SBen Gras * @lnr: leb number
1947d65f6f70SBen Gras *
1948d65f6f70SBen Gras * Returns zero on success, error code in case of fail
1949d65f6f70SBen Gras */
1950d65f6f70SBen Gras int
ebh_map_leb(struct chfs_ebh * ebh,int lnr)1951d65f6f70SBen Gras ebh_map_leb(struct chfs_ebh *ebh, int lnr)
1952d65f6f70SBen Gras {
1953d65f6f70SBen Gras int err, pebnr, retries = 0;
1954d65f6f70SBen Gras struct chfs_eb_hdr *ebhdr;
1955d65f6f70SBen Gras
1956d65f6f70SBen Gras ebhdr = kmem_alloc(sizeof(struct chfs_eb_hdr), KM_SLEEP);
1957d65f6f70SBen Gras
1958d65f6f70SBen Gras err = leb_write_lock(ebh, lnr);
1959*0a6a1f1dSLionel Sambuc if (err) {
1960*0a6a1f1dSLionel Sambuc kmem_free(ebhdr, sizeof(struct chfs_eb_hdr));
1961d65f6f70SBen Gras return err;
1962*0a6a1f1dSLionel Sambuc }
1963d65f6f70SBen Gras
1964d65f6f70SBen Gras retry:
1965d65f6f70SBen Gras pebnr = get_peb(ebh);
1966d65f6f70SBen Gras if (pebnr < 0) {
1967d65f6f70SBen Gras err = pebnr;
1968d65f6f70SBen Gras goto out_unlock;
1969d65f6f70SBen Gras }
1970d65f6f70SBen Gras
1971d65f6f70SBen Gras ebh->ops->create_eb_hdr(ebhdr, lnr);
1972d65f6f70SBen Gras
1973d65f6f70SBen Gras err = ebh->ops->write_eb_hdr(ebh, pebnr, ebhdr);
1974d65f6f70SBen Gras if (err) {
1975d65f6f70SBen Gras chfs_warn(
1976d65f6f70SBen Gras "error writing eraseblock header: LEB %d , PEB %d\n",
1977d65f6f70SBen Gras lnr, pebnr);
1978d65f6f70SBen Gras goto write_error;
1979d65f6f70SBen Gras }
1980d65f6f70SBen Gras
1981d65f6f70SBen Gras ebh->lmap[lnr] = pebnr;
1982d65f6f70SBen Gras
1983d65f6f70SBen Gras out_unlock:
1984d65f6f70SBen Gras leb_write_unlock(ebh, lnr);
1985d65f6f70SBen Gras return err;
1986d65f6f70SBen Gras
1987d65f6f70SBen Gras write_error:
1988d65f6f70SBen Gras err = release_peb(ebh, pebnr);
1989d65f6f70SBen Gras // max retries (NOW: 2)
1990d65f6f70SBen Gras if (err || CHFS_MAX_GET_PEB_RETRIES < ++retries) {
1991d65f6f70SBen Gras leb_write_unlock(ebh, lnr);
1992d65f6f70SBen Gras kmem_free(ebhdr, sizeof(struct chfs_eb_hdr));
1993d65f6f70SBen Gras return err;
1994d65f6f70SBen Gras }
1995d65f6f70SBen Gras goto retry;
1996d65f6f70SBen Gras }
1997d65f6f70SBen Gras
1998d65f6f70SBen Gras /**
1999d65f6f70SBen Gras * ebh_unmap_leb -
2000d65f6f70SBen Gras * @ebh: eraseblock handler
2001d65f6f70SBen Gras * @lnr: leb number
2002d65f6f70SBen Gras *
2003d65f6f70SBen Gras * Retruns zero on success, error code in case of fail.
2004d65f6f70SBen Gras */
2005d65f6f70SBen Gras int
ebh_unmap_leb(struct chfs_ebh * ebh,int lnr)2006d65f6f70SBen Gras ebh_unmap_leb(struct chfs_ebh *ebh, int lnr)
2007d65f6f70SBen Gras {
2008d65f6f70SBen Gras int err;
2009d65f6f70SBen Gras
2010d65f6f70SBen Gras if (ebh_is_mapped(ebh, lnr) < 0)
2011d65f6f70SBen Gras /* If the eraseblock already unmapped */
2012d65f6f70SBen Gras return 0;
2013d65f6f70SBen Gras
2014d65f6f70SBen Gras err = ebh_erase_leb(ebh, lnr);
2015d65f6f70SBen Gras
2016d65f6f70SBen Gras return err;
2017d65f6f70SBen Gras }
2018d65f6f70SBen Gras
2019d65f6f70SBen Gras /**
2020d65f6f70SBen Gras * ebh_is_mapped - check if a PEB is mapped to @lnr
2021d65f6f70SBen Gras * @ebh: eraseblock handler
2022d65f6f70SBen Gras * @lnr: leb number
2023d65f6f70SBen Gras *
2024d65f6f70SBen Gras * Retruns 0 if the logical eraseblock is mapped, negative error code otherwise.
2025d65f6f70SBen Gras */
2026d65f6f70SBen Gras int
ebh_is_mapped(struct chfs_ebh * ebh,int lnr)2027d65f6f70SBen Gras ebh_is_mapped(struct chfs_ebh *ebh, int lnr)
2028d65f6f70SBen Gras {
2029d65f6f70SBen Gras int err, result;
2030d65f6f70SBen Gras err = leb_read_lock(ebh, lnr);
2031d65f6f70SBen Gras if (err)
2032d65f6f70SBen Gras return err;
2033d65f6f70SBen Gras
2034d65f6f70SBen Gras result = ebh->lmap[lnr];
2035d65f6f70SBen Gras leb_read_unlock(ebh, lnr);
2036d65f6f70SBen Gras
2037d65f6f70SBen Gras return result;
2038d65f6f70SBen Gras }
2039d65f6f70SBen Gras
2040d65f6f70SBen Gras /**
2041d65f6f70SBen Gras * ebh_change_leb - write the LEB to another PEB
2042d65f6f70SBen Gras * @ebh: eraseblock handler
2043d65f6f70SBen Gras * @lnr: leb number
2044d65f6f70SBen Gras * @buf: data to write
2045d65f6f70SBen Gras * @len: length of data
2046d65f6f70SBen Gras * Returns zero in case of success, error code in case of fail.
2047d65f6f70SBen Gras */
2048d65f6f70SBen Gras int
ebh_change_leb(struct chfs_ebh * ebh,int lnr,char * buf,size_t len,size_t * retlen)2049d65f6f70SBen Gras ebh_change_leb(struct chfs_ebh *ebh, int lnr, char *buf, size_t len,
2050d65f6f70SBen Gras size_t *retlen)
2051d65f6f70SBen Gras {
2052d65f6f70SBen Gras int err, pebnr, pebnr_old, retries = 0;
2053d65f6f70SBen Gras off_t data_offset;
2054d65f6f70SBen Gras
2055d65f6f70SBen Gras struct chfs_peb *peb = NULL;
2056d65f6f70SBen Gras struct chfs_eb_hdr *ebhdr;
2057d65f6f70SBen Gras
2058d65f6f70SBen Gras if (ebh_is_mapped(ebh, lnr) < 0)
2059d65f6f70SBen Gras return EBH_LEB_UNMAPPED;
2060d65f6f70SBen Gras
2061d65f6f70SBen Gras if (len == 0) {
2062d65f6f70SBen Gras err = ebh_unmap_leb(ebh, lnr);
2063d65f6f70SBen Gras if (err)
2064d65f6f70SBen Gras return err;
2065d65f6f70SBen Gras return ebh_map_leb(ebh, lnr);
2066d65f6f70SBen Gras }
2067d65f6f70SBen Gras
2068d65f6f70SBen Gras ebhdr = kmem_alloc(sizeof(struct chfs_eb_hdr), KM_SLEEP);
2069d65f6f70SBen Gras
2070d65f6f70SBen Gras pebnr_old = ebh->lmap[lnr];
2071d65f6f70SBen Gras
2072d65f6f70SBen Gras mutex_enter(&ebh->alc_mutex);
2073d65f6f70SBen Gras err = leb_write_lock(ebh, lnr);
2074d65f6f70SBen Gras if (err)
2075d65f6f70SBen Gras goto out_mutex;
2076d65f6f70SBen Gras
2077d65f6f70SBen Gras if (ebh->ops->mark_eb_hdr_dirty_flash) {
2078d65f6f70SBen Gras err = ebh->ops->mark_eb_hdr_dirty_flash(ebh, pebnr_old, lnr);
2079d65f6f70SBen Gras if (err)
2080d65f6f70SBen Gras goto out_unlock;
2081d65f6f70SBen Gras }
2082d65f6f70SBen Gras
2083d65f6f70SBen Gras /* Setting up eraseblock header properties */
2084d65f6f70SBen Gras ebh->ops->create_eb_hdr(ebhdr, lnr);
2085d65f6f70SBen Gras
2086d65f6f70SBen Gras retry:
2087d65f6f70SBen Gras /* Getting a physical eraseblock from the wear leveling system */
2088d65f6f70SBen Gras pebnr = get_peb(ebh);
2089d65f6f70SBen Gras if (pebnr < 0) {
2090d65f6f70SBen Gras leb_write_unlock(ebh, lnr);
2091d65f6f70SBen Gras mutex_exit(&ebh->alc_mutex);
2092d65f6f70SBen Gras kmem_free(ebhdr, sizeof(struct chfs_eb_hdr));
2093d65f6f70SBen Gras return pebnr;
2094d65f6f70SBen Gras }
2095d65f6f70SBen Gras
2096d65f6f70SBen Gras err = ebh->ops->write_eb_hdr(ebh, pebnr, ebhdr);
2097d65f6f70SBen Gras if (err) {
2098d65f6f70SBen Gras chfs_warn(
2099d65f6f70SBen Gras "error writing eraseblock header: LEB %d , PEB %d",
2100d65f6f70SBen Gras lnr, pebnr);
2101d65f6f70SBen Gras goto write_error;
2102d65f6f70SBen Gras }
2103d65f6f70SBen Gras
2104d65f6f70SBen Gras /* Write out data */
2105d65f6f70SBen Gras data_offset = ebh->ops->calc_data_offs(ebh, pebnr, 0);
2106d65f6f70SBen Gras err = flash_write(ebh->flash_dev, data_offset, len, retlen,
2107d65f6f70SBen Gras (unsigned char *) buf);
2108d65f6f70SBen Gras if (err) {
2109d65f6f70SBen Gras chfs_err("error %d while writing %zu bytes to PEB %d:%ju,"
2110d65f6f70SBen Gras " written %zu bytes",
2111d65f6f70SBen Gras err, len, pebnr, (uintmax_t)data_offset, *retlen);
2112d65f6f70SBen Gras goto write_error;
2113d65f6f70SBen Gras }
2114d65f6f70SBen Gras
2115d65f6f70SBen Gras ebh->lmap[lnr] = pebnr;
2116d65f6f70SBen Gras
2117d65f6f70SBen Gras if (ebh->ops->invalidate_eb_hdr) {
2118d65f6f70SBen Gras err = ebh->ops->invalidate_eb_hdr(ebh, pebnr_old);
2119d65f6f70SBen Gras if (err)
2120d65f6f70SBen Gras goto out_unlock;
2121d65f6f70SBen Gras }
2122d65f6f70SBen Gras peb = find_peb_in_use(ebh, pebnr_old);
2123d65f6f70SBen Gras err = release_peb(ebh, peb->pebnr);
2124d65f6f70SBen Gras
2125d65f6f70SBen Gras out_unlock:
2126d65f6f70SBen Gras leb_write_unlock(ebh, lnr);
2127d65f6f70SBen Gras
2128d65f6f70SBen Gras out_mutex:
2129d65f6f70SBen Gras mutex_exit(&ebh->alc_mutex);
2130d65f6f70SBen Gras kmem_free(ebhdr, sizeof(struct chfs_eb_hdr));
2131d65f6f70SBen Gras kmem_free(peb, sizeof(struct chfs_peb));
2132d65f6f70SBen Gras return err;
2133d65f6f70SBen Gras
2134d65f6f70SBen Gras write_error:
2135d65f6f70SBen Gras err = release_peb(ebh, pebnr);
2136d65f6f70SBen Gras //max retries (NOW: 2)
2137d65f6f70SBen Gras if (err || CHFS_MAX_GET_PEB_RETRIES < ++retries) {
2138d65f6f70SBen Gras leb_write_unlock(ebh, lnr);
2139d65f6f70SBen Gras mutex_exit(&ebh->alc_mutex);
2140d65f6f70SBen Gras kmem_free(ebhdr, sizeof(struct chfs_eb_hdr));
2141d65f6f70SBen Gras return err;
2142d65f6f70SBen Gras }
2143d65f6f70SBen Gras goto retry;
2144d65f6f70SBen Gras }
2145d65f6f70SBen Gras
2146