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_logical_sector_write PORTABLE C */
40 /* 6.1.6 */
41 /* AUTHOR */
42 /* */
43 /* William E. Lamie, Microsoft Corporation */
44 /* */
45 /* DESCRIPTION */
46 /* */
47 /* This function handles logical sector write requests for all FileX */
48 /* components. If the logical sector is currently in the media's */
49 /* buffer supplied by the caller, the function simply marks the buffer */
50 /* as written to. Otherwise, physical I/O is requested through the */
51 /* corresponding I/O driver. */
52 /* */
53 /* Note: Conversion of the logical sector is done inside the driver. */
54 /* This results in a performance boost for FLASH or RAM media */
55 /* devices. */
56 /* */
57 /* INPUT */
58 /* */
59 /* media_ptr Media control block pointer */
60 /* logical_sector Logical sector number */
61 /* buffer_ptr Pointer of sector buffer */
62 /* sectors Number of sectors to write */
63 /* sector_type Type of sector(s) to write */
64 /* */
65 /* OUTPUT */
66 /* */
67 /* return status */
68 /* */
69 /* CALLS */
70 /* */
71 /* _fx_utility_logical_sector_flush Flush and invalidate sectors */
72 /* that overlap with non-cache */
73 /* sector I/O. */
74 /* I/O Driver */
75 /* */
76 /* CALLED BY */
77 /* */
78 /* FileX System Functions */
79 /* */
80 /* RELEASE HISTORY */
81 /* */
82 /* DATE NAME DESCRIPTION */
83 /* */
84 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
85 /* 09-30-2020 William E. Lamie Modified comment(s), and */
86 /* added conditional to */
87 /* disable cache, */
88 /* resulting in version 6.1 */
89 /* 04-02-2021 Bhupendra Naphade Modified comment(s), */
90 /* updated check for logical */
91 /* sector value, */
92 /* resulting in version 6.1.6 */
93 /* */
94 /**************************************************************************/
_fx_utility_logical_sector_write(FX_MEDIA * media_ptr,ULONG64 logical_sector,VOID * buffer_ptr,ULONG sectors,UCHAR sector_type)95 UINT _fx_utility_logical_sector_write(FX_MEDIA *media_ptr, ULONG64 logical_sector,
96 VOID *buffer_ptr, ULONG sectors, UCHAR sector_type)
97 {
98
99 #ifndef FX_DISABLE_CACHE
100 FX_CACHED_SECTOR *cache_entry;
101 UINT cache_size;
102 UINT index;
103 UINT i;
104 UCHAR cache_found = FX_FALSE;
105 #endif /* FX_DISABLE_CACHE */
106
107 #ifndef FX_MEDIA_STATISTICS_DISABLE
108
109 /* Determine if the request is for FAT sector. */
110 if (sector_type == FX_FAT_SECTOR)
111 {
112
113 /* Increment the number of FAT sector writes. */
114 media_ptr -> fx_media_fat_sector_writes++;
115 }
116
117 /* Increment the number of logical sectors written. */
118 media_ptr -> fx_media_logical_sector_writes++;
119 #endif
120
121 /* Extended port-specific processing macro, which is by default defined to white space. */
122 FX_UTILITY_LOGICAL_SECTOR_WRITE_EXTENSION
123
124 #ifndef FX_DISABLE_CACHE
125 /* Determine if the request is from the internal media buffer area. */
126 if ((((UCHAR *)buffer_ptr) >= media_ptr -> fx_media_memory_buffer) &&
127 (((UCHAR *)buffer_ptr) <= media_ptr -> fx_media_sector_cache_end))
128 {
129
130 /* Internal cache buffer is requested. */
131
132 /* Determine if the logical sector cache access should use the hash function. */
133 if (media_ptr -> fx_media_sector_cache_hashed)
134 {
135
136 /* Calculate the area of the cache for this logical sector. */
137 index = (ULONG)(logical_sector & media_ptr -> fx_media_sector_cache_hash_mask) * FX_SECTOR_CACHE_DEPTH;
138
139 /* Build a pointer to the cache entry. */
140 cache_entry = &(media_ptr -> fx_media_sector_cache[index]);
141
142 for (i = 0; i < FX_SECTOR_CACHE_DEPTH; i++, cache_entry++)
143 {
144
145
146 /* Determine if the logical sector is in the cache - assuming the depth of the
147 sector cache is 4 entries. */
148 if ((cache_entry -> fx_cached_sector_valid) && (cache_entry -> fx_cached_sector == logical_sector))
149 {
150 cache_found = FX_TRUE;
151 break;
152 }
153 }
154 }
155 else
156 {
157
158 /* Search for an entry in the cache that matches this request. */
159 cache_size = media_ptr -> fx_media_sector_cache_size;
160 cache_entry = media_ptr -> fx_media_sector_cache_list_ptr;
161
162 /* Look at the cache entries until a match is found or the end of
163 the cache is reached. */
164 while (cache_size--)
165 {
166
167 /* Determine if the requested sector has been found. */
168 if ((cache_entry -> fx_cached_sector_valid) && (cache_entry -> fx_cached_sector == logical_sector))
169 {
170 cache_found = FX_TRUE;
171 break;
172 }
173
174 /* Otherwise, we have not found the cached entry yet. */
175
176 /* If there are more entries, move to the next one. */
177 if (cache_entry -> fx_cached_sector_next_used)
178 {
179
180 /* Move to the next cache entry. */
181 cache_entry = cache_entry -> fx_cached_sector_next_used;
182 }
183 }
184 }
185
186 #ifdef FX_ENABLE_FAULT_TOLERANT
187 if (media_ptr -> fx_media_fault_tolerant_enabled &&
188 (media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_STARTED) &&
189 (sector_type == FX_DATA_SECTOR) &&
190 !(cache_found && (cache_entry -> fx_cached_sector_memory_buffer == buffer_ptr)))
191 {
192
193 /* Special use case for file write when fault tolerant is enabled. */
194 /* Data are read from one sector but write to another sector. */
195 /* Need to invalidate both of original and new caches. */
196 if (cache_found)
197 {
198
199 /* Invalidate the new cache. */
200 cache_entry -> fx_cached_sector_valid = FX_FALSE;
201 cache_found = FX_FALSE;
202 }
203
204 /* Search for original cache. */
205 cache_size = media_ptr -> fx_media_sector_cache_size;
206 cache_entry = media_ptr -> fx_media_sector_cache_list_ptr;
207
208 /* Look at the cache entries until a match is found or the end of
209 the cache is reached. */
210 while (cache_size--)
211 {
212
213 /* Determine if the original sector has been found. */
214 if ((cache_entry -> fx_cached_sector_valid) &&
215 (cache_entry -> fx_cached_sector_memory_buffer == buffer_ptr))
216 {
217
218 /* Invalidate the original cache. */
219 cache_entry -> fx_cached_sector_valid = FX_FALSE;
220 break;
221 }
222
223 /* Otherwise, we have not found the cached entry yet. */
224
225 /* If there are more entries, move to the next one. */
226 if (cache_entry -> fx_cached_sector_next_used)
227 {
228
229 /* Move to the next cache entry. */
230 cache_entry = cache_entry -> fx_cached_sector_next_used;
231 }
232 }
233 }
234 #endif /* FX_ENABLE_FAULT_TOLERANT */
235
236 if (cache_found)
237 {
238
239 /* Yes, we found a match. */
240
241 #ifdef FX_FAULT_TOLERANT
242
243 /* Check for a system sector. Data sector fault tolerance is selected with
244 the FX_FAULT_TOLERANT_DATA option. */
245 if (sector_type != FX_DATA_SECTOR)
246 {
247
248 /* With the fault tolerant option enabled, system sectors are written immediately to
249 the media. */
250
251 #ifndef FX_MEDIA_STATISTICS_DISABLE
252
253 /* Increment the number of driver write sector(s) requests. */
254 media_ptr -> fx_media_driver_write_requests++;
255 #endif
256
257 /* Build write request to the driver. */
258 media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
259 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
260 media_ptr -> fx_media_driver_buffer = cache_entry -> fx_cached_sector_memory_buffer;
261 #ifdef FX_DRIVER_USE_64BIT_LBA
262 media_ptr -> fx_media_driver_logical_sector = logical_sector;
263 #else
264 media_ptr -> fx_media_driver_logical_sector = (ULONG)logical_sector;
265 #endif
266 media_ptr -> fx_media_driver_sectors = 1;
267 media_ptr -> fx_media_driver_sector_type = sector_type;
268
269 /* Yes, a system sector write is present so set the flag. The driver
270 can use this flag to make extra safeguards in writing the sector
271 out, yielding more fault tolerance. */
272 media_ptr -> fx_media_driver_system_write = FX_TRUE;
273
274 /* If trace is enabled, insert this event into the trace buffer. */
275 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, logical_sector, 1, cache_entry -> fx_cached_sector_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0)
276
277 /* Invoke the driver to write the sector(s). */
278 (media_ptr -> fx_media_driver_entry) (media_ptr);
279
280 /* Clear the system write flag. */
281 media_ptr -> fx_media_driver_system_write = FX_FALSE;
282
283 /* Return success. */
284 return(media_ptr -> fx_media_driver_status);
285 }
286 #endif
287
288 /* Determine if this is the first write of this logical sector. */
289 if (cache_entry -> fx_cached_sector_buffer_dirty == FX_FALSE)
290 {
291
292 /* Yes, increment the number of outstanding dirty sectors. */
293 media_ptr -> fx_media_sector_cache_dirty_count++;
294
295 /* Simply mark this entry as dirty. */
296 cache_entry -> fx_cached_sector_buffer_dirty = FX_TRUE;
297 }
298
299 /* Don't bother updating the cache linked list since writes are
300 preceded by reads anyway. */
301
302 /* Success, return to caller immediately! */
303 return(FX_SUCCESS);
304 }
305
306
307 /* Okay, so if we are here the request must be for the additional FAT writes, since this is the
308 only time a write request is made without a preceding read request. */
309
310 /* Is the logical sector valid? */
311 if ((logical_sector == 0) || (logical_sector == ((ULONG)0xFFFFFFFF)))
312 {
313 return(FX_SECTOR_INVALID);
314 }
315
316 /* Compare logical sector against total sectors to make sure it is valid. */
317 if ((logical_sector + sectors - 1) >= media_ptr -> fx_media_total_sectors)
318 {
319 return(FX_SECTOR_INVALID);
320 }
321
322 /* Just write the buffer to the media. */
323
324 #ifndef FX_MEDIA_STATISTICS_DISABLE
325
326 /* Increment the number of driver write sector(s) requests. */
327 media_ptr -> fx_media_driver_write_requests++;
328 #endif
329
330 /* Build write request to the driver. */
331 media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
332 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
333 media_ptr -> fx_media_driver_buffer = buffer_ptr;
334 #ifdef FX_DRIVER_USE_64BIT_LBA
335 media_ptr -> fx_media_driver_logical_sector = logical_sector;
336 #else
337 media_ptr -> fx_media_driver_logical_sector = (ULONG)logical_sector;
338 #endif
339 media_ptr -> fx_media_driver_sectors = sectors;
340 media_ptr -> fx_media_driver_sector_type = sector_type;
341
342 /* Determine if the system write flag needs to be set. */
343 if (sector_type != FX_DATA_SECTOR)
344 {
345
346 /* Yes, a system sector write is present so set the flag. The driver
347 can use this flag to make extra safeguards in writing the sector
348 out, yielding more fault tolerance. */
349 media_ptr -> fx_media_driver_system_write = FX_TRUE;
350 }
351
352 /* If trace is enabled, insert this event into the trace buffer. */
353 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, logical_sector, sectors, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
354
355 /* Invoke the driver to write the sector(s). */
356 (media_ptr -> fx_media_driver_entry) (media_ptr);
357
358 /* Clear the system write flag. */
359 media_ptr -> fx_media_driver_system_write = FX_FALSE;
360
361 /* Check for successful completion. */
362 if (media_ptr -> fx_media_driver_status)
363 {
364
365 /* Error writing a internal sector out. Return the
366 error status. */
367 return(media_ptr -> fx_media_driver_status);
368 }
369
370 /* At this point, we have a successful write. */
371 return(FX_SUCCESS);
372 }
373 else
374 #endif /* FX_DISABLE_CACHE */
375 {
376
377 /* Otherwise, the write request is being made directly from an application
378 buffer. Determine if the logical sector is valid. */
379
380 /* Is the logical sector valid? */
381 if ((logical_sector == 0) || (logical_sector == ((ULONG)0xFFFFFFFF)))
382 {
383 return(FX_SECTOR_INVALID);
384 }
385
386 /* Compare logical sector against total sectors to make sure it is valid. */
387 if ((logical_sector + sectors - 1) >= media_ptr -> fx_media_total_sectors)
388 {
389 return(FX_SECTOR_INVALID);
390 }
391
392 /* Flush and invalidate for any entries in the cache that are in this direct I/O read request range. */
393 _fx_utility_logical_sector_flush(media_ptr, logical_sector, (ULONG64) sectors, FX_TRUE);
394
395 #ifdef FX_DISABLE_CACHE
396 if ((logical_sector <= media_ptr -> fx_media_memory_buffer_sector) && (logical_sector + sectors >= media_ptr -> fx_media_memory_buffer_sector))
397 {
398 media_ptr -> fx_media_memory_buffer_sector = (ULONG64)-1;
399 }
400 #endif /* FX_DISABLE_CACHE */
401
402 #ifndef FX_MEDIA_STATISTICS_DISABLE
403
404 /* Increment the number of driver write sector(s) requests. */
405 media_ptr -> fx_media_driver_write_requests++;
406 #endif
407
408 /* Build request to the driver. */
409 media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
410 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
411 media_ptr -> fx_media_driver_buffer = buffer_ptr;
412 #ifdef FX_DRIVER_USE_64BIT_LBA
413 media_ptr -> fx_media_driver_logical_sector = logical_sector;
414 #else
415 media_ptr -> fx_media_driver_logical_sector = (ULONG)logical_sector;
416 #endif
417 media_ptr -> fx_media_driver_sectors = sectors;
418 media_ptr -> fx_media_driver_sector_type = sector_type;
419
420 /* Determine if the system write flag needs to be set. */
421 if (sector_type != FX_DATA_SECTOR)
422 {
423
424 /* Yes, a system sector write is present so set the flag. The driver
425 can use this flag to make extra safeguards in writing the sector
426 out, yielding more fault tolerance. */
427 media_ptr -> fx_media_driver_system_write = FX_TRUE;
428 }
429
430 /* If trace is enabled, insert this event into the trace buffer. */
431 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, logical_sector, sectors, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
432
433 /* Invoke the driver to write the sector(s). */
434 (media_ptr -> fx_media_driver_entry) (media_ptr);
435
436 /* Clear the system write flag. */
437 media_ptr -> fx_media_driver_system_write = FX_FALSE;
438
439 /* Return driver status. */
440 return(media_ptr -> fx_media_driver_status);
441 }
442 }
443
444