1*10465441SEvalZero /*
2*10465441SEvalZero This file is part of UFFS, the Ultra-low-cost Flash File System.
3*10465441SEvalZero
4*10465441SEvalZero Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
5*10465441SEvalZero
6*10465441SEvalZero UFFS is free software; you can redistribute it and/or modify it under
7*10465441SEvalZero the GNU Library General Public License as published by the Free Software
8*10465441SEvalZero Foundation; either version 2 of the License, or (at your option) any
9*10465441SEvalZero later version.
10*10465441SEvalZero
11*10465441SEvalZero UFFS is distributed in the hope that it will be useful, but WITHOUT
12*10465441SEvalZero ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*10465441SEvalZero FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14*10465441SEvalZero or GNU Library General Public License, as applicable, for more details.
15*10465441SEvalZero
16*10465441SEvalZero You should have received a copy of the GNU General Public License
17*10465441SEvalZero and GNU Library General Public License along with UFFS; if not, write
18*10465441SEvalZero to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19*10465441SEvalZero Boston, MA 02110-1301, USA.
20*10465441SEvalZero
21*10465441SEvalZero As a special exception, if other files instantiate templates or use
22*10465441SEvalZero macros or inline functions from this file, or you compile this file
23*10465441SEvalZero and link it with other works to produce a work based on this file,
24*10465441SEvalZero this file does not by itself cause the resulting work to be covered
25*10465441SEvalZero by the GNU General Public License. However the source code for this
26*10465441SEvalZero file must still be made available in accordance with section (3) of
27*10465441SEvalZero the GNU General Public License v2.
28*10465441SEvalZero
29*10465441SEvalZero This exception does not invalidate any other reasons why a work based
30*10465441SEvalZero on this file might be covered by the GNU General Public License.
31*10465441SEvalZero */
32*10465441SEvalZero /**
33*10465441SEvalZero * \file uffs_buf.c
34*10465441SEvalZero * \brief uffs page buffers manipulations
35*10465441SEvalZero * \author Ricky Zheng
36*10465441SEvalZero * \note Created in 11th May, 2005
37*10465441SEvalZero */
38*10465441SEvalZero #include "uffs_config.h"
39*10465441SEvalZero #include "uffs/uffs_types.h"
40*10465441SEvalZero #include "uffs/uffs_buf.h"
41*10465441SEvalZero #include "uffs/uffs_device.h"
42*10465441SEvalZero #include "uffs/uffs_os.h"
43*10465441SEvalZero #include "uffs/uffs_public.h"
44*10465441SEvalZero #include "uffs/uffs_pool.h"
45*10465441SEvalZero #include "uffs/uffs_ecc.h"
46*10465441SEvalZero #include "uffs/uffs_badblock.h"
47*10465441SEvalZero #include <string.h>
48*10465441SEvalZero
49*10465441SEvalZero #define PFX "pbuf: "
50*10465441SEvalZero
51*10465441SEvalZero
52*10465441SEvalZero URET _BufFlush(struct uffs_DeviceSt *dev, UBOOL force_block_recover, int slot);
53*10465441SEvalZero
54*10465441SEvalZero
55*10465441SEvalZero /**
56*10465441SEvalZero * \brief inspect (print) uffs page buffers.
57*10465441SEvalZero * \param[in] dev uffs device to be inspected.
58*10465441SEvalZero */
uffs_BufInspect(uffs_Device * dev)59*10465441SEvalZero void uffs_BufInspect(uffs_Device *dev)
60*10465441SEvalZero {
61*10465441SEvalZero struct uffs_PageBufDescSt *pb = &dev->buf;
62*10465441SEvalZero uffs_Buf *buf;
63*10465441SEvalZero
64*10465441SEvalZero uffs_PerrorRaw(UFFS_MSG_NORMAL,
65*10465441SEvalZero "------------- page buffer inspect ---------" TENDSTR);
66*10465441SEvalZero uffs_PerrorRaw(UFFS_MSG_NORMAL, "all buffers: " TENDSTR);
67*10465441SEvalZero for (buf = pb->head; buf; buf = buf->next) {
68*10465441SEvalZero if (buf->mark != 0) {
69*10465441SEvalZero uffs_PerrorRaw(UFFS_MSG_NORMAL,
70*10465441SEvalZero "\tF:%04x S:%04x P:%02d R:%02d D:%03d M:%c EM:%d" TENDSTR,
71*10465441SEvalZero buf->parent, buf->serial,
72*10465441SEvalZero buf->page_id, buf->ref_count,
73*10465441SEvalZero buf->data_len, buf->mark == UFFS_BUF_VALID ? 'V' : 'D',
74*10465441SEvalZero buf->ext_mark);
75*10465441SEvalZero }
76*10465441SEvalZero }
77*10465441SEvalZero uffs_PerrorRaw(UFFS_MSG_NORMAL,
78*10465441SEvalZero "--------------------------------------------" TENDSTR);
79*10465441SEvalZero }
80*10465441SEvalZero
81*10465441SEvalZero /**
82*10465441SEvalZero * \brief initialize page buffers for device
83*10465441SEvalZero * in UFFS, each device has one buffer pool
84*10465441SEvalZero * \param[in] dev uffs device
85*10465441SEvalZero * \param[in] buf_max maximum buffer number, normally use #MAX_PAGE_BUFFERS
86*10465441SEvalZero * \param[in] dirty_buf_max maximum dirty buffer allowed,
87*10465441SEvalZero * if the dirty buffer over this number,
88*10465441SEvalZero * than need to be flush to flash
89*10465441SEvalZero */
uffs_BufInit(uffs_Device * dev,int buf_max,int dirty_buf_max)90*10465441SEvalZero URET uffs_BufInit(uffs_Device *dev, int buf_max, int dirty_buf_max)
91*10465441SEvalZero {
92*10465441SEvalZero void *pool;
93*10465441SEvalZero u8 *data;
94*10465441SEvalZero uffs_Buf *buf;
95*10465441SEvalZero int size;
96*10465441SEvalZero int i, slot;
97*10465441SEvalZero
98*10465441SEvalZero if (!dev)
99*10465441SEvalZero return U_FAIL;
100*10465441SEvalZero
101*10465441SEvalZero //init device common parameters, which are needed by page buffers
102*10465441SEvalZero dev->com.pg_size = dev->attr->page_data_size; // we use the whole page.
103*10465441SEvalZero dev->com.header_size = sizeof(struct uffs_MiniHeaderSt); // mini header
104*10465441SEvalZero dev->com.pg_data_size = dev->com.pg_size - dev->com.header_size;
105*10465441SEvalZero
106*10465441SEvalZero if (dev->buf.pool != NULL) {
107*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL,
108*10465441SEvalZero "buf.pool is not NULL, buf already inited ?");
109*10465441SEvalZero return U_FAIL;
110*10465441SEvalZero }
111*10465441SEvalZero
112*10465441SEvalZero size = (sizeof(uffs_Buf) + dev->com.pg_size) * buf_max;
113*10465441SEvalZero if (dev->mem.pagebuf_pool_size == 0) {
114*10465441SEvalZero if (dev->mem.malloc) {
115*10465441SEvalZero dev->mem.pagebuf_pool_buf = dev->mem.malloc(dev, size);
116*10465441SEvalZero if (dev->mem.pagebuf_pool_buf)
117*10465441SEvalZero dev->mem.pagebuf_pool_size = size;
118*10465441SEvalZero }
119*10465441SEvalZero }
120*10465441SEvalZero if (size > dev->mem.pagebuf_pool_size) {
121*10465441SEvalZero uffs_Perror(UFFS_MSG_DEAD,
122*10465441SEvalZero "page buffers require %d but only %d available.",
123*10465441SEvalZero size, dev->mem.pagebuf_pool_size);
124*10465441SEvalZero return U_FAIL;
125*10465441SEvalZero }
126*10465441SEvalZero pool = dev->mem.pagebuf_pool_buf;
127*10465441SEvalZero
128*10465441SEvalZero uffs_Perror(UFFS_MSG_NOISY, "alloc %d bytes.", size);
129*10465441SEvalZero dev->buf.pool = pool;
130*10465441SEvalZero
131*10465441SEvalZero for (i = 0; i < buf_max; i++) {
132*10465441SEvalZero buf = (uffs_Buf *)((u8 *)pool + (sizeof(uffs_Buf) * i));
133*10465441SEvalZero memset(buf, 0, sizeof(uffs_Buf));
134*10465441SEvalZero data = (u8 *)pool + (sizeof(uffs_Buf) * buf_max) + (dev->com.pg_size * i);
135*10465441SEvalZero buf->header = data;
136*10465441SEvalZero buf->data = data + dev->com.header_size;
137*10465441SEvalZero buf->mark = UFFS_BUF_EMPTY;
138*10465441SEvalZero memset(buf->header, 0, dev->com.pg_size);
139*10465441SEvalZero if (i == 0) {
140*10465441SEvalZero buf->prev = NULL;
141*10465441SEvalZero dev->buf.head = buf;
142*10465441SEvalZero }
143*10465441SEvalZero else {
144*10465441SEvalZero buf->prev = (uffs_Buf *)((u8 *)buf - sizeof(uffs_Buf));
145*10465441SEvalZero }
146*10465441SEvalZero
147*10465441SEvalZero if (i == (buf_max - 1)) {
148*10465441SEvalZero buf->next = NULL;
149*10465441SEvalZero dev->buf.tail = buf;
150*10465441SEvalZero }
151*10465441SEvalZero else {
152*10465441SEvalZero buf->next = (uffs_Buf *)((u8 *)buf + sizeof(uffs_Buf));
153*10465441SEvalZero }
154*10465441SEvalZero }
155*10465441SEvalZero
156*10465441SEvalZero dev->buf.buf_max = buf_max;
157*10465441SEvalZero dev->buf.dirty_buf_max = (dirty_buf_max > dev->attr->pages_per_block ?
158*10465441SEvalZero dev->attr->pages_per_block : dirty_buf_max);
159*10465441SEvalZero
160*10465441SEvalZero for (slot = 0; slot < dev->cfg.dirty_groups; slot++) {
161*10465441SEvalZero dev->buf.dirtyGroup[slot].dirty = NULL;
162*10465441SEvalZero dev->buf.dirtyGroup[slot].count = 0;
163*10465441SEvalZero }
164*10465441SEvalZero return U_SUCC;
165*10465441SEvalZero }
166*10465441SEvalZero
167*10465441SEvalZero /**
168*10465441SEvalZero * \brief flush all buffers
169*10465441SEvalZero */
uffs_BufFlushAll(struct uffs_DeviceSt * dev)170*10465441SEvalZero URET uffs_BufFlushAll(struct uffs_DeviceSt *dev)
171*10465441SEvalZero {
172*10465441SEvalZero int slot;
173*10465441SEvalZero for (slot = 0; slot < dev->cfg.dirty_groups; slot++) {
174*10465441SEvalZero if(_BufFlush(dev, FALSE, slot) != U_SUCC) {
175*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL,
176*10465441SEvalZero "fail to flush buffer(slot %d)", slot);
177*10465441SEvalZero return U_FAIL;
178*10465441SEvalZero }
179*10465441SEvalZero }
180*10465441SEvalZero return U_SUCC;
181*10465441SEvalZero }
182*10465441SEvalZero
183*10465441SEvalZero /**
184*10465441SEvalZero * \brief release all page buffer, this function should be called
185*10465441SEvalZero when unmounting a uffs device
186*10465441SEvalZero * \param[in] dev uffs device
187*10465441SEvalZero * \note if there are page buffers in used, it may cause fail to release
188*10465441SEvalZero */
uffs_BufReleaseAll(uffs_Device * dev)189*10465441SEvalZero URET uffs_BufReleaseAll(uffs_Device *dev)
190*10465441SEvalZero {
191*10465441SEvalZero uffs_Buf *p;
192*10465441SEvalZero
193*10465441SEvalZero if (!dev)
194*10465441SEvalZero return U_FAIL;
195*10465441SEvalZero
196*10465441SEvalZero //now release all buffer
197*10465441SEvalZero p = dev->buf.head;
198*10465441SEvalZero while (p) {
199*10465441SEvalZero if (p->ref_count != 0) {
200*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL, PFX
201*10465441SEvalZero "can't release buffers, parent:%d, serial:%d, \
202*10465441SEvalZero page_id:%d still in used.\n",
203*10465441SEvalZero p->parent, p->serial, p->page_id);
204*10465441SEvalZero return U_FAIL;
205*10465441SEvalZero }
206*10465441SEvalZero p = p->next;
207*10465441SEvalZero }
208*10465441SEvalZero
209*10465441SEvalZero if (uffs_BufFlushAll(dev) != U_SUCC) {
210*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL,
211*10465441SEvalZero "can't release buf, fail to flush buffer");
212*10465441SEvalZero return U_FAIL;
213*10465441SEvalZero }
214*10465441SEvalZero
215*10465441SEvalZero if (dev->mem.free) {
216*10465441SEvalZero dev->mem.free(dev, dev->buf.pool);
217*10465441SEvalZero dev->mem.pagebuf_pool_size = 0;
218*10465441SEvalZero }
219*10465441SEvalZero
220*10465441SEvalZero dev->buf.pool = NULL;
221*10465441SEvalZero dev->buf.head = dev->buf.tail = NULL;
222*10465441SEvalZero
223*10465441SEvalZero return U_SUCC;
224*10465441SEvalZero }
225*10465441SEvalZero
226*10465441SEvalZero
_BreakFromBufList(uffs_Device * dev,uffs_Buf * buf)227*10465441SEvalZero static void _BreakFromBufList(uffs_Device *dev, uffs_Buf *buf)
228*10465441SEvalZero {
229*10465441SEvalZero if(buf->next)
230*10465441SEvalZero buf->next->prev = buf->prev;
231*10465441SEvalZero
232*10465441SEvalZero if(buf->prev)
233*10465441SEvalZero buf->prev->next = buf->next;
234*10465441SEvalZero
235*10465441SEvalZero if(dev->buf.head == buf)
236*10465441SEvalZero dev->buf.head = buf->next;
237*10465441SEvalZero
238*10465441SEvalZero if(dev->buf.tail == buf)
239*10465441SEvalZero dev->buf.tail = buf->prev;
240*10465441SEvalZero
241*10465441SEvalZero }
242*10465441SEvalZero
_LinkToBufListHead(uffs_Device * dev,uffs_Buf * buf)243*10465441SEvalZero static void _LinkToBufListHead(uffs_Device *dev, uffs_Buf *buf)
244*10465441SEvalZero {
245*10465441SEvalZero if (buf == dev->buf.head)
246*10465441SEvalZero return;
247*10465441SEvalZero
248*10465441SEvalZero buf->prev = NULL;
249*10465441SEvalZero buf->next = dev->buf.head;
250*10465441SEvalZero
251*10465441SEvalZero if (dev->buf.head)
252*10465441SEvalZero dev->buf.head->prev = buf;
253*10465441SEvalZero
254*10465441SEvalZero if (dev->buf.tail == NULL)
255*10465441SEvalZero dev->buf.tail = buf;
256*10465441SEvalZero
257*10465441SEvalZero dev->buf.head = buf;
258*10465441SEvalZero }
259*10465441SEvalZero
_LinkToBufListTail(uffs_Device * dev,uffs_Buf * buf)260*10465441SEvalZero static void _LinkToBufListTail(uffs_Device *dev, uffs_Buf *buf)
261*10465441SEvalZero {
262*10465441SEvalZero if (dev->buf.tail == buf)
263*10465441SEvalZero return;
264*10465441SEvalZero
265*10465441SEvalZero buf->prev = dev->buf.tail;
266*10465441SEvalZero buf->next = NULL;
267*10465441SEvalZero
268*10465441SEvalZero if (dev->buf.tail)
269*10465441SEvalZero dev->buf.tail->next = buf;
270*10465441SEvalZero
271*10465441SEvalZero if (dev->buf.head == NULL)
272*10465441SEvalZero dev->buf.head = buf;
273*10465441SEvalZero
274*10465441SEvalZero dev->buf.tail = buf;
275*10465441SEvalZero }
276*10465441SEvalZero
277*10465441SEvalZero //move a node which linked in the list to the head of list
_MoveNodeToHead(uffs_Device * dev,uffs_Buf * p)278*10465441SEvalZero static void _MoveNodeToHead(uffs_Device *dev, uffs_Buf *p)
279*10465441SEvalZero {
280*10465441SEvalZero if (p == dev->buf.head)
281*10465441SEvalZero return;
282*10465441SEvalZero
283*10465441SEvalZero //break from list
284*10465441SEvalZero _BreakFromBufList(dev, p);
285*10465441SEvalZero
286*10465441SEvalZero //link to head
287*10465441SEvalZero _LinkToBufListHead(dev, p);
288*10465441SEvalZero }
289*10465441SEvalZero
290*10465441SEvalZero // check if the buf is already in dirty list
_IsBufInInDirtyList(uffs_Device * dev,int slot,uffs_Buf * buf)291*10465441SEvalZero static UBOOL _IsBufInInDirtyList(uffs_Device *dev, int slot, uffs_Buf *buf)
292*10465441SEvalZero {
293*10465441SEvalZero uffs_Buf *work;
294*10465441SEvalZero work = dev->buf.dirtyGroup[slot].dirty;
295*10465441SEvalZero while (work) {
296*10465441SEvalZero if (work == buf)
297*10465441SEvalZero return U_TRUE;
298*10465441SEvalZero work = work->next_dirty;
299*10465441SEvalZero }
300*10465441SEvalZero
301*10465441SEvalZero return U_FALSE;
302*10465441SEvalZero }
303*10465441SEvalZero
_LinkToDirtyList(uffs_Device * dev,int slot,uffs_Buf * buf)304*10465441SEvalZero static void _LinkToDirtyList(uffs_Device *dev, int slot, uffs_Buf *buf)
305*10465441SEvalZero {
306*10465441SEvalZero
307*10465441SEvalZero if (buf == NULL) {
308*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS,
309*10465441SEvalZero "Try to insert a NULL node into dirty list ?");
310*10465441SEvalZero return;
311*10465441SEvalZero }
312*10465441SEvalZero
313*10465441SEvalZero buf->mark = UFFS_BUF_DIRTY;
314*10465441SEvalZero buf->prev_dirty = NULL;
315*10465441SEvalZero buf->next_dirty = dev->buf.dirtyGroup[slot].dirty;
316*10465441SEvalZero
317*10465441SEvalZero if (dev->buf.dirtyGroup[slot].dirty)
318*10465441SEvalZero dev->buf.dirtyGroup[slot].dirty->prev_dirty = buf;
319*10465441SEvalZero
320*10465441SEvalZero dev->buf.dirtyGroup[slot].dirty = buf;
321*10465441SEvalZero dev->buf.dirtyGroup[slot].count++;
322*10465441SEvalZero }
323*10465441SEvalZero
CountFreeBuf(uffs_Device * dev)324*10465441SEvalZero static int CountFreeBuf(uffs_Device *dev)
325*10465441SEvalZero {
326*10465441SEvalZero int count = 0;
327*10465441SEvalZero
328*10465441SEvalZero uffs_Buf *buf = dev->buf.head;
329*10465441SEvalZero
330*10465441SEvalZero while (buf) {
331*10465441SEvalZero
332*10465441SEvalZero if (buf->ref_count == 0 &&
333*10465441SEvalZero buf->mark != UFFS_BUF_DIRTY)
334*10465441SEvalZero count++;
335*10465441SEvalZero
336*10465441SEvalZero buf = buf->next;
337*10465441SEvalZero }
338*10465441SEvalZero
339*10465441SEvalZero return count;
340*10465441SEvalZero }
341*10465441SEvalZero
_FindFreeBufEx(uffs_Device * dev,int clone)342*10465441SEvalZero static uffs_Buf * _FindFreeBufEx(uffs_Device *dev, int clone)
343*10465441SEvalZero {
344*10465441SEvalZero uffs_Buf *buf;
345*10465441SEvalZero
346*10465441SEvalZero if (!clone && CountFreeBuf(dev) <= CLONE_BUFFERS_THRESHOLD)
347*10465441SEvalZero return NULL;
348*10465441SEvalZero
349*10465441SEvalZero #if 0
350*10465441SEvalZero buf = dev->buf.head;
351*10465441SEvalZero while (buf) {
352*10465441SEvalZero
353*10465441SEvalZero if (buf->ref_count == 0 &&
354*10465441SEvalZero buf->mark != UFFS_BUF_DIRTY)
355*10465441SEvalZero return buf;
356*10465441SEvalZero
357*10465441SEvalZero buf = buf->next;
358*10465441SEvalZero }
359*10465441SEvalZero #else
360*10465441SEvalZero buf = dev->buf.tail;
361*10465441SEvalZero while (buf) {
362*10465441SEvalZero
363*10465441SEvalZero if(buf->ref_count == 0 &&
364*10465441SEvalZero buf->mark != UFFS_BUF_DIRTY)
365*10465441SEvalZero return buf;
366*10465441SEvalZero
367*10465441SEvalZero buf = buf->prev;
368*10465441SEvalZero }
369*10465441SEvalZero #endif
370*10465441SEvalZero
371*10465441SEvalZero return buf;
372*10465441SEvalZero }
373*10465441SEvalZero
_FindFreeBuf(uffs_Device * dev)374*10465441SEvalZero static uffs_Buf * _FindFreeBuf(uffs_Device *dev)
375*10465441SEvalZero {
376*10465441SEvalZero return _FindFreeBufEx(dev, 0);
377*10465441SEvalZero }
378*10465441SEvalZero
379*10465441SEvalZero
380*10465441SEvalZero /**
381*10465441SEvalZero * load psychical page data into buf and do ecc check
382*10465441SEvalZero * \param[in] dev uffs device
383*10465441SEvalZero * \param[in] buf buf to be load in
384*10465441SEvalZero * \param[in] block psychical block number
385*10465441SEvalZero * \param[in] page psychical page number
386*10465441SEvalZero * \return return U_SUCC if no error,
387*10465441SEvalZero * return U_FAIL if I/O error or ecc check fail
388*10465441SEvalZero */
uffs_BufLoadPhyData(uffs_Device * dev,uffs_Buf * buf,u32 block,u32 page)389*10465441SEvalZero URET uffs_BufLoadPhyData(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page)
390*10465441SEvalZero {
391*10465441SEvalZero int ret;
392*10465441SEvalZero
393*10465441SEvalZero ret = uffs_FlashReadPage(dev, block, page, buf, U_FALSE);
394*10465441SEvalZero
395*10465441SEvalZero if (UFFS_FLASH_HAVE_ERR(ret)) {
396*10465441SEvalZero buf->mark = UFFS_BUF_EMPTY;
397*10465441SEvalZero return U_FAIL;
398*10465441SEvalZero }
399*10465441SEvalZero else {
400*10465441SEvalZero buf->mark = UFFS_BUF_VALID;
401*10465441SEvalZero return U_SUCC;
402*10465441SEvalZero }
403*10465441SEvalZero }
404*10465441SEvalZero
405*10465441SEvalZero /**
406*10465441SEvalZero * \brief load psychical page data into buf and ignore ECC result
407*10465441SEvalZero *
408*10465441SEvalZero * \param[in] dev uffs device
409*10465441SEvalZero * \param[in] buf buf to be load in
410*10465441SEvalZero * \param[in] block psychical block number
411*10465441SEvalZero * \param[in] page psychical page number
412*10465441SEvalZero *
413*10465441SEvalZero * \return return U_SUCC if no error, return U_FAIL if I/O error
414*10465441SEvalZero * \note this function should be only used when doing bad block recover.
415*10465441SEvalZero */
uffs_LoadPhyDataToBufEccUnCare(uffs_Device * dev,uffs_Buf * buf,u32 block,u32 page)416*10465441SEvalZero URET uffs_LoadPhyDataToBufEccUnCare(uffs_Device *dev,
417*10465441SEvalZero uffs_Buf *buf, u32 block, u32 page)
418*10465441SEvalZero {
419*10465441SEvalZero int ret;
420*10465441SEvalZero
421*10465441SEvalZero ret = uffs_FlashReadPage(dev, block, page, buf, U_TRUE);
422*10465441SEvalZero
423*10465441SEvalZero if (ret == UFFS_FLASH_IO_ERR) {
424*10465441SEvalZero buf->mark = UFFS_BUF_EMPTY;
425*10465441SEvalZero return U_FAIL;
426*10465441SEvalZero }
427*10465441SEvalZero else {
428*10465441SEvalZero buf->mark = UFFS_BUF_VALID;
429*10465441SEvalZero return U_SUCC;
430*10465441SEvalZero }
431*10465441SEvalZero }
432*10465441SEvalZero
433*10465441SEvalZero /**
434*10465441SEvalZero * find a buffer in the pool
435*10465441SEvalZero * \param[in] dev uffs device
436*10465441SEvalZero * \param[in] start buf to search from
437*10465441SEvalZero * \param[in] parent parent serial num
438*10465441SEvalZero * \param[in] serial serial num
439*10465441SEvalZero * \param[in] page_id page_id (if page_id == UFFS_ALL_PAGES then any page would match)
440*10465441SEvalZero * \return return found buffer, return NULL if buffer not found
441*10465441SEvalZero */
uffs_BufFindFrom(uffs_Device * dev,uffs_Buf * start,u16 parent,u16 serial,u16 page_id)442*10465441SEvalZero uffs_Buf * uffs_BufFindFrom(uffs_Device *dev, uffs_Buf *start,
443*10465441SEvalZero u16 parent, u16 serial, u16 page_id)
444*10465441SEvalZero {
445*10465441SEvalZero uffs_Buf *p = start;
446*10465441SEvalZero
447*10465441SEvalZero while (p) {
448*10465441SEvalZero if( p->parent == parent &&
449*10465441SEvalZero p->serial == serial &&
450*10465441SEvalZero (page_id == UFFS_ALL_PAGES || p->page_id == page_id) &&
451*10465441SEvalZero p->mark != UFFS_BUF_EMPTY)
452*10465441SEvalZero {
453*10465441SEvalZero //they have match one
454*10465441SEvalZero return p;
455*10465441SEvalZero }
456*10465441SEvalZero p = p->next;
457*10465441SEvalZero }
458*10465441SEvalZero
459*10465441SEvalZero return NULL; //buffer not found
460*10465441SEvalZero }
461*10465441SEvalZero
462*10465441SEvalZero /**
463*10465441SEvalZero * find a buffer in the pool
464*10465441SEvalZero * \param[in] dev uffs device
465*10465441SEvalZero * \param[in] parent parent serial num
466*10465441SEvalZero * \param[in] serial serial num
467*10465441SEvalZero * \param[in] page_id page_id (if page_id == UFFS_ALL_PAGES then any page would match)
468*10465441SEvalZero * \return return found buffer, return NULL if buffer not found
469*10465441SEvalZero */
uffs_BufFind(uffs_Device * dev,u16 parent,u16 serial,u16 page_id)470*10465441SEvalZero uffs_Buf * uffs_BufFind(uffs_Device *dev,
471*10465441SEvalZero u16 parent, u16 serial, u16 page_id)
472*10465441SEvalZero {
473*10465441SEvalZero uffs_Buf *p = dev->buf.head;
474*10465441SEvalZero
475*10465441SEvalZero return uffs_BufFindFrom(dev, p, parent, serial, page_id);
476*10465441SEvalZero }
477*10465441SEvalZero
478*10465441SEvalZero
_FindBufInDirtyList(uffs_Buf * dirty,u16 page_id)479*10465441SEvalZero static uffs_Buf * _FindBufInDirtyList(uffs_Buf *dirty, u16 page_id)
480*10465441SEvalZero {
481*10465441SEvalZero while(dirty) {
482*10465441SEvalZero if (dirty->page_id == page_id)
483*10465441SEvalZero return dirty;
484*10465441SEvalZero dirty = dirty->next_dirty;
485*10465441SEvalZero }
486*10465441SEvalZero return NULL;
487*10465441SEvalZero }
488*10465441SEvalZero
_BreakFromDirty(uffs_Device * dev,uffs_Buf * dirtyBuf)489*10465441SEvalZero static URET _BreakFromDirty(uffs_Device *dev, uffs_Buf *dirtyBuf)
490*10465441SEvalZero {
491*10465441SEvalZero int slot = -1;
492*10465441SEvalZero
493*10465441SEvalZero if (dirtyBuf->mark != UFFS_BUF_DIRTY) {
494*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL,
495*10465441SEvalZero "try to break a non-dirty buf from dirty list ?");
496*10465441SEvalZero return U_FAIL;
497*10465441SEvalZero }
498*10465441SEvalZero
499*10465441SEvalZero slot = uffs_BufFindGroupSlot(dev, dirtyBuf->parent, dirtyBuf->serial);
500*10465441SEvalZero if (slot < 0) {
501*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL, "no dirty list exit ?");
502*10465441SEvalZero return U_FAIL;
503*10465441SEvalZero }
504*10465441SEvalZero
505*10465441SEvalZero // break from the link
506*10465441SEvalZero if (dirtyBuf->next_dirty) {
507*10465441SEvalZero dirtyBuf->next_dirty->prev_dirty = dirtyBuf->prev_dirty;
508*10465441SEvalZero }
509*10465441SEvalZero
510*10465441SEvalZero if (dirtyBuf->prev_dirty) {
511*10465441SEvalZero dirtyBuf->prev_dirty->next_dirty = dirtyBuf->next_dirty;
512*10465441SEvalZero }
513*10465441SEvalZero
514*10465441SEvalZero // check if it's the link head ...
515*10465441SEvalZero if (dev->buf.dirtyGroup[slot].dirty == dirtyBuf) {
516*10465441SEvalZero dev->buf.dirtyGroup[slot].dirty = dirtyBuf->next_dirty;
517*10465441SEvalZero }
518*10465441SEvalZero
519*10465441SEvalZero dirtyBuf->next_dirty = dirtyBuf->prev_dirty = NULL; // clear dirty link
520*10465441SEvalZero
521*10465441SEvalZero dev->buf.dirtyGroup[slot].count--;
522*10465441SEvalZero
523*10465441SEvalZero return U_SUCC;
524*10465441SEvalZero }
525*10465441SEvalZero
_GetDirOrFileNameSum(uffs_Device * dev,uffs_Buf * buf)526*10465441SEvalZero static u16 _GetDirOrFileNameSum(uffs_Device *dev, uffs_Buf *buf)
527*10465441SEvalZero {
528*10465441SEvalZero u16 data_sum = 0; //default: 0
529*10465441SEvalZero uffs_FileInfo *fi;
530*10465441SEvalZero
531*10465441SEvalZero dev = dev;
532*10465441SEvalZero //FIXME: We use the same schema for both dir and file.
533*10465441SEvalZero if (buf->type == UFFS_TYPE_FILE || buf->type == UFFS_TYPE_DIR) {
534*10465441SEvalZero if (buf->page_id == 0) {
535*10465441SEvalZero fi = (uffs_FileInfo *)(buf->data);
536*10465441SEvalZero data_sum = uffs_MakeSum16(fi->name, fi->name_len);
537*10465441SEvalZero }
538*10465441SEvalZero }
539*10465441SEvalZero
540*10465441SEvalZero return data_sum;
541*10465441SEvalZero }
542*10465441SEvalZero
543*10465441SEvalZero
_CheckDirtyList(uffs_Buf * dirty)544*10465441SEvalZero static URET _CheckDirtyList(uffs_Buf *dirty)
545*10465441SEvalZero {
546*10465441SEvalZero u16 parent;
547*10465441SEvalZero u16 serial;
548*10465441SEvalZero
549*10465441SEvalZero if (dirty == NULL) {
550*10465441SEvalZero return U_SUCC;
551*10465441SEvalZero }
552*10465441SEvalZero
553*10465441SEvalZero parent = dirty->parent;
554*10465441SEvalZero serial = dirty->serial;
555*10465441SEvalZero dirty = dirty->next_dirty;
556*10465441SEvalZero
557*10465441SEvalZero while (dirty) {
558*10465441SEvalZero if (parent != dirty->parent ||
559*10465441SEvalZero serial != dirty->serial) {
560*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS,
561*10465441SEvalZero "parent or serial in dirty pages buffer are not the same ?");
562*10465441SEvalZero return U_FAIL;
563*10465441SEvalZero }
564*10465441SEvalZero if (dirty->mark != UFFS_BUF_DIRTY) {
565*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS,
566*10465441SEvalZero "non-dirty page buffer in dirty buffer list ?");
567*10465441SEvalZero return U_FAIL;
568*10465441SEvalZero }
569*10465441SEvalZero dirty = dirty->next_dirty;
570*10465441SEvalZero }
571*10465441SEvalZero return U_SUCC;
572*10465441SEvalZero }
573*10465441SEvalZero
574*10465441SEvalZero /** find a page in dirty list, which has minimum page_id */
_FindMinimunPageIdFromDirtyList(uffs_Buf * dirtyList)575*10465441SEvalZero uffs_Buf * _FindMinimunPageIdFromDirtyList(uffs_Buf *dirtyList)
576*10465441SEvalZero {
577*10465441SEvalZero uffs_Buf * work = dirtyList;
578*10465441SEvalZero uffs_Buf * buf = dirtyList;
579*10465441SEvalZero
580*10465441SEvalZero if (buf) {
581*10465441SEvalZero work = work->next_dirty;
582*10465441SEvalZero while (work) {
583*10465441SEvalZero if (work->page_id < buf->page_id)
584*10465441SEvalZero buf = work;
585*10465441SEvalZero work = work->next_dirty;
586*10465441SEvalZero }
587*10465441SEvalZero
588*10465441SEvalZero uffs_Assert(buf->mark == UFFS_BUF_DIRTY,
589*10465441SEvalZero "buf (serial = %d, parent = %d, page_id = %d, type = %d) in dirty list but mark is 0x%x ?",
590*10465441SEvalZero buf->serial, buf->parent, buf->page_id, buf->type, buf->mark);
591*10465441SEvalZero }
592*10465441SEvalZero
593*10465441SEvalZero return buf;
594*10465441SEvalZero }
595*10465441SEvalZero
596*10465441SEvalZero
597*10465441SEvalZero /**
598*10465441SEvalZero * \brief flush buffer with block recover
599*10465441SEvalZero *
600*10465441SEvalZero * Scenario:
601*10465441SEvalZero * 1. get a free (erased) block --> newNode <br>
602*10465441SEvalZero * 2. copy from old block ---> oldNode, or copy from dirty list, <br>
603*10465441SEvalZero * sorted by page_id, to new block. Skips the invalid pages when copy pages.<br>
604*10465441SEvalZero * 3. erased old block. set new info to oldNode, set newNode->block = old block,<br>
605*10465441SEvalZero * and put newNode to erased list.<br>
606*10465441SEvalZero * \note IT'S IMPORTANT TO KEEP OLD NODE IN THE LIST,
607*10465441SEvalZero * so you don't need to update the obj->node :-)
608*10465441SEvalZero */
uffs_BufFlush_Exist_With_BlockCover(uffs_Device * dev,int slot,TreeNode * node,uffs_BlockInfo * bc)609*10465441SEvalZero static URET uffs_BufFlush_Exist_With_BlockCover(
610*10465441SEvalZero uffs_Device *dev,
611*10465441SEvalZero int slot, //!< dirty group slot
612*10465441SEvalZero TreeNode *node, //!< old data node on tree
613*10465441SEvalZero uffs_BlockInfo *bc //!< old data block info
614*10465441SEvalZero )
615*10465441SEvalZero {
616*10465441SEvalZero u16 i;
617*10465441SEvalZero u8 type, timeStamp;
618*10465441SEvalZero u16 page, parent, serial;
619*10465441SEvalZero uffs_Buf *buf;
620*10465441SEvalZero TreeNode *newNode;
621*10465441SEvalZero uffs_BlockInfo *newBc;
622*10465441SEvalZero uffs_Tags *tag, *oldTag;
623*10465441SEvalZero int x;
624*10465441SEvalZero u16 newBlock;
625*10465441SEvalZero UBOOL succRecover; //U_TRUE: recover successful, erase old block,
626*10465441SEvalZero //U_FALSE: fail to recover, erase new block
627*10465441SEvalZero UBOOL flash_op_err;
628*10465441SEvalZero u16 data_sum = 0xFFFF;
629*10465441SEvalZero
630*10465441SEvalZero UBOOL useCloneBuf;
631*10465441SEvalZero
632*10465441SEvalZero type = dev->buf.dirtyGroup[slot].dirty->type;
633*10465441SEvalZero parent = dev->buf.dirtyGroup[slot].dirty->parent;
634*10465441SEvalZero serial = dev->buf.dirtyGroup[slot].dirty->serial;
635*10465441SEvalZero
636*10465441SEvalZero retry:
637*10465441SEvalZero uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
638*10465441SEvalZero
639*10465441SEvalZero flash_op_err = UFFS_FLASH_NO_ERR;
640*10465441SEvalZero succRecover = U_FALSE;
641*10465441SEvalZero
642*10465441SEvalZero newNode = uffs_TreeGetErasedNode(dev);
643*10465441SEvalZero if (newNode == NULL) {
644*10465441SEvalZero uffs_Perror(UFFS_MSG_NOISY, "no enough erased block!");
645*10465441SEvalZero goto ext;
646*10465441SEvalZero }
647*10465441SEvalZero newBlock = newNode->u.list.block;
648*10465441SEvalZero newBc = uffs_BlockInfoGet(dev, newBlock);
649*10465441SEvalZero if (newBc == NULL) {
650*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "get block info fail!");
651*10465441SEvalZero uffs_InsertToErasedListHead(dev, newNode); //put node back to erased list
652*10465441SEvalZero //because it doesn't use, so put to head
653*10465441SEvalZero goto ext;
654*10465441SEvalZero }
655*10465441SEvalZero
656*10465441SEvalZero //uffs_Perror(UFFS_MSG_NOISY, "flush buffer with block cover to %d", newBlock);
657*10465441SEvalZero
658*10465441SEvalZero #if 0
659*10465441SEvalZero // this assert seems not necessary ...
660*10465441SEvalZero if (!uffs_Assert(newBc->expired_count == dev->attr->pages_per_block,
661*10465441SEvalZero "We have block cache for erased block ? expired_count = %d, block = %d\n",
662*10465441SEvalZero newBc->expired_count, newBc->block)) {
663*10465441SEvalZero uffs_BlockInfoExpire(dev, newBc, UFFS_ALL_PAGES);
664*10465441SEvalZero }
665*10465441SEvalZero #endif
666*10465441SEvalZero
667*10465441SEvalZero uffs_BlockInfoLoad(dev, newBc, UFFS_ALL_PAGES);
668*10465441SEvalZero timeStamp = uffs_GetNextBlockTimeStamp(uffs_GetBlockTimeStamp(dev, bc));
669*10465441SEvalZero
670*10465441SEvalZero // uffs_Perror(UFFS_MSG_NOISY, "Flush buffers with Block Recover, from %d to %d",
671*10465441SEvalZero // bc->block, newBc->block);
672*10465441SEvalZero
673*10465441SEvalZero for (i = 0; i < dev->attr->pages_per_block; i++) {
674*10465441SEvalZero tag = GET_TAG(newBc, i);
675*10465441SEvalZero TAG_DIRTY_BIT(tag) = TAG_DIRTY;
676*10465441SEvalZero TAG_VALID_BIT(tag) = TAG_VALID;
677*10465441SEvalZero TAG_BLOCK_TS(tag) = timeStamp;
678*10465441SEvalZero TAG_PARENT(tag) = parent;
679*10465441SEvalZero TAG_SERIAL(tag) = serial;
680*10465441SEvalZero TAG_TYPE(tag) = type;
681*10465441SEvalZero TAG_PAGE_ID(tag) = (u8)(i & 0xFF); // now, page_id = page.
682*10465441SEvalZero // FIX ME!! if more than 256 pages in a block
683*10465441SEvalZero
684*10465441SEvalZero SEAL_TAG(tag);
685*10465441SEvalZero
686*10465441SEvalZero buf = _FindBufInDirtyList(dev->buf.dirtyGroup[slot].dirty, i);
687*10465441SEvalZero if (buf != NULL) {
688*10465441SEvalZero if (i == 0)
689*10465441SEvalZero data_sum = _GetDirOrFileNameSum(dev, buf);
690*10465441SEvalZero
691*10465441SEvalZero TAG_DATA_LEN(tag) = buf->data_len;
692*10465441SEvalZero
693*10465441SEvalZero if (buf->data_len == 0 || (buf->ext_mark & UFFS_BUF_EXT_MARK_TRUNC_TAIL)) { // this only happen when truncating a file
694*10465441SEvalZero
695*10465441SEvalZero // when truncating a file, the last dirty buf will be
696*10465441SEvalZero // set as UFFS_BUF_EXT_MARK_TAIL. so that we don't do page recovery
697*10465441SEvalZero // for the rest pages in the block. (file is ended at this page)
698*10465441SEvalZero
699*10465441SEvalZero if (!uffs_Assert((buf->ext_mark & UFFS_BUF_EXT_MARK_TRUNC_TAIL) != 0,
700*10465441SEvalZero "buf->data == 0 but not the last page of truncating ? block = %d, page_id = %d",
701*10465441SEvalZero bc->block, i)) {
702*10465441SEvalZero
703*10465441SEvalZero // We can't do more about it for now ...
704*10465441SEvalZero }
705*10465441SEvalZero
706*10465441SEvalZero if (buf->data_len > 0) {
707*10465441SEvalZero flash_op_err = uffs_FlashWritePageCombine(dev, newBlock, i, buf, tag);
708*10465441SEvalZero }
709*10465441SEvalZero else {
710*10465441SEvalZero // data_len == 0, no I/O needed.
711*10465441SEvalZero flash_op_err = UFFS_FLASH_NO_ERR;
712*10465441SEvalZero }
713*10465441SEvalZero succRecover = U_TRUE;
714*10465441SEvalZero break;
715*10465441SEvalZero }
716*10465441SEvalZero else
717*10465441SEvalZero flash_op_err = uffs_FlashWritePageCombine(dev, newBlock, i, buf, tag);
718*10465441SEvalZero
719*10465441SEvalZero if (flash_op_err != UFFS_FLASH_NO_ERR) {
720*10465441SEvalZero if (flash_op_err == UFFS_FLASH_BAD_BLK) {
721*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL,
722*10465441SEvalZero "new bad block %d discovered.", newBlock);
723*10465441SEvalZero break;
724*10465441SEvalZero }
725*10465441SEvalZero else if (flash_op_err == UFFS_FLASH_IO_ERR) {
726*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL,
727*10465441SEvalZero "writing to block %d page %d, I/O error ?",
728*10465441SEvalZero (int)newBlock, (int)i);
729*10465441SEvalZero break;
730*10465441SEvalZero }
731*10465441SEvalZero else {
732*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "Unhandled flash op result: %d", flash_op_err);
733*10465441SEvalZero break;
734*10465441SEvalZero }
735*10465441SEvalZero }
736*10465441SEvalZero }
737*10465441SEvalZero else {
738*10465441SEvalZero page = uffs_FindPageInBlockWithPageId(dev, bc, i);
739*10465441SEvalZero if (page == UFFS_INVALID_PAGE) {
740*10465441SEvalZero succRecover = U_TRUE;
741*10465441SEvalZero break; //end of last page, normal break
742*10465441SEvalZero }
743*10465441SEvalZero page = uffs_FindBestPageInBlock(dev, bc, page);
744*10465441SEvalZero
745*10465441SEvalZero if (!uffs_Assert(page != UFFS_INVALID_PAGE, "got an invalid page ?\n"))
746*10465441SEvalZero break;
747*10465441SEvalZero
748*10465441SEvalZero oldTag = GET_TAG(bc, page);
749*10465441SEvalZero
750*10465441SEvalZero // First, try to find existing cached buffer.
751*10465441SEvalZero // Note: do not call uffs_BufGetEx() as it may trigger buf flush and result in infinite loop
752*10465441SEvalZero buf = uffs_BufGet(dev, parent, serial, i);
753*10465441SEvalZero
754*10465441SEvalZero if (buf == NULL) { // no cached page buffer, use clone buffer.
755*10465441SEvalZero useCloneBuf = U_TRUE;
756*10465441SEvalZero buf = uffs_BufClone(dev, NULL);
757*10465441SEvalZero if (buf == NULL) {
758*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "Can't clone a new buf!");
759*10465441SEvalZero break;
760*10465441SEvalZero }
761*10465441SEvalZero x = uffs_BufLoadPhyData(dev, buf, bc->block, page);
762*10465441SEvalZero if (x == U_FAIL) {
763*10465441SEvalZero if (HAVE_BADBLOCK(dev) && dev->bad.block == bc->block) {
764*10465441SEvalZero // the old block is a bad block, we'll process it later.
765*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS,
766*10465441SEvalZero "the old block %d is a bad block, \
767*10465441SEvalZero but ignore it for now.",
768*10465441SEvalZero bc->block);
769*10465441SEvalZero }
770*10465441SEvalZero else {
771*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "I/O error ?");
772*10465441SEvalZero uffs_BufFreeClone(dev, buf);
773*10465441SEvalZero flash_op_err = UFFS_FLASH_IO_ERR;
774*10465441SEvalZero break;
775*10465441SEvalZero }
776*10465441SEvalZero }
777*10465441SEvalZero
778*10465441SEvalZero buf->type = type;
779*10465441SEvalZero buf->parent = parent;
780*10465441SEvalZero buf->serial = serial;
781*10465441SEvalZero buf->page_id = TAG_PAGE_ID(oldTag);
782*10465441SEvalZero buf->data_len = TAG_DATA_LEN(oldTag);
783*10465441SEvalZero
784*10465441SEvalZero }
785*10465441SEvalZero else {
786*10465441SEvalZero useCloneBuf = U_FALSE;
787*10465441SEvalZero
788*10465441SEvalZero uffs_Assert(buf->page_id == TAG_PAGE_ID(oldTag), "buf->page_id = %d, tag page id: %d", buf->page_id, TAG_PAGE_ID(oldTag));
789*10465441SEvalZero uffs_Assert(buf->data_len == TAG_DATA_LEN(oldTag), "buf->data_len = %d, tag data len: %d", buf->data_len, TAG_DATA_LEN(oldTag));
790*10465441SEvalZero }
791*10465441SEvalZero
792*10465441SEvalZero if (buf->data_len > dev->com.pg_data_size) {
793*10465441SEvalZero uffs_Perror(UFFS_MSG_NOISY, "data length over flow, truncated !");
794*10465441SEvalZero buf->data_len = dev->com.pg_data_size;
795*10465441SEvalZero }
796*10465441SEvalZero
797*10465441SEvalZero if (!uffs_Assert(buf->data_len != 0, "data_len == 0 ? block %d, page %d, serial %d, parent %d",
798*10465441SEvalZero bc->block, page, buf->serial, buf->parent)) {
799*10465441SEvalZero // this could be some error on flash ? we can't do more about it for now ...
800*10465441SEvalZero }
801*10465441SEvalZero
802*10465441SEvalZero TAG_DATA_LEN(tag) = buf->data_len;
803*10465441SEvalZero
804*10465441SEvalZero if (i == 0)
805*10465441SEvalZero data_sum = _GetDirOrFileNameSum(dev, buf);
806*10465441SEvalZero
807*10465441SEvalZero flash_op_err = uffs_FlashWritePageCombine(dev, newBlock, i, buf, tag);
808*10465441SEvalZero
809*10465441SEvalZero if (buf) {
810*10465441SEvalZero if (useCloneBuf)
811*10465441SEvalZero uffs_BufFreeClone(dev, buf);
812*10465441SEvalZero else
813*10465441SEvalZero uffs_BufPut(dev, buf);
814*10465441SEvalZero }
815*10465441SEvalZero
816*10465441SEvalZero if (flash_op_err == UFFS_FLASH_BAD_BLK) {
817*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL,
818*10465441SEvalZero "new bad block %d discovered.", newBlock);
819*10465441SEvalZero break;
820*10465441SEvalZero }
821*10465441SEvalZero else if (flash_op_err == UFFS_FLASH_IO_ERR) {
822*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL, "I/O error ?", newBlock);
823*10465441SEvalZero break;
824*10465441SEvalZero }
825*10465441SEvalZero }
826*10465441SEvalZero } //end of for
827*10465441SEvalZero
828*10465441SEvalZero if (i == dev->attr->pages_per_block)
829*10465441SEvalZero succRecover = U_TRUE;
830*10465441SEvalZero else {
831*10465441SEvalZero // expire last page info cache in case the 'tag' is not written.
832*10465441SEvalZero uffs_BlockInfoExpire(dev, newBc, i);
833*10465441SEvalZero }
834*10465441SEvalZero
835*10465441SEvalZero if (flash_op_err == UFFS_FLASH_BAD_BLK) {
836*10465441SEvalZero uffs_BlockInfoExpire(dev, newBc, UFFS_ALL_PAGES);
837*10465441SEvalZero uffs_BlockInfoPut(dev, newBc);
838*10465441SEvalZero if (newNode->u.list.block == dev->bad.block) {
839*10465441SEvalZero // the recovered block is a BAD block (buy me a lotto, please :-), we need to
840*10465441SEvalZero // deal with it immediately (mark it as 'bad' and put into bad block list).
841*10465441SEvalZero uffs_BadBlockProcess(dev, newNode);
842*10465441SEvalZero }
843*10465441SEvalZero
844*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL, "Retry block cover ...");
845*10465441SEvalZero
846*10465441SEvalZero goto retry; // retry on a new erased block ...
847*10465441SEvalZero }
848*10465441SEvalZero
849*10465441SEvalZero if (succRecover == U_TRUE) {
850*10465441SEvalZero // now it's time to clean the dirty buffers
851*10465441SEvalZero for (i = 0; i < dev->attr->pages_per_block; i++) {
852*10465441SEvalZero buf = _FindBufInDirtyList(dev->buf.dirtyGroup[slot].dirty, i);
853*10465441SEvalZero if (buf) {
854*10465441SEvalZero if (_BreakFromDirty(dev, buf) == U_SUCC) {
855*10465441SEvalZero buf->mark = UFFS_BUF_VALID;
856*10465441SEvalZero buf->ext_mark &= ~UFFS_BUF_EXT_MARK_TRUNC_TAIL;
857*10465441SEvalZero _MoveNodeToHead(dev, buf);
858*10465441SEvalZero }
859*10465441SEvalZero }
860*10465441SEvalZero }
861*10465441SEvalZero
862*10465441SEvalZero // swap the old block node and new block node.
863*10465441SEvalZero // it's important that we 'swap' the block and keep the node unchanged
864*10465441SEvalZero // so that allowing someone hold the node pointer unawared.
865*10465441SEvalZero switch (type) {
866*10465441SEvalZero case UFFS_TYPE_DIR:
867*10465441SEvalZero node->u.dir.parent = parent;
868*10465441SEvalZero node->u.dir.serial = serial;
869*10465441SEvalZero node->u.dir.block = newBlock;
870*10465441SEvalZero node->u.dir.checksum = data_sum;
871*10465441SEvalZero break;
872*10465441SEvalZero case UFFS_TYPE_FILE:
873*10465441SEvalZero node->u.file.parent = parent;
874*10465441SEvalZero node->u.file.serial = serial;
875*10465441SEvalZero node->u.file.block = newBlock;
876*10465441SEvalZero node->u.file.checksum = data_sum;
877*10465441SEvalZero break;
878*10465441SEvalZero case UFFS_TYPE_DATA:
879*10465441SEvalZero node->u.data.parent = parent;
880*10465441SEvalZero node->u.data.serial = serial;
881*10465441SEvalZero node->u.data.block = newBlock;
882*10465441SEvalZero break;
883*10465441SEvalZero default:
884*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "UNKNOW TYPE");
885*10465441SEvalZero break;
886*10465441SEvalZero }
887*10465441SEvalZero
888*10465441SEvalZero newNode->u.list.block = bc->block;
889*10465441SEvalZero
890*10465441SEvalZero // if the recovered block is a bad block, it's time to process it.
891*10465441SEvalZero if (HAVE_BADBLOCK(dev) && dev->bad.block == newNode->u.list.block) {
892*10465441SEvalZero //uffs_Perror(UFFS_MSG_SERIOUS, "Still have bad block ?");
893*10465441SEvalZero uffs_BadBlockProcess(dev, newNode);
894*10465441SEvalZero }
895*10465441SEvalZero else {
896*10465441SEvalZero // erase recovered block, put it back to erased block list.
897*10465441SEvalZero if (uffs_IsThisBlockUsed(dev, bc)) {
898*10465441SEvalZero uffs_FlashEraseBlock(dev, bc->block);
899*10465441SEvalZero }
900*10465441SEvalZero if (HAVE_BADBLOCK(dev))
901*10465441SEvalZero uffs_BadBlockProcess(dev, newNode);
902*10465441SEvalZero else
903*10465441SEvalZero uffs_TreeInsertToErasedListTail(dev, newNode);
904*10465441SEvalZero }
905*10465441SEvalZero }
906*10465441SEvalZero else {
907*10465441SEvalZero
908*10465441SEvalZero uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES); // FIXME: this might not be necessary ...
909*10465441SEvalZero
910*10465441SEvalZero uffs_FlashEraseBlock(dev, newBlock);
911*10465441SEvalZero newNode->u.list.block = newBlock;
912*10465441SEvalZero if (HAVE_BADBLOCK(dev))
913*10465441SEvalZero uffs_BadBlockProcess(dev, newNode);
914*10465441SEvalZero else
915*10465441SEvalZero uffs_TreeInsertToErasedListTail(dev, newNode);
916*10465441SEvalZero }
917*10465441SEvalZero
918*10465441SEvalZero if (dev->buf.dirtyGroup[slot].dirty != NULL ||
919*10465441SEvalZero dev->buf.dirtyGroup[slot].count != 0) {
920*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL, "still have dirty buffer ?");
921*10465441SEvalZero }
922*10465441SEvalZero
923*10465441SEvalZero uffs_BlockInfoPut(dev, newBc);
924*10465441SEvalZero
925*10465441SEvalZero ext:
926*10465441SEvalZero return (succRecover == U_TRUE ? U_SUCC : U_FAIL);
927*10465441SEvalZero
928*10465441SEvalZero }
929*10465441SEvalZero
930*10465441SEvalZero
931*10465441SEvalZero
932*10465441SEvalZero /**
933*10465441SEvalZero * \brief flush buffer to a new block which is not registered in tree
934*10465441SEvalZero *
935*10465441SEvalZero * Scenario:
936*10465441SEvalZero * 1. get a new block
937*10465441SEvalZero * 2. write pages in dirty list to new block, sorted by page_id
938*10465441SEvalZero * 3. insert new block to tree
939*10465441SEvalZero */
_BufFlush_NewBlock(uffs_Device * dev,int slot)940*10465441SEvalZero static URET _BufFlush_NewBlock(uffs_Device *dev, int slot)
941*10465441SEvalZero {
942*10465441SEvalZero u8 type;
943*10465441SEvalZero TreeNode *node;
944*10465441SEvalZero uffs_BlockInfo *bc;
945*10465441SEvalZero URET ret;
946*10465441SEvalZero
947*10465441SEvalZero ret = U_FAIL;
948*10465441SEvalZero
949*10465441SEvalZero node = uffs_TreeGetErasedNode(dev);
950*10465441SEvalZero if (node == NULL) {
951*10465441SEvalZero uffs_Perror(UFFS_MSG_NOISY, "no erased block!");
952*10465441SEvalZero goto ext;
953*10465441SEvalZero }
954*10465441SEvalZero bc = uffs_BlockInfoGet(dev, node->u.list.block);
955*10465441SEvalZero if (bc == NULL) {
956*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "get block info fail!");
957*10465441SEvalZero uffs_InsertToErasedListHead(dev, node); //put node back to erased list
958*10465441SEvalZero goto ext;
959*10465441SEvalZero }
960*10465441SEvalZero
961*10465441SEvalZero type = dev->buf.dirtyGroup[slot].dirty->type;
962*10465441SEvalZero
963*10465441SEvalZero ret = uffs_BufFlush_Exist_With_BlockCover(dev, slot, node, bc);
964*10465441SEvalZero
965*10465441SEvalZero if (ret == U_SUCC)
966*10465441SEvalZero uffs_InsertNodeToTree(dev, type, node);
967*10465441SEvalZero else {
968*10465441SEvalZero uffs_FlashEraseBlock(dev, bc->block);
969*10465441SEvalZero uffs_TreeInsertToErasedListTail(dev, node);
970*10465441SEvalZero }
971*10465441SEvalZero
972*10465441SEvalZero uffs_BlockInfoPut(dev, bc);
973*10465441SEvalZero ext:
974*10465441SEvalZero return ret;
975*10465441SEvalZero }
976*10465441SEvalZero
977*10465441SEvalZero
978*10465441SEvalZero /**
979*10465441SEvalZero * \brief flush buffer to a block with enough free pages
980*10465441SEvalZero *
981*10465441SEvalZero * pages in dirty list must be sorted by page_id to write to flash
982*10465441SEvalZero */
983*10465441SEvalZero static
984*10465441SEvalZero URET
uffs_BufFlush_Exist_With_Enough_FreePage(uffs_Device * dev,int slot,TreeNode * node,uffs_BlockInfo * bc)985*10465441SEvalZero uffs_BufFlush_Exist_With_Enough_FreePage(
986*10465441SEvalZero uffs_Device *dev,
987*10465441SEvalZero int slot, //!< dirty group slot
988*10465441SEvalZero TreeNode *node, //!< tree node
989*10465441SEvalZero uffs_BlockInfo *bc //!< block info (Source, also destination)
990*10465441SEvalZero )
991*10465441SEvalZero {
992*10465441SEvalZero u16 page;
993*10465441SEvalZero uffs_Buf *buf;
994*10465441SEvalZero uffs_Tags *tag;
995*10465441SEvalZero URET ret = U_FAIL;
996*10465441SEvalZero int x;
997*10465441SEvalZero
998*10465441SEvalZero // uffs_Perror(UFFS_MSG_NOISY,
999*10465441SEvalZero // "Flush buffers with Enough Free Page to block %d",
1000*10465441SEvalZero // bc->block);
1001*10465441SEvalZero
1002*10465441SEvalZero for (page = 1; // page 0 won't be a free page, so we start from 1.
1003*10465441SEvalZero page < dev->attr->pages_per_block &&
1004*10465441SEvalZero dev->buf.dirtyGroup[slot].count > 0; //still has dirty pages?
1005*10465441SEvalZero page++) {
1006*10465441SEvalZero
1007*10465441SEvalZero // locate to the free page (make sure the page is a erased page, so an unclean page won't sneak in)
1008*10465441SEvalZero for (; page < dev->attr->pages_per_block; page++) {
1009*10465441SEvalZero if (uffs_IsPageErased(dev, bc, page))
1010*10465441SEvalZero break;
1011*10465441SEvalZero }
1012*10465441SEvalZero
1013*10465441SEvalZero if (!uffs_Assert(page < dev->attr->pages_per_block, "no free page? buf flush not finished."))
1014*10465441SEvalZero break;
1015*10465441SEvalZero
1016*10465441SEvalZero buf = _FindMinimunPageIdFromDirtyList(dev->buf.dirtyGroup[slot].dirty);
1017*10465441SEvalZero if (buf == NULL) {
1018*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS,
1019*10465441SEvalZero "count > 0, but no dirty pages in list ?");
1020*10465441SEvalZero goto ext;
1021*10465441SEvalZero }
1022*10465441SEvalZero
1023*10465441SEvalZero //write the dirty page (id: buf->page_id) to page (free page)
1024*10465441SEvalZero tag = GET_TAG(bc, page);
1025*10465441SEvalZero TAG_DIRTY_BIT(tag) = TAG_DIRTY;
1026*10465441SEvalZero TAG_VALID_BIT(tag) = TAG_VALID;
1027*10465441SEvalZero TAG_BLOCK_TS(tag) = uffs_GetBlockTimeStamp(dev, bc);
1028*10465441SEvalZero TAG_DATA_LEN(tag) = buf->data_len;
1029*10465441SEvalZero TAG_TYPE(tag) = buf->type;
1030*10465441SEvalZero TAG_PARENT(tag) = buf->parent;
1031*10465441SEvalZero TAG_SERIAL(tag) = buf->serial;
1032*10465441SEvalZero TAG_PAGE_ID(tag) = (u8)(buf->page_id);
1033*10465441SEvalZero
1034*10465441SEvalZero SEAL_TAG(tag);
1035*10465441SEvalZero
1036*10465441SEvalZero x = uffs_FlashWritePageCombine(dev, bc->block, page, buf, tag);
1037*10465441SEvalZero if (x == UFFS_FLASH_IO_ERR) {
1038*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL, "I/O error <1>?");
1039*10465441SEvalZero goto ext;
1040*10465441SEvalZero }
1041*10465441SEvalZero else if (x == UFFS_FLASH_BAD_BLK) {
1042*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL, "Bad blcok found, start block cover ...");
1043*10465441SEvalZero ret = uffs_BufFlush_Exist_With_BlockCover(dev, slot, node, bc);
1044*10465441SEvalZero goto ext;
1045*10465441SEvalZero }
1046*10465441SEvalZero else {
1047*10465441SEvalZero if(_BreakFromDirty(dev, buf) == U_SUCC) {
1048*10465441SEvalZero buf->mark = UFFS_BUF_VALID;
1049*10465441SEvalZero _MoveNodeToHead(dev, buf);
1050*10465441SEvalZero }
1051*10465441SEvalZero }
1052*10465441SEvalZero } //end of for
1053*10465441SEvalZero
1054*10465441SEvalZero if (dev->buf.dirtyGroup[slot].dirty != NULL ||
1055*10465441SEvalZero dev->buf.dirtyGroup[slot].count != 0) {
1056*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL, "still has dirty buffer ?");
1057*10465441SEvalZero }
1058*10465441SEvalZero else {
1059*10465441SEvalZero ret = U_SUCC;
1060*10465441SEvalZero }
1061*10465441SEvalZero
1062*10465441SEvalZero ext:
1063*10465441SEvalZero return ret;
1064*10465441SEvalZero }
1065*10465441SEvalZero
1066*10465441SEvalZero
_BufFlush(struct uffs_DeviceSt * dev,UBOOL force_block_recover,int slot)1067*10465441SEvalZero URET _BufFlush(struct uffs_DeviceSt *dev,
1068*10465441SEvalZero UBOOL force_block_recover, int slot)
1069*10465441SEvalZero {
1070*10465441SEvalZero uffs_Buf *dirty;
1071*10465441SEvalZero TreeNode *node;
1072*10465441SEvalZero uffs_BlockInfo *bc;
1073*10465441SEvalZero u16 n;
1074*10465441SEvalZero URET ret;
1075*10465441SEvalZero u8 type;
1076*10465441SEvalZero u16 parent;
1077*10465441SEvalZero u16 serial;
1078*10465441SEvalZero int block;
1079*10465441SEvalZero
1080*10465441SEvalZero if (dev->buf.dirtyGroup[slot].count == 0) {
1081*10465441SEvalZero return U_SUCC;
1082*10465441SEvalZero }
1083*10465441SEvalZero
1084*10465441SEvalZero dirty = dev->buf.dirtyGroup[slot].dirty;
1085*10465441SEvalZero
1086*10465441SEvalZero if (_CheckDirtyList(dirty) == U_FAIL)
1087*10465441SEvalZero return U_FAIL;
1088*10465441SEvalZero
1089*10465441SEvalZero type = dirty->type;
1090*10465441SEvalZero parent = dirty->parent;
1091*10465441SEvalZero serial = dirty->serial;
1092*10465441SEvalZero
1093*10465441SEvalZero switch (type) {
1094*10465441SEvalZero case UFFS_TYPE_DIR:
1095*10465441SEvalZero node = uffs_TreeFindDirNode(dev, serial);
1096*10465441SEvalZero break;
1097*10465441SEvalZero case UFFS_TYPE_FILE:
1098*10465441SEvalZero node = uffs_TreeFindFileNode(dev, serial);
1099*10465441SEvalZero break;
1100*10465441SEvalZero case UFFS_TYPE_DATA:
1101*10465441SEvalZero node = uffs_TreeFindDataNode(dev, parent, serial);
1102*10465441SEvalZero break;
1103*10465441SEvalZero default:
1104*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "unknown type");
1105*10465441SEvalZero return U_FAIL;
1106*10465441SEvalZero }
1107*10465441SEvalZero
1108*10465441SEvalZero if (node == NULL) {
1109*10465441SEvalZero //not found in the tree, need to generate a new block
1110*10465441SEvalZero ret = _BufFlush_NewBlock(dev, slot);
1111*10465441SEvalZero }
1112*10465441SEvalZero else {
1113*10465441SEvalZero switch (type) {
1114*10465441SEvalZero case UFFS_TYPE_DIR:
1115*10465441SEvalZero block = node->u.dir.block;
1116*10465441SEvalZero break;
1117*10465441SEvalZero case UFFS_TYPE_FILE:
1118*10465441SEvalZero block = node->u.file.block;
1119*10465441SEvalZero break;
1120*10465441SEvalZero case UFFS_TYPE_DATA:
1121*10465441SEvalZero block = node->u.data.block;
1122*10465441SEvalZero break;
1123*10465441SEvalZero default:
1124*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "unknown type.");
1125*10465441SEvalZero return U_FAIL;
1126*10465441SEvalZero }
1127*10465441SEvalZero bc = uffs_BlockInfoGet(dev, block);
1128*10465441SEvalZero if(bc == NULL) {
1129*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "get block info fail.");
1130*10465441SEvalZero return U_FAIL;
1131*10465441SEvalZero }
1132*10465441SEvalZero
1133*10465441SEvalZero ret = uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
1134*10465441SEvalZero if (ret == U_SUCC) {
1135*10465441SEvalZero
1136*10465441SEvalZero n = uffs_GetFreePagesCount(dev, bc);
1137*10465441SEvalZero
1138*10465441SEvalZero if (n >= dev->buf.dirtyGroup[slot].count && !force_block_recover) {
1139*10465441SEvalZero //The free pages are enough for the dirty pages
1140*10465441SEvalZero ret = uffs_BufFlush_Exist_With_Enough_FreePage(dev, slot, node, bc);
1141*10465441SEvalZero }
1142*10465441SEvalZero else {
1143*10465441SEvalZero ret = uffs_BufFlush_Exist_With_BlockCover(dev, slot, node, bc);
1144*10465441SEvalZero }
1145*10465441SEvalZero }
1146*10465441SEvalZero uffs_BlockInfoPut(dev, bc);
1147*10465441SEvalZero }
1148*10465441SEvalZero
1149*10465441SEvalZero return ret;
1150*10465441SEvalZero }
1151*10465441SEvalZero
_FindMostDirtyGroup(struct uffs_DeviceSt * dev)1152*10465441SEvalZero static int _FindMostDirtyGroup(struct uffs_DeviceSt *dev)
1153*10465441SEvalZero {
1154*10465441SEvalZero int i, slot = -1;
1155*10465441SEvalZero int max_count = 0;
1156*10465441SEvalZero
1157*10465441SEvalZero for (i = 0; i < dev->cfg.dirty_groups; i++) {
1158*10465441SEvalZero if (dev->buf.dirtyGroup[i].dirty &&
1159*10465441SEvalZero dev->buf.dirtyGroup[i].lock == 0) {
1160*10465441SEvalZero if (dev->buf.dirtyGroup[i].count > max_count) {
1161*10465441SEvalZero max_count = dev->buf.dirtyGroup[i].count;
1162*10465441SEvalZero slot = i;
1163*10465441SEvalZero }
1164*10465441SEvalZero }
1165*10465441SEvalZero }
1166*10465441SEvalZero
1167*10465441SEvalZero return slot;
1168*10465441SEvalZero }
1169*10465441SEvalZero
1170*10465441SEvalZero /** lock dirty group */
uffs_BufLockGroup(struct uffs_DeviceSt * dev,int slot)1171*10465441SEvalZero URET uffs_BufLockGroup(struct uffs_DeviceSt *dev, int slot)
1172*10465441SEvalZero {
1173*10465441SEvalZero URET ret = U_FAIL;
1174*10465441SEvalZero if (slot >= 0 && slot < dev->cfg.dirty_groups) {
1175*10465441SEvalZero dev->buf.dirtyGroup[slot].lock++;
1176*10465441SEvalZero ret = U_SUCC;
1177*10465441SEvalZero }
1178*10465441SEvalZero return ret;
1179*10465441SEvalZero }
1180*10465441SEvalZero
1181*10465441SEvalZero /** unlock dirty group */
uffs_BufUnLockGroup(struct uffs_DeviceSt * dev,int slot)1182*10465441SEvalZero URET uffs_BufUnLockGroup(struct uffs_DeviceSt *dev, int slot)
1183*10465441SEvalZero {
1184*10465441SEvalZero URET ret = U_FAIL;
1185*10465441SEvalZero
1186*10465441SEvalZero if (slot >= 0 && slot < dev->cfg.dirty_groups) {
1187*10465441SEvalZero if (dev->buf.dirtyGroup[slot].lock > 0)
1188*10465441SEvalZero dev->buf.dirtyGroup[slot].lock--;
1189*10465441SEvalZero else {
1190*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "Try to unlock an unlocked group ?");
1191*10465441SEvalZero }
1192*10465441SEvalZero ret = U_SUCC;
1193*10465441SEvalZero }
1194*10465441SEvalZero return ret;
1195*10465441SEvalZero }
1196*10465441SEvalZero
1197*10465441SEvalZero
1198*10465441SEvalZero /**
1199*10465441SEvalZero * flush buffers to flash.
1200*10465441SEvalZero * this will flush all dirty groups.
1201*10465441SEvalZero * \param[in] dev uffs device
1202*10465441SEvalZero */
uffs_BufFlush(struct uffs_DeviceSt * dev)1203*10465441SEvalZero URET uffs_BufFlush(struct uffs_DeviceSt *dev)
1204*10465441SEvalZero {
1205*10465441SEvalZero int slot;
1206*10465441SEvalZero
1207*10465441SEvalZero slot = uffs_BufFindFreeGroupSlot(dev);
1208*10465441SEvalZero if (slot >= 0)
1209*10465441SEvalZero return U_SUCC; // do nothing if there is free slot
1210*10465441SEvalZero else
1211*10465441SEvalZero return uffs_BufFlushMostDirtyGroup(dev);
1212*10465441SEvalZero }
1213*10465441SEvalZero
1214*10465441SEvalZero /**
1215*10465441SEvalZero * flush most dirty group
1216*10465441SEvalZero * \param[in] dev uffs device
1217*10465441SEvalZero */
uffs_BufFlushMostDirtyGroup(struct uffs_DeviceSt * dev)1218*10465441SEvalZero URET uffs_BufFlushMostDirtyGroup(struct uffs_DeviceSt *dev)
1219*10465441SEvalZero {
1220*10465441SEvalZero int slot;
1221*10465441SEvalZero
1222*10465441SEvalZero slot = _FindMostDirtyGroup(dev);
1223*10465441SEvalZero if (slot >= 0) {
1224*10465441SEvalZero return _BufFlush(dev, U_FALSE, slot);
1225*10465441SEvalZero }
1226*10465441SEvalZero return U_SUCC;
1227*10465441SEvalZero }
1228*10465441SEvalZero
1229*10465441SEvalZero /**
1230*10465441SEvalZero * flush buffers to flash
1231*10465441SEvalZero * this will pick up a most dirty group,
1232*10465441SEvalZero * and flush it if there is no free dirty group slot.
1233*10465441SEvalZero *
1234*10465441SEvalZero * \param[in] dev uffs device
1235*10465441SEvalZero * \param[in] force_block_recover #U_TRUE: force a block recover
1236*10465441SEvalZero * even there are enough free pages
1237*10465441SEvalZero */
uffs_BufFlushEx(struct uffs_DeviceSt * dev,UBOOL force_block_recover)1238*10465441SEvalZero URET uffs_BufFlushEx(struct uffs_DeviceSt *dev, UBOOL force_block_recover)
1239*10465441SEvalZero {
1240*10465441SEvalZero int slot;
1241*10465441SEvalZero
1242*10465441SEvalZero slot = uffs_BufFindFreeGroupSlot(dev);
1243*10465441SEvalZero if (slot >= 0) {
1244*10465441SEvalZero return U_SUCC; //there is free slot, do nothing.
1245*10465441SEvalZero }
1246*10465441SEvalZero else {
1247*10465441SEvalZero slot = _FindMostDirtyGroup(dev);
1248*10465441SEvalZero return _BufFlush(dev, force_block_recover, slot);
1249*10465441SEvalZero }
1250*10465441SEvalZero }
1251*10465441SEvalZero
1252*10465441SEvalZero /**
1253*10465441SEvalZero * flush buffer group with given parent/serial num.
1254*10465441SEvalZero *
1255*10465441SEvalZero * \param[in] dev uffs device
1256*10465441SEvalZero * \param[in] parent parent num of the group
1257*10465441SEvalZero * \param[in] serial serial num of the group
1258*10465441SEvalZero */
uffs_BufFlushGroup(struct uffs_DeviceSt * dev,u16 parent,u16 serial)1259*10465441SEvalZero URET uffs_BufFlushGroup(struct uffs_DeviceSt *dev, u16 parent, u16 serial)
1260*10465441SEvalZero {
1261*10465441SEvalZero int slot;
1262*10465441SEvalZero
1263*10465441SEvalZero slot = uffs_BufFindGroupSlot(dev, parent, serial);
1264*10465441SEvalZero if (slot >= 0) {
1265*10465441SEvalZero return _BufFlush(dev, U_FALSE, slot);
1266*10465441SEvalZero }
1267*10465441SEvalZero
1268*10465441SEvalZero return U_SUCC;
1269*10465441SEvalZero }
1270*10465441SEvalZero
1271*10465441SEvalZero /**
1272*10465441SEvalZero * flush buffer group with given parent/serial num
1273*10465441SEvalZero * and force_block_recover indicator.
1274*10465441SEvalZero *
1275*10465441SEvalZero * \param[in] dev uffs device
1276*10465441SEvalZero * \param[in] parent parent num of the group
1277*10465441SEvalZero * \param[in] serial serial num of group
1278*10465441SEvalZero * \param[in] force_block_recover indicator
1279*10465441SEvalZero */
uffs_BufFlushGroupEx(struct uffs_DeviceSt * dev,u16 parent,u16 serial,UBOOL force_block_recover)1280*10465441SEvalZero URET uffs_BufFlushGroupEx(struct uffs_DeviceSt *dev,
1281*10465441SEvalZero u16 parent, u16 serial, UBOOL force_block_recover)
1282*10465441SEvalZero {
1283*10465441SEvalZero int slot;
1284*10465441SEvalZero
1285*10465441SEvalZero slot = uffs_BufFindGroupSlot(dev, parent, serial);
1286*10465441SEvalZero if (slot >= 0) {
1287*10465441SEvalZero return _BufFlush(dev, force_block_recover, slot);
1288*10465441SEvalZero }
1289*10465441SEvalZero
1290*10465441SEvalZero return U_SUCC;
1291*10465441SEvalZero }
1292*10465441SEvalZero
1293*10465441SEvalZero
1294*10465441SEvalZero /**
1295*10465441SEvalZero * flush buffer group/groups which match given parent num.
1296*10465441SEvalZero *
1297*10465441SEvalZero * \param[in] dev uffs device
1298*10465441SEvalZero * \param[in] parent parent num of the group
1299*10465441SEvalZero * \param[in] serial serial num of group
1300*10465441SEvalZero * \param[in] force_block_recover indicator
1301*10465441SEvalZero */
uffs_BufFlushGroupMatchParent(struct uffs_DeviceSt * dev,u16 parent)1302*10465441SEvalZero URET uffs_BufFlushGroupMatchParent(struct uffs_DeviceSt *dev, u16 parent)
1303*10465441SEvalZero {
1304*10465441SEvalZero int slot;
1305*10465441SEvalZero uffs_Buf *buf;
1306*10465441SEvalZero URET ret = U_SUCC;
1307*10465441SEvalZero
1308*10465441SEvalZero for (slot = 0; slot < dev->cfg.dirty_groups && ret == U_SUCC; slot++) {
1309*10465441SEvalZero if (dev->buf.dirtyGroup[slot].dirty) {
1310*10465441SEvalZero buf = dev->buf.dirtyGroup[slot].dirty;
1311*10465441SEvalZero if (buf->parent == parent) {
1312*10465441SEvalZero ret = _BufFlush(dev, U_FALSE, slot);
1313*10465441SEvalZero }
1314*10465441SEvalZero }
1315*10465441SEvalZero }
1316*10465441SEvalZero
1317*10465441SEvalZero return ret;
1318*10465441SEvalZero }
1319*10465441SEvalZero
1320*10465441SEvalZero /**
1321*10465441SEvalZero * find a free dirty group slot
1322*10465441SEvalZero *
1323*10465441SEvalZero * \param[in] dev uffs device
1324*10465441SEvalZero * \return slot index (0 to MAX_DIRTY_BUF_GROUPS - 1) if found one,
1325*10465441SEvalZero * otherwise return -1.
1326*10465441SEvalZero */
uffs_BufFindFreeGroupSlot(struct uffs_DeviceSt * dev)1327*10465441SEvalZero int uffs_BufFindFreeGroupSlot(struct uffs_DeviceSt *dev)
1328*10465441SEvalZero {
1329*10465441SEvalZero int i, slot = -1;
1330*10465441SEvalZero
1331*10465441SEvalZero for (i = 0; i < dev->cfg.dirty_groups; i++) {
1332*10465441SEvalZero if (dev->buf.dirtyGroup[i].dirty == NULL) {
1333*10465441SEvalZero slot = i;
1334*10465441SEvalZero break;
1335*10465441SEvalZero }
1336*10465441SEvalZero }
1337*10465441SEvalZero return slot;
1338*10465441SEvalZero }
1339*10465441SEvalZero
1340*10465441SEvalZero /**
1341*10465441SEvalZero * find a dirty group slot with given parent/serial num.
1342*10465441SEvalZero *
1343*10465441SEvalZero * \param[in] dev uffs device
1344*10465441SEvalZero * \param[in] parent parent num of the group
1345*10465441SEvalZero * \param[in] serial serial num of group
1346*10465441SEvalZero * \return slot index (0 to MAX_DIRTY_BUF_GROUPS - 1) if found one,
1347*10465441SEvalZero * otherwise return -1.
1348*10465441SEvalZero */
uffs_BufFindGroupSlot(struct uffs_DeviceSt * dev,u16 parent,u16 serial)1349*10465441SEvalZero int uffs_BufFindGroupSlot(struct uffs_DeviceSt *dev, u16 parent, u16 serial)
1350*10465441SEvalZero {
1351*10465441SEvalZero uffs_Buf *buf;
1352*10465441SEvalZero int i, slot = -1;
1353*10465441SEvalZero
1354*10465441SEvalZero for (i = 0; i < dev->cfg.dirty_groups; i++) {
1355*10465441SEvalZero if (dev->buf.dirtyGroup[i].dirty) {
1356*10465441SEvalZero buf = dev->buf.dirtyGroup[i].dirty;
1357*10465441SEvalZero if (buf->parent == parent && buf->serial == serial) {
1358*10465441SEvalZero slot = i;
1359*10465441SEvalZero break;
1360*10465441SEvalZero }
1361*10465441SEvalZero }
1362*10465441SEvalZero }
1363*10465441SEvalZero return slot;
1364*10465441SEvalZero }
1365*10465441SEvalZero
1366*10465441SEvalZero /**
1367*10465441SEvalZero * \brief get a page buffer
1368*10465441SEvalZero * \param[in] dev uffs device
1369*10465441SEvalZero * \param[in] parent parent serial num
1370*10465441SEvalZero * \param[in] serial serial num
1371*10465441SEvalZero * \param[in] page_id page_id
1372*10465441SEvalZero * \return return the buffer found in buffer list, if not found, return NULL.
1373*10465441SEvalZero */
uffs_BufGet(struct uffs_DeviceSt * dev,u16 parent,u16 serial,u16 page_id)1374*10465441SEvalZero uffs_Buf * uffs_BufGet(struct uffs_DeviceSt *dev,
1375*10465441SEvalZero u16 parent, u16 serial, u16 page_id)
1376*10465441SEvalZero {
1377*10465441SEvalZero uffs_Buf *p;
1378*10465441SEvalZero
1379*10465441SEvalZero //first, check whether the buffer exist in buf list ?
1380*10465441SEvalZero p = uffs_BufFind(dev, parent, serial, page_id);
1381*10465441SEvalZero
1382*10465441SEvalZero if (p) {
1383*10465441SEvalZero p->ref_count++;
1384*10465441SEvalZero _MoveNodeToHead(dev, p);
1385*10465441SEvalZero }
1386*10465441SEvalZero
1387*10465441SEvalZero return p;
1388*10465441SEvalZero }
1389*10465441SEvalZero
1390*10465441SEvalZero /**
1391*10465441SEvalZero * New generate a buffer
1392*10465441SEvalZero */
uffs_BufNew(struct uffs_DeviceSt * dev,u8 type,u16 parent,u16 serial,u16 page_id)1393*10465441SEvalZero uffs_Buf *uffs_BufNew(struct uffs_DeviceSt *dev,
1394*10465441SEvalZero u8 type, u16 parent, u16 serial, u16 page_id)
1395*10465441SEvalZero {
1396*10465441SEvalZero uffs_Buf *buf;
1397*10465441SEvalZero
1398*10465441SEvalZero buf = uffs_BufGet(dev, parent, serial, page_id);
1399*10465441SEvalZero if (buf) {
1400*10465441SEvalZero if (buf->ref_count > 1) {
1401*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "When create new buf, \
1402*10465441SEvalZero an exist buffer has ref count %d, possibly bug!",
1403*10465441SEvalZero buf->ref_count);
1404*10465441SEvalZero }
1405*10465441SEvalZero else {
1406*10465441SEvalZero buf->data_len = 0;
1407*10465441SEvalZero }
1408*10465441SEvalZero _MoveNodeToHead(dev, buf);
1409*10465441SEvalZero return buf;
1410*10465441SEvalZero }
1411*10465441SEvalZero
1412*10465441SEvalZero buf = _FindFreeBuf(dev);
1413*10465441SEvalZero if (buf == NULL) {
1414*10465441SEvalZero uffs_BufFlushMostDirtyGroup(dev);
1415*10465441SEvalZero buf = _FindFreeBuf(dev);
1416*10465441SEvalZero if (buf == NULL) {
1417*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "no free page buf!");
1418*10465441SEvalZero return NULL;
1419*10465441SEvalZero }
1420*10465441SEvalZero }
1421*10465441SEvalZero
1422*10465441SEvalZero buf->mark = UFFS_BUF_EMPTY;
1423*10465441SEvalZero buf->type = type;
1424*10465441SEvalZero buf->parent = parent;
1425*10465441SEvalZero buf->serial = serial;
1426*10465441SEvalZero buf->page_id = page_id;
1427*10465441SEvalZero buf->data_len = 0;
1428*10465441SEvalZero buf->ref_count++;
1429*10465441SEvalZero memset(buf->data, 0xff, dev->com.pg_data_size);
1430*10465441SEvalZero
1431*10465441SEvalZero _MoveNodeToHead(dev, buf);
1432*10465441SEvalZero
1433*10465441SEvalZero return buf;
1434*10465441SEvalZero }
1435*10465441SEvalZero
1436*10465441SEvalZero
1437*10465441SEvalZero
1438*10465441SEvalZero /**
1439*10465441SEvalZero * get a page buffer
1440*10465441SEvalZero * \param[in] dev uffs device
1441*10465441SEvalZero * \param[in] type dir, file or data ?
1442*10465441SEvalZero * \param[in] node node on the tree
1443*10465441SEvalZero * \param[in] page_id page_id
1444*10465441SEvalZero * \param[in] oflag the open flag of current file/dir object
1445*10465441SEvalZero * \return return the buffer if found in buffer list, if not found in
1446*10465441SEvalZero * buffer list, it will get a free buffer, and load data from flash.
1447*10465441SEvalZero * return NULL if not free buffer.
1448*10465441SEvalZero */
uffs_BufGetEx(struct uffs_DeviceSt * dev,u8 type,TreeNode * node,u16 page_id,int oflag)1449*10465441SEvalZero uffs_Buf *uffs_BufGetEx(struct uffs_DeviceSt *dev,
1450*10465441SEvalZero u8 type, TreeNode *node, u16 page_id, int oflag)
1451*10465441SEvalZero {
1452*10465441SEvalZero uffs_Buf *buf;
1453*10465441SEvalZero u16 parent, serial, block, page;
1454*10465441SEvalZero uffs_BlockInfo *bc;
1455*10465441SEvalZero
1456*10465441SEvalZero switch (type) {
1457*10465441SEvalZero case UFFS_TYPE_DIR:
1458*10465441SEvalZero parent = node->u.dir.parent;
1459*10465441SEvalZero serial = node->u.dir.serial;
1460*10465441SEvalZero block = node->u.dir.block;
1461*10465441SEvalZero break;
1462*10465441SEvalZero case UFFS_TYPE_FILE:
1463*10465441SEvalZero parent = node->u.file.parent;
1464*10465441SEvalZero serial = node->u.file.serial;
1465*10465441SEvalZero block = node->u.file.block;
1466*10465441SEvalZero break;
1467*10465441SEvalZero case UFFS_TYPE_DATA:
1468*10465441SEvalZero parent = node->u.data.parent;
1469*10465441SEvalZero serial = node->u.data.serial;
1470*10465441SEvalZero block = node->u.data.block;
1471*10465441SEvalZero break;
1472*10465441SEvalZero default:
1473*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "unknown type");
1474*10465441SEvalZero return NULL;
1475*10465441SEvalZero }
1476*10465441SEvalZero
1477*10465441SEvalZero buf = uffs_BufFind(dev, parent, serial, page_id);
1478*10465441SEvalZero if (buf) {
1479*10465441SEvalZero buf->ref_count++;
1480*10465441SEvalZero return buf;
1481*10465441SEvalZero }
1482*10465441SEvalZero
1483*10465441SEvalZero buf = _FindFreeBuf(dev);
1484*10465441SEvalZero if (buf == NULL) {
1485*10465441SEvalZero uffs_BufFlushMostDirtyGroup(dev);
1486*10465441SEvalZero buf = _FindFreeBuf(dev);
1487*10465441SEvalZero if (buf == NULL) {
1488*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "no free page buf!");
1489*10465441SEvalZero return NULL;
1490*10465441SEvalZero }
1491*10465441SEvalZero
1492*10465441SEvalZero /* Note: if uffs_BufFlushMostDirtyGroup() flush the same block as we'll write to,
1493*10465441SEvalZero * the block will be changed to a new one! (and the content of 'node' is changed).
1494*10465441SEvalZero * So here we need to update block number from the new 'node'.
1495*10465441SEvalZero */
1496*10465441SEvalZero switch (type) {
1497*10465441SEvalZero case UFFS_TYPE_DIR:
1498*10465441SEvalZero block = node->u.dir.block;
1499*10465441SEvalZero break;
1500*10465441SEvalZero case UFFS_TYPE_FILE:
1501*10465441SEvalZero block = node->u.file.block;
1502*10465441SEvalZero break;
1503*10465441SEvalZero case UFFS_TYPE_DATA:
1504*10465441SEvalZero block = node->u.data.block;
1505*10465441SEvalZero break;
1506*10465441SEvalZero default:
1507*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "unknown type");
1508*10465441SEvalZero return NULL;
1509*10465441SEvalZero }
1510*10465441SEvalZero }
1511*10465441SEvalZero
1512*10465441SEvalZero bc = uffs_BlockInfoGet(dev, block);
1513*10465441SEvalZero if (bc == NULL) {
1514*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "Can't get block info!");
1515*10465441SEvalZero return NULL;
1516*10465441SEvalZero }
1517*10465441SEvalZero
1518*10465441SEvalZero page = uffs_FindPageInBlockWithPageId(dev, bc, page_id);
1519*10465441SEvalZero if (page == UFFS_INVALID_PAGE) {
1520*10465441SEvalZero uffs_BlockInfoPut(dev, bc);
1521*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "can't find right page ? block %d page_id %d", bc->block, page_id);
1522*10465441SEvalZero return NULL;
1523*10465441SEvalZero }
1524*10465441SEvalZero page = uffs_FindBestPageInBlock(dev, bc, page);
1525*10465441SEvalZero if (!uffs_Assert(page != UFFS_INVALID_PAGE, "got an invalid page?\n"))
1526*10465441SEvalZero return NULL;
1527*10465441SEvalZero
1528*10465441SEvalZero uffs_BlockInfoPut(dev, bc);
1529*10465441SEvalZero
1530*10465441SEvalZero buf->mark = UFFS_BUF_EMPTY;
1531*10465441SEvalZero buf->type = type;
1532*10465441SEvalZero buf->parent = parent;
1533*10465441SEvalZero buf->serial = serial;
1534*10465441SEvalZero buf->page_id = page_id;
1535*10465441SEvalZero
1536*10465441SEvalZero if (UFFS_FLASH_HAVE_ERR(uffs_FlashReadPage(dev, block, page, buf, oflag & UO_NOECC ? U_TRUE : U_FALSE))) {
1537*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "can't load page from flash !");
1538*10465441SEvalZero return NULL;
1539*10465441SEvalZero }
1540*10465441SEvalZero
1541*10465441SEvalZero buf->data_len = TAG_DATA_LEN(GET_TAG(bc, page));
1542*10465441SEvalZero buf->mark = UFFS_BUF_VALID;
1543*10465441SEvalZero buf->ref_count++;
1544*10465441SEvalZero
1545*10465441SEvalZero _MoveNodeToHead(dev, buf);
1546*10465441SEvalZero
1547*10465441SEvalZero return buf;
1548*10465441SEvalZero
1549*10465441SEvalZero }
1550*10465441SEvalZero
1551*10465441SEvalZero /**
1552*10465441SEvalZero * \brief Put back a page buffer, make reference count decrease by one
1553*10465441SEvalZero * \param[in] dev uffs device
1554*10465441SEvalZero * \param[in] buf buffer to be put back
1555*10465441SEvalZero */
uffs_BufPut(uffs_Device * dev,uffs_Buf * buf)1556*10465441SEvalZero URET uffs_BufPut(uffs_Device *dev, uffs_Buf *buf)
1557*10465441SEvalZero {
1558*10465441SEvalZero URET ret = U_FAIL;
1559*10465441SEvalZero
1560*10465441SEvalZero dev = dev;
1561*10465441SEvalZero if (buf == NULL) {
1562*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL, "Can't put an NULL buffer!");
1563*10465441SEvalZero }
1564*10465441SEvalZero else if (buf->ref_count == 0) {
1565*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL, "Putting an unused page buffer ? ");
1566*10465441SEvalZero }
1567*10465441SEvalZero else if (buf->ref_count == CLONE_BUF_MARK) {
1568*10465441SEvalZero uffs_Perror(UFFS_MSG_NORMAL, "Putting an cloned page buffer ? ");
1569*10465441SEvalZero ret = uffs_BufFreeClone(dev, buf);
1570*10465441SEvalZero }
1571*10465441SEvalZero else {
1572*10465441SEvalZero buf->ref_count--;
1573*10465441SEvalZero ret = U_SUCC;
1574*10465441SEvalZero }
1575*10465441SEvalZero
1576*10465441SEvalZero return ret;
1577*10465441SEvalZero }
1578*10465441SEvalZero
1579*10465441SEvalZero
1580*10465441SEvalZero /**
1581*10465441SEvalZero * \brief clone from an exist buffer.
1582*10465441SEvalZero allocate memory for new buffer, and copy data from original buffer if
1583*10465441SEvalZero original buffer is not NULL.
1584*10465441SEvalZero * \param[in] dev uffs device
1585*10465441SEvalZero * \param[in] buf page buffer to be clone from.
1586*10465441SEvalZero * if NULL presented here, data copy will not be processed
1587*10465441SEvalZero * \return return the cloned page buffer, all data copied from source
1588*10465441SEvalZero * \note the cloned buffer is not linked in page buffer list in uffs device,
1589*10465441SEvalZero * so you should use #uffs_BufFreeClone instead of #uffs_BufPut
1590*10465441SEvalZero * when you put back or release buffer
1591*10465441SEvalZero */
uffs_BufClone(uffs_Device * dev,uffs_Buf * buf)1592*10465441SEvalZero uffs_Buf * uffs_BufClone(uffs_Device *dev, uffs_Buf *buf)
1593*10465441SEvalZero {
1594*10465441SEvalZero uffs_Buf *p;
1595*10465441SEvalZero
1596*10465441SEvalZero p = _FindFreeBufEx(dev, 1);
1597*10465441SEvalZero if (p == NULL) {
1598*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS,
1599*10465441SEvalZero "no enough free pages for clone! " \
1600*10465441SEvalZero "Please increase Clone Buffer Count threshold.");
1601*10465441SEvalZero }
1602*10465441SEvalZero else {
1603*10465441SEvalZero _BreakFromBufList(dev, p);
1604*10465441SEvalZero
1605*10465441SEvalZero if (buf) {
1606*10465441SEvalZero p->parent = buf->parent;
1607*10465441SEvalZero p->type = buf->type;
1608*10465441SEvalZero p->serial = buf->serial;
1609*10465441SEvalZero p->page_id = buf->page_id;
1610*10465441SEvalZero
1611*10465441SEvalZero p->data_len = buf->data_len;
1612*10465441SEvalZero //athough the valid data length is .data_len,
1613*10465441SEvalZero //but we still need copy the whole buffer, include header
1614*10465441SEvalZero memcpy(p->header, buf->header, dev->com.pg_size);
1615*10465441SEvalZero }
1616*10465441SEvalZero p->next = p->prev = NULL; // the cloned one is not linked to device buffer
1617*10465441SEvalZero p->next_dirty = p->prev_dirty = NULL;
1618*10465441SEvalZero p->ref_count = CLONE_BUF_MARK; // CLONE_BUF_MARK indicates that
1619*10465441SEvalZero // this is an cloned buffer
1620*10465441SEvalZero }
1621*10465441SEvalZero
1622*10465441SEvalZero return p;
1623*10465441SEvalZero }
1624*10465441SEvalZero
1625*10465441SEvalZero /**
1626*10465441SEvalZero * \brief release cloned buffer
1627*10465441SEvalZero * \param[in] dev uffs device
1628*10465441SEvalZero * \param[in] buf cloned buffer
1629*10465441SEvalZero */
uffs_BufFreeClone(uffs_Device * dev,uffs_Buf * buf)1630*10465441SEvalZero URET uffs_BufFreeClone(uffs_Device *dev, uffs_Buf *buf)
1631*10465441SEvalZero {
1632*10465441SEvalZero dev = dev; //make compiler happy
1633*10465441SEvalZero if (!buf)
1634*10465441SEvalZero return U_FAIL;
1635*10465441SEvalZero
1636*10465441SEvalZero if (buf->ref_count != CLONE_BUF_MARK) {
1637*10465441SEvalZero /* a cloned buffer must have a ref_count of CLONE_BUF_MARK */
1638*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS,
1639*10465441SEvalZero "Try to release a non-cloned page buffer ?");
1640*10465441SEvalZero return U_FAIL;
1641*10465441SEvalZero }
1642*10465441SEvalZero
1643*10465441SEvalZero buf->ref_count = 0;
1644*10465441SEvalZero buf->mark = UFFS_BUF_EMPTY;
1645*10465441SEvalZero _LinkToBufListTail(dev, buf);
1646*10465441SEvalZero
1647*10465441SEvalZero return U_SUCC;
1648*10465441SEvalZero }
1649*10465441SEvalZero
1650*10465441SEvalZero
1651*10465441SEvalZero
uffs_BufIsAllFree(struct uffs_DeviceSt * dev)1652*10465441SEvalZero UBOOL uffs_BufIsAllFree(struct uffs_DeviceSt *dev)
1653*10465441SEvalZero {
1654*10465441SEvalZero uffs_Buf *buf = dev->buf.head;
1655*10465441SEvalZero
1656*10465441SEvalZero while (buf) {
1657*10465441SEvalZero if(buf->ref_count != 0) return U_FALSE;
1658*10465441SEvalZero buf = buf->next;
1659*10465441SEvalZero }
1660*10465441SEvalZero
1661*10465441SEvalZero return U_TRUE;
1662*10465441SEvalZero }
1663*10465441SEvalZero
uffs_BufIsAllEmpty(struct uffs_DeviceSt * dev)1664*10465441SEvalZero UBOOL uffs_BufIsAllEmpty(struct uffs_DeviceSt *dev)
1665*10465441SEvalZero {
1666*10465441SEvalZero uffs_Buf *buf = dev->buf.head;
1667*10465441SEvalZero
1668*10465441SEvalZero while (buf) {
1669*10465441SEvalZero if(buf->mark != UFFS_BUF_EMPTY) return U_FALSE;
1670*10465441SEvalZero buf = buf->next;
1671*10465441SEvalZero }
1672*10465441SEvalZero
1673*10465441SEvalZero return U_TRUE;
1674*10465441SEvalZero }
1675*10465441SEvalZero
1676*10465441SEvalZero
uffs_BufSetAllEmpty(struct uffs_DeviceSt * dev)1677*10465441SEvalZero URET uffs_BufSetAllEmpty(struct uffs_DeviceSt *dev)
1678*10465441SEvalZero {
1679*10465441SEvalZero uffs_Buf *buf = dev->buf.head;
1680*10465441SEvalZero
1681*10465441SEvalZero while (buf) {
1682*10465441SEvalZero buf->mark = UFFS_BUF_EMPTY;
1683*10465441SEvalZero buf = buf->next;
1684*10465441SEvalZero }
1685*10465441SEvalZero return U_SUCC;
1686*10465441SEvalZero }
1687*10465441SEvalZero
1688*10465441SEvalZero
uffs_BufIncRef(uffs_Buf * buf)1689*10465441SEvalZero void uffs_BufIncRef(uffs_Buf *buf)
1690*10465441SEvalZero {
1691*10465441SEvalZero buf->ref_count++;
1692*10465441SEvalZero }
1693*10465441SEvalZero
uffs_BufDecRef(uffs_Buf * buf)1694*10465441SEvalZero void uffs_BufDecRef(uffs_Buf *buf)
1695*10465441SEvalZero {
1696*10465441SEvalZero if (buf->ref_count > 0)
1697*10465441SEvalZero buf->ref_count--;
1698*10465441SEvalZero }
1699*10465441SEvalZero
1700*10465441SEvalZero /** mark buffer as #UFFS_BUF_EMPTY if ref_count == 0,
1701*10465441SEvalZero and discard all data it holds */
uffs_BufMarkEmpty(uffs_Device * dev,uffs_Buf * buf)1702*10465441SEvalZero void uffs_BufMarkEmpty(uffs_Device *dev, uffs_Buf *buf)
1703*10465441SEvalZero {
1704*10465441SEvalZero if (buf->mark != UFFS_BUF_EMPTY) {
1705*10465441SEvalZero if (buf->ref_count == 0) {
1706*10465441SEvalZero if (buf->mark == UFFS_BUF_DIRTY)
1707*10465441SEvalZero _BreakFromDirty(dev, buf);
1708*10465441SEvalZero buf->mark = UFFS_BUF_EMPTY;
1709*10465441SEvalZero }
1710*10465441SEvalZero }
1711*10465441SEvalZero }
1712*10465441SEvalZero
1713*10465441SEvalZero #if 0
1714*10465441SEvalZero static UBOOL _IsBufInDirtyList(struct uffs_DeviceSt *dev, uffs_Buf *buf)
1715*10465441SEvalZero {
1716*10465441SEvalZero uffs_Buf *p = dev->buf.dirtyGroup[slot].dirty;
1717*10465441SEvalZero
1718*10465441SEvalZero while (p) {
1719*10465441SEvalZero if(p == buf) return U_TRUE;
1720*10465441SEvalZero p = p->next_dirty;
1721*10465441SEvalZero }
1722*10465441SEvalZero
1723*10465441SEvalZero return U_FALSE;
1724*10465441SEvalZero }
1725*10465441SEvalZero #endif
1726*10465441SEvalZero
uffs_BufWrite(struct uffs_DeviceSt * dev,uffs_Buf * buf,void * data,u32 ofs,u32 len)1727*10465441SEvalZero URET uffs_BufWrite(struct uffs_DeviceSt *dev,
1728*10465441SEvalZero uffs_Buf *buf, void *data, u32 ofs, u32 len)
1729*10465441SEvalZero {
1730*10465441SEvalZero int slot;
1731*10465441SEvalZero
1732*10465441SEvalZero if(ofs + len > dev->com.pg_data_size) {
1733*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS,
1734*10465441SEvalZero "data length out of range! %d+%d", ofs, len);
1735*10465441SEvalZero return U_FAIL;
1736*10465441SEvalZero }
1737*10465441SEvalZero
1738*10465441SEvalZero slot = uffs_BufFindGroupSlot(dev, buf->parent, buf->serial);
1739*10465441SEvalZero
1740*10465441SEvalZero if (slot < 0) {
1741*10465441SEvalZero // need to take a free slot
1742*10465441SEvalZero slot = uffs_BufFindFreeGroupSlot(dev);
1743*10465441SEvalZero if (slot < 0) {
1744*10465441SEvalZero // no free slot ? flush buffer
1745*10465441SEvalZero if (uffs_BufFlushMostDirtyGroup(dev) != U_SUCC)
1746*10465441SEvalZero return U_FAIL;
1747*10465441SEvalZero
1748*10465441SEvalZero slot = uffs_BufFindFreeGroupSlot(dev);
1749*10465441SEvalZero if (slot < 0) {
1750*10465441SEvalZero // still no free slot ??
1751*10465441SEvalZero uffs_Perror(UFFS_MSG_SERIOUS, "no free slot ?");
1752*10465441SEvalZero return U_FAIL;
1753*10465441SEvalZero }
1754*10465441SEvalZero }
1755*10465441SEvalZero }
1756*10465441SEvalZero
1757*10465441SEvalZero if (data)
1758*10465441SEvalZero memcpy(buf->data + ofs, data, len);
1759*10465441SEvalZero else
1760*10465441SEvalZero memset(buf->data + ofs, 0, len); // if data == NULL, then fill all '\0'.
1761*10465441SEvalZero
1762*10465441SEvalZero if (ofs + len > buf->data_len)
1763*10465441SEvalZero buf->data_len = ofs + len;
1764*10465441SEvalZero
1765*10465441SEvalZero if (_IsBufInInDirtyList(dev, slot, buf) == U_FALSE) {
1766*10465441SEvalZero _LinkToDirtyList(dev, slot, buf);
1767*10465441SEvalZero }
1768*10465441SEvalZero
1769*10465441SEvalZero if (dev->buf.dirtyGroup[slot].count >= dev->buf.dirty_buf_max) {
1770*10465441SEvalZero if (uffs_BufFlushGroup(dev, buf->parent, buf->serial) != U_SUCC) {
1771*10465441SEvalZero return U_FAIL;
1772*10465441SEvalZero }
1773*10465441SEvalZero }
1774*10465441SEvalZero
1775*10465441SEvalZero return U_SUCC;
1776*10465441SEvalZero }
1777*10465441SEvalZero
uffs_BufRead(struct uffs_DeviceSt * dev,uffs_Buf * buf,void * data,u32 ofs,u32 len)1778*10465441SEvalZero URET uffs_BufRead(struct uffs_DeviceSt *dev,
1779*10465441SEvalZero uffs_Buf *buf, void *data, u32 ofs, u32 len)
1780*10465441SEvalZero {
1781*10465441SEvalZero u32 readSize;
1782*10465441SEvalZero u32 pg_data_size = dev->com.pg_data_size;
1783*10465441SEvalZero
1784*10465441SEvalZero readSize = (ofs >= pg_data_size ?
1785*10465441SEvalZero 0 : (ofs + len >= pg_data_size ? pg_data_size - ofs : len)
1786*10465441SEvalZero );
1787*10465441SEvalZero
1788*10465441SEvalZero if (readSize > 0)
1789*10465441SEvalZero memcpy(data, buf->data + ofs, readSize);
1790*10465441SEvalZero
1791*10465441SEvalZero return U_SUCC;
1792*10465441SEvalZero }
1793*10465441SEvalZero
1794*10465441SEvalZero
1795*10465441SEvalZero
1796*10465441SEvalZero
1797*10465441SEvalZero
1798*10465441SEvalZero
1799*10465441SEvalZero
1800