xref: /minix3/sys/ufs/chfs/ebh.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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