altos/test: Adjust CRC error rate after FEC fix
[fw/altos] / src / kernel / ao_storage.c
1 /*
2  * Copyright © 2011 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <ao.h>
20 #include <ao_storage.h>
21
22 #define AO_STORAGE_DATA_SIZE    128
23
24 static uint8_t storage_data[AO_STORAGE_DATA_SIZE];
25 static uint8_t storage_mutex;
26
27 uint8_t
28 ao_storage_read(ao_pos_t pos, void *v_buf, uint16_t len)
29 {
30         uint8_t *buf = v_buf;
31         uint16_t this_len;
32         uint16_t this_off;
33
34         ao_storage_setup();
35         if (pos >= ao_storage_total || pos + len > ao_storage_total)
36                 return 0;
37         while (len) {
38
39                 /* Compute portion of transfer within
40                  * a single block
41                  */
42                 this_off = (uint16_t) (pos & (ao_storage_unit - 1));
43                 this_len = ao_storage_unit - this_off;
44                 if (this_len > len)
45                         this_len = len;
46
47                 if (!ao_storage_device_read(pos, buf, this_len))
48                         return 0;
49
50                 /* See how much is left */
51                 buf += this_len;
52                 len -= this_len;
53                 pos += this_len;
54         }
55         return 1;
56 }
57
58 uint8_t
59 ao_storage_write(ao_pos_t pos, void *v_buf, uint16_t len) 
60 {
61         uint8_t *buf = v_buf;
62         uint16_t this_len;
63         uint16_t this_off;
64
65         ao_storage_setup();
66         if (pos >= ao_storage_total || pos + len > ao_storage_total)
67                 return 0;
68         while (len) {
69
70                 /* Compute portion of transfer within
71                  * a single block
72                  */
73                 this_off = (uint16_t) (pos & (ao_storage_unit - 1));
74                 this_len = ao_storage_unit - this_off;
75                 if (this_len > len)
76                         this_len = len;
77
78                 if (!ao_storage_device_write(pos, buf, this_len))
79                         return 0;
80
81                 /* See how much is left */
82                 buf += this_len;
83                 len -= this_len;
84                 pos += this_len;
85         }
86         return 1;
87 }
88
89 uint8_t
90 ao_storage_is_erased(uint32_t pos)
91 {
92         uint32_t        read_pos;
93         uint32_t        read_len;
94         uint32_t        i;
95         uint8_t         ret = 1;
96
97         ao_storage_setup();
98         ao_mutex_get(&storage_mutex);
99         read_pos = pos;
100         read_len = ao_storage_block;
101         while (read_len) {
102                 uint32_t this_time = AO_STORAGE_DATA_SIZE;
103                 if (this_time > read_len)
104                         this_time = read_len;
105                 if (!ao_storage_read(read_pos, storage_data, (uint16_t) this_time)) {
106                         ret = 0;
107                         goto done;
108                 }
109                 for (i = 0; i < this_time; i++)
110                         if (storage_data[i] != AO_STORAGE_ERASED_BYTE) {
111                                 ret = 0;
112                                 goto done;
113                         }
114                 read_pos += this_time;
115                 read_len -= this_time;
116         }
117 done:
118         ao_mutex_put(&storage_mutex);
119         return ret;
120 }
121
122 uint8_t
123 ao_storage_erase(uint32_t start_pos, uint32_t len)
124 {
125         /* Round 'len' up to ao_storage_block units */
126         len = ((len + ao_storage_block - 1) / ao_storage_block) * ao_storage_block;
127
128         /*
129          * Start at the end of the area to erase so that the
130          * last block cleared is the first block; this will ensure
131          * that partially erased flight logs still appear in the list
132          * and can be re-erased.
133          */
134         uint32_t pos = start_pos + len - ao_storage_block;
135         while (len) {
136                 int tries;
137
138 #define MAX_TRIES       4       /* needs to be at least 2 */
139                 for (tries = 0; tries < MAX_TRIES; tries++) {
140                         if (ao_storage_is_erased(pos))
141                                 break;
142                         if (!ao_storage_device_erase(pos))
143                                 return 0;
144                 }
145                 if (tries == MAX_TRIES)
146                         return 0;
147                 pos -= ao_storage_block;
148                 len -= ao_storage_block;
149         }
150         return 1;
151 }
152
153 static void
154 ao_storage_dump(void) 
155 {
156         uint32_t block;
157         uint8_t i, j, k;
158
159         block = ao_cmd_hex();
160         if (ao_cmd_status != ao_cmd_success)
161                 return;
162         ao_mutex_get(&storage_mutex);
163         for (i = 0; ; i += AO_STORAGE_DATA_SIZE) {
164                 if (ao_storage_read((block << 8) + i,
165                                     storage_data,
166                                     AO_STORAGE_DATA_SIZE)) {
167                         for (k = 0; k < AO_STORAGE_DATA_SIZE; k += 8) {
168                                 ao_cmd_put16((uint16_t) i + k);
169                                 for (j = 0; j < 8; j++) {
170                                         putchar(' ');
171                                         ao_cmd_put8(storage_data[k + j]);
172                                 }
173                                 putchar ('\n');
174                         }
175                 }
176                 if (i == 256 - AO_STORAGE_DATA_SIZE)
177                         break;
178         }
179         ao_mutex_put(&storage_mutex);
180 }
181
182 #if HAS_STORAGE_DEBUG
183
184 /* not enough space for this today
185  */
186 static void
187 ao_storage_store(void) 
188 {
189         uint16_t block;
190         uint8_t i;
191         uint16_t len;
192         uint8_t b;
193         uint32_t addr;
194
195         block = ao_cmd_hex();
196         i = ao_cmd_hex();
197         addr = ((uint32_t) block << 8) | i;
198         len = ao_cmd_hex();
199         if (ao_cmd_status != ao_cmd_success)
200                 return;
201         while (len--) {
202                 b = ao_cmd_hexbyte();
203                 if (ao_cmd_status != ao_cmd_success)
204                         return;
205                 ao_storage_write(addr, &b, 1);
206                 addr++;
207         }
208 }
209 #endif
210
211 static void
212 ao_storage_zap(void) 
213 {
214         uint32_t v = ao_cmd_hex();
215         if (ao_cmd_status != ao_cmd_success)
216                 return;
217         ao_storage_erase((uint32_t) v << 8, ao_storage_block);
218 }
219
220 static void
221 ao_storage_zapall(void) 
222 {
223         ao_cmd_white();
224         if (!ao_match_word("DoIt"))
225                 return;
226         ao_storage_erase(0, ao_storage_log_max);
227 }
228
229 #if AO_STORAGE_TEST
230
231 #define AO_STORAGE_TEST_SIZE    256
232 static uint8_t storage_test[AO_STORAGE_TEST_SIZE];
233
234 static void
235 ao_storage_failure(uint32_t pos, char *format, ...)
236 {
237         va_list a;
238         printf("TEST FAILURE AT %08x: ", pos);
239         va_start(a, format);
240         vprintf(format, a);
241         va_end(a);
242 }
243
244 static uint8_t
245 ao_storage_check_block(uint32_t pos, uint8_t value)
246 {
247         uint32_t        offset;
248         uint32_t        byte;
249
250         for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_test)) {
251                 if (!ao_storage_read(pos + offset, storage_test, sizeof (storage_test))) {
252                         ao_storage_failure(pos + offset, "read failed\n");
253                         return 0;
254                 }
255                 for (byte = 0; byte < sizeof (storage_test); byte++)
256                         if (storage_test[byte] != value) {
257                                 ao_storage_failure(pos + offset + byte,
258                                                    "want %02x got %02x\n",
259                                                    value, storage_test[byte]);
260                                 return 0;
261                         }
262         }
263         return 1;
264 }
265
266 static uint8_t
267 ao_storage_fill_block(uint32_t pos, uint8_t value)
268 {
269         uint32_t        offset;
270         uint32_t        byte;
271
272         for (byte = 0; byte < sizeof (storage_test); byte++)
273                 storage_test[byte] = value;
274         for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_test)) {
275                 if (!ao_storage_write(pos + offset, storage_test, sizeof (storage_test))) {
276                         ao_storage_failure(pos + offset, "write failed\n");
277                         return 0;
278                 }
279         }
280         return 1;
281 }
282
283 static uint8_t
284 ao_storage_check_incr_block(uint32_t pos)
285 {
286         uint32_t        offset;
287         uint32_t        byte;
288
289         for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_test)) {
290                 if (!ao_storage_read(pos + offset, storage_test, sizeof (storage_test))) {
291                         ao_storage_failure(pos + offset, "read failed\n");
292                         return 0;
293                 }
294                 for (byte = 0; byte < sizeof (storage_test); byte++) {
295                         uint8_t value = offset + byte;
296                         if (storage_test[byte] != value) {
297                                 ao_storage_failure(pos + offset + byte,
298                                                    "want %02x got %02x\n",
299                                                    value, storage_test[byte]);
300                                 return 0;
301                         }
302                 }
303         }
304         return 1;
305 }
306
307 static uint8_t
308 ao_storage_fill_incr_block(uint32_t pos)
309 {
310         uint32_t        offset;
311         uint32_t        byte;
312
313         for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_test)) {
314                 for (byte = 0; byte < sizeof (storage_test); byte++)
315                         storage_test[byte] = offset + byte;
316                 if (!ao_storage_write(pos + offset, storage_test, sizeof (storage_test))) {
317                         ao_storage_failure(pos + offset, "write failed\n");
318                         return 0;
319                 }
320         }
321         return 1;
322 }
323
324 static uint8_t
325 ao_storage_fill_check_block(uint32_t pos, uint8_t value)
326 {
327         return ao_storage_fill_block(pos, value) && ao_storage_check_block(pos, value);
328 }
329
330 static uint8_t
331 ao_storage_incr_check_block(uint32_t pos)
332 {
333         return ao_storage_fill_incr_block(pos) && ao_storage_check_incr_block(pos);
334 }
335
336 static uint8_t
337 ao_storage_test_block(uint32_t pos) 
338 {
339         ao_storage_erase(pos, ao_storage_block);
340         printf(" erase"); flush();
341         if (!ao_storage_check_block(pos, 0xff))
342                 return 0;
343         printf(" zero"); flush();
344         if (!ao_storage_fill_check_block(pos, 0x00))
345                 return 0;
346         ao_storage_erase(pos, ao_storage_block);
347         printf(" 0xaa"); flush();
348         if (!ao_storage_fill_check_block(pos, 0xaa))
349                 return 0;
350         ao_storage_erase(pos, ao_storage_block);
351         printf(" 0x55"); flush();
352         if (!ao_storage_fill_check_block(pos, 0x55))
353                 return 0;
354         ao_storage_erase(pos, ao_storage_block);
355         printf(" increment"); flush();
356         if (!ao_storage_incr_check_block(pos))
357                 return 0;
358         ao_storage_erase(pos, ao_storage_block);
359         printf(" pass\n"); flush();
360         return 1;
361 }
362
363 static void
364 ao_storage_test(void) 
365 {
366         uint32_t        pos;
367
368         ao_cmd_white();
369         if (!ao_match_word("DoIt"))
370                 return;
371         for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block) {
372                 printf("Testing block 0x%08x:", pos); flush();
373                 if (!ao_storage_test_block(pos))
374                         break;
375         }
376         printf("Test complete\n");
377 }
378
379 static void
380 ao_storage_fill(void)
381 {
382         uint32_t        pos;
383
384         ao_cmd_white();
385         if (!ao_match_word("DoIt"))
386                 return;
387         printf("erase "); flush();
388         ao_storage_erase(0, ao_storage_log_max);
389         for (pos = 0; pos < sizeof (storage_test); pos++)
390                 storage_test[pos] = (uint8_t) pos;
391         for (pos = 0; pos < ao_storage_log_max; pos += sizeof (storage_test)) {
392                 if ((pos & 0xffff) == 0) {
393                         printf("Fill 0x%x\n", pos); flush();
394                 }
395                 ao_storage_write(pos, storage_test, sizeof (storage_test));
396         }
397         printf("Fill complete\n");
398 }
399 #endif /* AO_STORAGE_TEST */
400
401 static void
402 ao_storage_info(void) 
403 {
404         ao_storage_setup();
405         printf("Storage size: %ld\n", (long) ao_storage_total);
406         printf("Storage erase unit: %ld\n", (long) ao_storage_block);
407         ao_storage_device_info();
408 }
409
410 const struct ao_cmds ao_storage_cmds[] = {
411         { ao_storage_info, "f\0Show storage" },
412         { ao_storage_dump, "e <block>\0Dump flash" },
413 #if HAS_STORAGE_DEBUG
414         { ao_storage_store, "w <block> <start> <len> <data> ...\0Write data to flash" },
415 #endif
416         { ao_storage_zap, "z <block>\0Erase <block>" },
417         { ao_storage_zapall,"Z <key>\0Erase all. <key> is doit with D&I" },
418 #if AO_STORAGE_TEST
419         { ao_storage_test, "V <key>\0Validate flash (destructive). <key> is doit with D&I" },
420         { ao_storage_fill, "F <key>\0Fill flash with data. <key> is doit with D&I" },
421 #endif
422         { 0, NULL },
423 };
424
425 void
426 ao_storage_init(void)
427 {
428         ao_storage_device_init();
429         ao_cmd_register(&ao_storage_cmds[0]);
430 }