4 * Copyright (c) 2002-2006 Intel Corporation
7 * This file is distributed under the terms in the attached INTEL-LICENSE
8 * file. If you do not find these files, copies can be found by writing to
9 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA,
10 * 94704. Attention: Intel License Inquiry.
14 * Private component of the AT45DB implementation of the config storage
17 * @author: David Gay <dgay@acm.org>
23 module ConfigStorageP {
25 interface Mount[uint8_t id];
26 interface ConfigStorage[uint8_t id];
27 interface At45dbBlockConfig as BConfig[uint8_t id];
31 interface BlockRead[uint8_t id];
32 interface BlockWrite[uint8_t id];
37 /* A config storage is built on top of a block storage volume, with
38 the block storage volume divided into two and the first 4 bytes of
39 each half holding a (>0) version number. The valid half with the
40 highest version number is the current version.
42 Transactional behaviour is achieved by copying the current half
43 into the other, then increment its version number. Writes then
44 proceed in that new half until a commit, which just uses the
45 underlying BlockStorage commit's operation.
47 Note: all of this depends on the at45db's implementation of
48 BlockStorageP. It will not work over an arbitrary BlockStorageP
49 implementation (additionally, it uses hooks in BlockStorageP to
50 support the half-volume operation). Additionally, the code assumes
51 that the config volumes all have lower ids than the block volumes.
64 N = uniqueCount(UQ_CONFIG_STORAGE),
68 /* Per-client state. We could keep just the state and current version
69 in an array, but this requires more complex arbitration (don't
70 release block storage during mount or commit). As I don't expect
71 many config volumes, this doesn't seem worth the trouble. */
74 uint8_t committing : 1;
82 /* Bit n is true if client n is using upper block */
83 uint8_t flipState[(N + 7) / 8];
85 uint8_t client = NO_CLIENT;
88 void setFlip(uint8_t id, bool flip) {
90 flipState[id >> 3] |= 1 << (id & 7);
92 flipState[id >> 3] &= ~(1 << (id & 7));
95 bool flipped(uint8_t id) {
96 return call BConfig.flipped[id]();
99 void flip(uint8_t id) {
100 setFlip(id, !flipped(id));
103 storage_len_t volumeSize(uint8_t id) {
104 return call BlockRead.getSize[id]();
107 /* ------------------------------------------------------------------ */
109 /* ------------------------------------------------------------------ */
111 command error_t Mount.mount[uint8_t id]() {
112 /* Read version on both halves. Validate higher. Validate lower if
113 higher invalid. Use lower if both invalid. */
114 if (s[id].state != S_STOPPED)
117 s[id].state = S_MOUNT;
119 call BlockRead.read[id](0, &low[id], sizeof low[id]);
124 void computeCrc(uint8_t id) {
125 call BlockRead.computeCrc[id](sizeof(nx_uint16_t),
126 volumeSize(id) - sizeof(nx_uint16_t),
130 void mountReadDone(uint8_t id, error_t error) {
131 if (error != SUCCESS)
133 s[id].state = S_STOPPED;
134 signal Mount.mountDone[id](FAIL);
136 else if (!call BConfig.flipped[id]())
138 /* Just read low-half version. Read high-half version */
140 call BlockRead.read[id](0, &high[id], sizeof high[id]);
144 /* Verify the half with the largest version */
145 setFlip(id, high[id].version > low[id].version);
150 void mountCrcDone(uint8_t id, uint16_t crc, error_t error) {
151 bool isflipped = call BConfig.flipped[id]();
153 if (error == SUCCESS &&
154 crc == (isflipped ? high[id].crc : low[id].crc))
156 /* We just use the low data once mounted */
158 low[id].version = high[id].version;
159 s[id].state = S_CLEAN;
163 // try the other half?
164 if ((high[id].version > low[id].version) == isflipped)
166 /* Verification of the half with the highest version failed. Try
168 setFlip(id, !isflipped);
172 /* Both halves bad, terminate. Reads will fail. */
173 s[id].state = S_INVALID;
176 signal Mount.mountDone[id](SUCCESS);
179 /* ------------------------------------------------------------------ */
181 /* ------------------------------------------------------------------ */
183 command error_t ConfigStorage.read[uint8_t id](storage_addr_t addr, void* buf, storage_len_t len) {
184 /* Read from current half using BlockRead */
185 if (s[id].state < S_CLEAN)
187 if (s[id].state == S_INVALID) // nothing to read
190 return call BlockRead.read[id](addr + sizeof low[0], buf, len);
193 void readReadDone(uint8_t id, storage_addr_t addr, void* buf, storage_len_t len, error_t error) {
194 signal ConfigStorage.readDone[id](addr - sizeof low[0], buf, len, error);
197 /* ------------------------------------------------------------------ */
199 /* ------------------------------------------------------------------ */
201 command error_t ConfigStorage.write[uint8_t id](storage_addr_t addr, void* buf, storage_len_t len) {
202 /* 1: If first write:
203 copy to other half with incremented version number
204 2: Write to other half using BlockWrite */
206 if (s[id].state < S_CLEAN)
208 return call BlockWrite.write[id](addr + sizeof low[0], buf, len);
211 void copyCopyPageDone(error_t error);
212 void writeContinue(error_t error);
214 command int BConfig.writeHook[uint8_t id]() {
215 if (s[id].committing)
218 flip(id); /* We write to the non-current half... */
219 if (s[id].state != S_CLEAN) // no copy if dirty or invalid
222 /* Time to do the copy dance */
224 nextPage = signal BConfig.npages[id]();
225 copyCopyPageDone(SUCCESS);
230 void copyCopyPageDone(error_t error) {
231 if (error != SUCCESS)
232 writeContinue(error);
233 else if (nextPage == 0) // copy done
235 s[client].state = S_DIRTY;
236 writeContinue(SUCCESS);
241 at45page_t from, to, npages = signal BConfig.npages[client]();
243 to = from = signal BConfig.remap[client](--nextPage);
249 call At45db.copyPage(from, to);
253 void writeContinue(error_t error) {
257 signal BConfig.writeContinue[id](error);
260 void writeWriteDone(uint8_t id, storage_addr_t addr, void* buf, storage_len_t len, error_t error) {
261 flip(id); // flip back to current half
262 signal ConfigStorage.writeDone[id](addr - sizeof low[0], buf, len, error);
265 /* ------------------------------------------------------------------ */
267 /* ------------------------------------------------------------------ */
269 void commitSyncDone(uint8_t id, error_t error);
271 command error_t ConfigStorage.commit[uint8_t id]() {
276 if (s[id].state < S_CLEAN)
279 if (s[id].state == S_CLEAN)
280 /* A dummy CRC call to avoid signaling a completion event from here */
281 return call BlockRead.computeCrc[id](0, 1, 0);
283 /* Compute CRC for new version and current contents */
286 for (crc = 0, i = 0; i < sizeof low[id].version; i++)
287 crc = crcByte(crc, ((uint8_t *)&low[id] + sizeof(nx_uint16_t))[i]);
288 ok = call BlockRead.computeCrc[id](sizeof low[id],
289 volumeSize(id) - sizeof low[id],
292 s[id].committing = TRUE;
297 void commitCrcDone(uint8_t id, uint16_t crc, error_t error) {
298 /* Weird commit of clean volume hack: we just complete now, w/o
299 really doing anything. Ideally we should short-circuit out in the
300 commit call, but that would break the "no-signal-from-command"
301 rule. So we just waste the CRC computation effort instead - the
302 assumption is people don't regularly commit clean volumes. */
303 if (s[id].state == S_CLEAN)
304 signal ConfigStorage.commitDone[id](error);
305 else if (error != SUCCESS)
306 commitSyncDone(id, error);
310 call BlockWrite.write[id](0, &low[id], sizeof low[id]);
314 void commitWriteDone(uint8_t id, error_t error) {
315 if (error != SUCCESS)
316 commitSyncDone(id, error);
318 call BlockWrite.sync[id]();
321 void commitSyncDone(uint8_t id, error_t error) {
322 s[id].committing = FALSE;
323 if (error == SUCCESS)
324 s[id].state = S_CLEAN;
326 flip(id); // revert to old block
327 signal ConfigStorage.commitDone[id](error);
330 /* ------------------------------------------------------------------ */
332 /* ------------------------------------------------------------------ */
334 command storage_len_t ConfigStorage.getSize[uint8_t id]() {
335 return volumeSize(id) - sizeof low[0];
338 /* ------------------------------------------------------------------ */
340 /* ------------------------------------------------------------------ */
342 command bool ConfigStorage.valid[uint8_t id]() {
343 return s[id].state != S_INVALID;
346 /* ------------------------------------------------------------------ */
347 /* Interface with BlockStorageP */
348 /* ------------------------------------------------------------------ */
350 /* The config volumes use the low block volume numbers. So a volume is a
351 config volume iff its its id is less than N */
353 command int BConfig.isConfig[uint8_t id]() {
357 inline command int BConfig.flipped[uint8_t id]() {
358 return (flipState[id >> 3] & (1 << (id & 7))) != 0;
361 event void BlockRead.readDone[uint8_t id](storage_addr_t addr, void* buf, storage_len_t len, error_t error) {
363 if (s[id].state == S_MOUNT)
364 mountReadDone(id, error);
366 readReadDone(id, addr, buf, len, error);
369 event void BlockWrite.writeDone[uint8_t id]( storage_addr_t addr, void* buf, storage_len_t len, error_t error ) {
371 if (s[id].committing)
372 commitWriteDone(id, error);
374 writeWriteDone(id, addr, buf, len, error);
377 event void BlockWrite.syncDone[uint8_t id]( error_t error ) {
379 commitSyncDone(id, error);
382 event void BlockRead.computeCrcDone[uint8_t id]( storage_addr_t addr, storage_len_t len, uint16_t crc, error_t error ) {
384 if (s[id].state == S_MOUNT)
385 mountCrcDone(id, crc, error);
387 commitCrcDone(id, crc, error);
390 event void At45db.copyPageDone(error_t error) {
391 if (client != NO_CLIENT)
392 copyCopyPageDone(error);
395 event void BlockWrite.eraseDone[uint8_t id](error_t error) {}
396 event void At45db.eraseDone(error_t error) {}
397 event void At45db.syncDone(error_t error) {}
398 event void At45db.flushDone(error_t error) {}
399 event void At45db.readDone(error_t error) {}
400 event void At45db.computeCrcDone(error_t error, uint16_t crc) {}
401 event void At45db.writeDone(error_t error) {}
403 default event void Mount.mountDone[uint8_t id](error_t error) { }
404 default event void ConfigStorage.readDone[uint8_t id](storage_addr_t addr, void* buf, storage_len_t len, error_t error) {}
405 default event void ConfigStorage.writeDone[uint8_t id](storage_addr_t addr, void* buf, storage_len_t len, error_t error) {}
406 default event void ConfigStorage.commitDone[uint8_t id](error_t error) {}