yaffsfs: Add commenting for OS glue interface
[yaffs2.git] / direct / test-framework / nandstore_file.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2010-2011 Aleph One Ltd.
5  *
6  * Created by Charles Manning <charles@aleph1.co.uk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12 /*
13  * Nand simulator modelled on a Samsung K9K2G08U0A 8-bit
14  *
15  *  Need to implement basic commands first:
16  *  Status
17  *  Reset
18  *  Read
19  *  Random read (ie set read position within current page)
20  *  Write
21  *  Erase
22  */
23
24 #include "nandstore_file.h"
25 #include "nand_store.h"
26 #include <stdint.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 extern int random_seed;
34 extern int simulate_power_failure;
35 static int remaining_ops;
36 static int nops_so_far;
37
38 struct nandstore_file_private {
39         char backing_file[500];
40         int handle;
41         unsigned char * buffer;
42         int buff_size;
43 };
44
45 static void maybe_power_fail(unsigned int nand_chunk, int fail_point)
46 {
47
48    nops_so_far++;
49
50    remaining_ops--;
51    if(simulate_power_failure &&
52       remaining_ops < 1){
53        printf("Simulated power failure after %d operations\n",nops_so_far);
54        printf("  power failed on nand_chunk %d, at fail point %d\n",
55                         nand_chunk, fail_point);
56         exit(0);
57   }
58 }
59
60 static void power_fail_init(void)
61 {
62         remaining_ops = (rand() % 1000) * 5;
63 }
64
65 static int nandstore_file_store(struct nand_store *this, int page,
66                                 const unsigned char * buffer)
67 {
68         struct nandstore_file_private *nsfp =
69                 (struct nandstore_file_private *)this->private_data;
70         int pos = nsfp->buff_size * page;
71         int i;
72
73         maybe_power_fail(page, __LINE__);
74
75         lseek(nsfp->handle, pos, SEEK_SET);
76         read(nsfp->handle, nsfp->buffer, nsfp->buff_size);
77         for(i = 0; i < nsfp->buff_size; i++)
78                 nsfp->buffer[i] &= buffer[i];
79         lseek(nsfp->handle, pos, SEEK_SET);
80         write(nsfp->handle, nsfp->buffer, nsfp->buff_size);
81
82         maybe_power_fail(page, __LINE__);
83
84         return 0;
85 }
86
87 static int nandstore_file_retrieve(struct nand_store *this, int page,
88                                 unsigned char * buffer)
89 {
90         struct nandstore_file_private *nsfp =
91                 (struct nandstore_file_private *)this->private_data;
92
93         lseek(nsfp->handle, nsfp->buff_size * page, SEEK_SET);
94         read(nsfp->handle, buffer, nsfp->buff_size);
95         return 0;
96 }
97 static int nandstore_file_erase(struct nand_store *this, int page)
98 {
99         int block = page / this->pages_per_block;
100         struct nandstore_file_private *nsfp =
101                 (struct nandstore_file_private *)this->private_data;
102         int i;
103
104         maybe_power_fail(page, __LINE__);
105
106         lseek(nsfp->handle,
107                 block * nsfp->buff_size * this->pages_per_block, SEEK_SET);
108         memset(nsfp->buffer, 0xff, nsfp->buff_size);
109         for(i = 0; i < this->pages_per_block; i++)
110                 write(nsfp->handle, nsfp->buffer, nsfp->buff_size);
111         return 0;
112 }
113
114 static int nandstore_file_shutdown(struct nand_store *this)
115 {
116         struct nandstore_file_private *nsfp =
117                 (struct nandstore_file_private *)this->private_data;
118         close(nsfp->handle);
119         nsfp->handle = -1;
120         return 0;
121 }
122
123 struct nand_store *
124 nandstore_file_init(const char *fname,
125                                 int blocks,
126                                 int pages_per_block,
127                                 int data_bytes_per_page,
128                                 int spare_bytes_per_page)
129 {
130         int fsize;
131         int nbytes;
132         int i;
133         struct nand_store *ns;
134         struct nandstore_file_private *nsfp;
135         unsigned char *buffer;
136         int buff_size = data_bytes_per_page + spare_bytes_per_page;
137
138         ns = malloc(sizeof(struct nand_store));
139         nsfp = malloc(sizeof(struct nandstore_file_private));
140         buffer = malloc(buff_size);
141
142
143         if (!ns || !nsfp || !buffer) {
144                 free(ns);
145                 free(nsfp);
146                 free(buffer);
147                 return NULL;
148         }
149
150         memset(ns, 0, sizeof(*ns));
151         memset(nsfp, 0, sizeof(*nsfp));
152         nsfp->buffer = buffer;
153         nsfp->buff_size = buff_size;
154         ns->private_data = nsfp;
155
156         ns->store = nandstore_file_store;
157         ns->retrieve = nandstore_file_retrieve;
158         ns->erase = nandstore_file_erase;
159         ns->shutdown = nandstore_file_shutdown;
160
161         ns->blocks = blocks;
162         ns->pages_per_block = pages_per_block;
163         ns->data_bytes_per_page = data_bytes_per_page;
164         ns->spare_bytes_per_page = spare_bytes_per_page;
165
166         strncpy(nsfp->backing_file, fname, sizeof(nsfp->backing_file));
167
168         nsfp->handle = open(nsfp->backing_file, O_RDWR | O_CREAT, 0666);
169         if(nsfp->handle >=0){
170                 fsize = lseek(nsfp->handle,0,SEEK_END);
171                 nbytes = ns->blocks * ns->pages_per_block *
172                         (ns->data_bytes_per_page + ns->spare_bytes_per_page);
173                 if (fsize != nbytes) {
174                         printf("Initialising backing file.\n");
175                         ftruncate(nsfp->handle,0);
176                         for(i = 0; i < ns->blocks; i++)
177                                 nandstore_file_erase(ns,
178                                         i * ns->pages_per_block);
179                 }
180         }
181
182         power_fail_init();
183
184         return ns;
185
186
187 }
188