1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** FileX Component */
16 /** */
17 /** Utility */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define FX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "fx_api.h"
28 #include "fx_system.h"
29 #include "fx_utility.h"
30 #ifdef FX_ENABLE_FAULT_TOLERANT
31 #include "fx_fault_tolerant.h"
32 #endif /* FX_ENABLE_FAULT_TOLERANT */
33
34
35 /**************************************************************************/
36 /* */
37 /* FUNCTION RELEASE */
38 /* */
39 /* _fx_utility_FAT_entry_write PORTABLE C */
40 /* 6.1 */
41 /* AUTHOR */
42 /* */
43 /* William E. Lamie, Microsoft Corporation */
44 /* */
45 /* DESCRIPTION */
46 /* */
47 /* This function writes to the supplied FAT entry to all FATs in */
48 /* the media. 12-bit, 16-bit, and 32-bit FAT writing is supported. */
49 /* */
50 /* INPUT */
51 /* */
52 /* media_ptr Media control block pointer */
53 /* cluster Cluster entry number */
54 /* next_cluster Next cluster integer pointer */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* return status */
59 /* */
60 /* CALLS */
61 /* */
62 /* _fx_utility_FAT_flush FLUSH dirty entries in the */
63 /* FAT cache */
64 /* _fx_fault_tolerant_add_fat_log Add FAT redo log */
65 /* */
66 /* CALLED BY */
67 /* */
68 /* FileX System Functions */
69 /* */
70 /* RELEASE HISTORY */
71 /* */
72 /* DATE NAME DESCRIPTION */
73 /* */
74 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
75 /* 09-30-2020 William E. Lamie Modified comment(s), */
76 /* resulting in version 6.1 */
77 /* */
78 /**************************************************************************/
_fx_utility_FAT_entry_write(FX_MEDIA * media_ptr,ULONG cluster,ULONG next_cluster)79 UINT _fx_utility_FAT_entry_write(FX_MEDIA *media_ptr, ULONG cluster, ULONG next_cluster)
80 {
81
82 UINT status, index, i;
83 FX_FAT_CACHE_ENTRY *cache_entry_ptr;
84 #ifdef FX_ENABLE_FAULT_TOLERANT
85 ULONG FAT_sector;
86
87 /* While fault_tolerant is enabled, only FAT entries in the same sector are allowed to be cached. */
88 /* We must flush FAT sectors in the order of FAT chains. */
89 if (media_ptr -> fx_media_fault_tolerant_enabled &&
90 (media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_STARTED))
91 {
92
93 if (!(media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN))
94 {
95
96 /* Redirect this request to log file. */
97 return(_fx_fault_tolerant_add_FAT_log(media_ptr, cluster, next_cluster));
98 }
99
100 /* Get sector number of the incoming FAT entry. */
101 FAT_sector = _fx_utility_FAT_sector_get(media_ptr, cluster);
102
103 /* Is FAT sector changed? */
104 if (FAT_sector != media_ptr -> fx_media_fault_tolerant_cached_FAT_sector)
105 {
106
107 /* Are there any cached FAT entries? */
108 if (media_ptr -> fx_media_fault_tolerant_cached_FAT_sector)
109 {
110
111 /* Current FAT entry is located in different sector. Force flush. */
112 /* Flush the cached individual FAT entries */
113 _fx_utility_FAT_flush(media_ptr);
114
115 }
116
117 /* Record sector number of current FAT entry. */
118 media_ptr -> fx_media_fault_tolerant_cached_FAT_sector = FAT_sector;
119 }
120 }
121 #endif /* FX_ENABLE_FAULT_TOLERANT */
122
123 #ifndef FX_MEDIA_STATISTICS_DISABLE
124 /* Increment the number of FAT entry writes and cache hits. */
125 media_ptr -> fx_media_fat_entry_writes++;
126 media_ptr -> fx_media_fat_entry_cache_write_hits++;
127 #endif
128
129 /* Extended port-specific processing macro, which is by default defined to white space. */
130 FX_UTILITY_FAT_ENTRY_WRITE_EXTENSION
131
132 /* Calculate the area of the cache for this FAT entry. */
133 index = (cluster & FX_FAT_CACHE_HASH_MASK) * FX_FAT_CACHE_DEPTH;
134
135 /* Build a pointer to the cache entry. */
136 cache_entry_ptr = &media_ptr -> fx_media_fat_cache[index];
137
138 /* First search for the entry in the FAT entry cache. */
139 for (i = 0; i < FX_FAT_CACHE_DEPTH; i++)
140 {
141
142 /* See if the entry matches the write request. */
143 if (((cache_entry_ptr + i) -> fx_fat_cache_entry_cluster) == cluster)
144 {
145
146 /* Yes, we have a matching entry. Save the new information in the FAT
147 cache and mark this entry as dirty. */
148 (cache_entry_ptr + i) -> fx_fat_cache_entry_value = next_cluster;
149 (cache_entry_ptr + i) -> fx_fat_cache_entry_dirty = 1;
150
151 /* Determine if the driver has requested notification when data sectors in the media
152 become free. This can be useful to FLASH manager software. */
153 if ((media_ptr -> fx_media_driver_free_sector_update) && (next_cluster == FX_FREE_CLUSTER))
154 {
155
156 /* Yes, the driver does wish to know that these specific sector(s) are
157 not in use. */
158
159 #ifndef FX_MEDIA_STATISTICS_DISABLE
160
161 /* Increment the number of driver release sectors requests. */
162 media_ptr -> fx_media_driver_release_sectors_requests++;
163 #endif
164
165 /* This cluster is being released so inform the driver that the
166 corresponding sectors are now available. */
167 media_ptr -> fx_media_driver_request = FX_DRIVER_RELEASE_SECTORS;
168 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
169 media_ptr -> fx_media_driver_logical_sector = (media_ptr -> fx_media_data_sector_start +
170 ((cluster - FX_FAT_ENTRY_START) * media_ptr -> fx_media_sectors_per_cluster));
171 media_ptr -> fx_media_driver_sectors = media_ptr -> fx_media_sectors_per_cluster;
172
173 /* If trace is enabled, insert this event into the trace buffer. */
174 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_RELEASE_SECTORS, media_ptr, media_ptr -> fx_media_driver_logical_sector, media_ptr -> fx_media_driver_sectors, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
175
176 /* Call the driver. */
177 (media_ptr -> fx_media_driver_entry)(media_ptr);
178 }
179
180 /* Done, return successful status. */
181 return(FX_SUCCESS);
182 }
183 }
184
185 /* If we reach this point, we know that the FAT write request is not in
186 the cache. */
187
188 #ifndef FX_MEDIA_STATISTICS_DISABLE
189 /* Decrement the number of cache hits. */
190 media_ptr -> fx_media_fat_entry_cache_write_hits--;
191
192 /* Increment the number of cache misses. */
193 media_ptr -> fx_media_fat_entry_cache_write_misses++;
194 #endif
195
196 /* Determine if the oldest entry is dirty and needs to be flushed. */
197 if (media_ptr -> fx_media_fat_cache[index + 3].fx_fat_cache_entry_dirty == 1)
198 {
199
200 /* Flush the dirty entry so it can be used to hold the current
201 FAT entry write request. */
202 status = _fx_utility_FAT_flush(media_ptr);
203
204 /* Determine if the write was successful. */
205 if (status != FX_SUCCESS)
206 {
207
208 /* No, return error status to caller. */
209 return(status);
210 }
211
212 }
213
214 /* Move all the cache entries down so the oldest is at the bottom. */
215 *(cache_entry_ptr + 3) = *(cache_entry_ptr + 2);
216 *(cache_entry_ptr + 2) = *(cache_entry_ptr + 1);
217 *(cache_entry_ptr + 1) = *(cache_entry_ptr);
218
219 /* Save the current FAT entry write request and mark as dirty. */
220 cache_entry_ptr -> fx_fat_cache_entry_dirty = 1;
221 cache_entry_ptr -> fx_fat_cache_entry_cluster = cluster;
222 cache_entry_ptr -> fx_fat_cache_entry_value = next_cluster;
223
224 /* Determine if the driver has requested notification when data sectors in the media
225 become free. This can be useful to FLASH manager software. */
226 if ((media_ptr -> fx_media_driver_free_sector_update) && (next_cluster == FX_FREE_CLUSTER))
227 {
228
229 /* Yes, the driver does wish to know that these specific sector(s) are
230 not in use. */
231
232 #ifndef FX_MEDIA_STATISTICS_DISABLE
233
234 /* Increment the number of driver release sectors requests. */
235 media_ptr -> fx_media_driver_release_sectors_requests++;
236 #endif
237
238 /* This cluster is being released so inform the driver that the
239 corresponding sectors are now available. */
240 media_ptr -> fx_media_driver_request = FX_DRIVER_RELEASE_SECTORS;
241 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
242 media_ptr -> fx_media_driver_logical_sector = (media_ptr -> fx_media_data_sector_start +
243 ((cluster - FX_FAT_ENTRY_START) * media_ptr -> fx_media_sectors_per_cluster));
244 media_ptr -> fx_media_driver_sectors = media_ptr -> fx_media_sectors_per_cluster;
245
246 /* If trace is enabled, insert this event into the trace buffer. */
247 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_RELEASE_SECTORS, media_ptr, media_ptr -> fx_media_driver_logical_sector, media_ptr -> fx_media_driver_sectors, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
248
249 /* Call the driver. */
250 (media_ptr -> fx_media_driver_entry)(media_ptr);
251 }
252
253 /* Return success to caller. */
254 return(FX_SUCCESS);
255 }
256
257