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_read PORTABLE C */
40 /* 6.2.0 */
41 /* AUTHOR */
42 /* */
43 /* William E. Lamie, Microsoft Corporation */
44 /* */
45 /* DESCRIPTION */
46 /* */
47 /* This function handles logical sector read requests for all FileX */
48 /* components. If the logical sector is currently in the logical */
49 /* sector cache, the function simply sets the appropriate pointer and */
50 /* returns a successful status to the caller. Otherwise, physical I/O */
51 /* is requested through the 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 receiving buffer */
62 /* sectors Number of sectors to read */
63 /* sector_type Type of sector(s) to read */
64 /* */
65 /* OUTPUT */
66 /* */
67 /* return status */
68 /* */
69 /* CALLS */
70 /* */
71 /* _fx_utility_logical_sector_cache_entry_read */
72 /* Read logical sector cache */
73 /* _fx_utility_logical_sector_flush Flush and invalidate sectors */
74 /* that overlap with non-cache */
75 /* sector I/O. */
76 /* _fx_utility_memory_copy Copy cache sector */
77 /* _fx_fault_tolerant_read_directory_sector */
78 /* Read directory sector */
79 /* */
80 /* CALLED BY */
81 /* */
82 /* FileX System Functions */
83 /* */
84 /* RELEASE HISTORY */
85 /* */
86 /* DATE NAME DESCRIPTION */
87 /* */
88 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
89 /* 09-30-2020 William E. Lamie Modified comment(s), */
90 /* verified memcpy usage, and */
91 /* added conditional to */
92 /* disable cache, */
93 /* resulting in version 6.1 */
94 /* 04-02-2021 Bhupendra Naphade Modified comment(s), */
95 /* updated check for logical */
96 /* sector value, */
97 /* resulting in version 6.1.6 */
98 /* 10-31-2022 Tiejun Zhou Modified comment(s), */
99 /* fixed memory buffer when */
100 /* cache is disabled, */
101 /* resulting in version 6.2.0 */
102 /* */
103 /**************************************************************************/
_fx_utility_logical_sector_read(FX_MEDIA * media_ptr,ULONG64 logical_sector,VOID * buffer_ptr,ULONG sectors,UCHAR sector_type)104 UINT _fx_utility_logical_sector_read(FX_MEDIA *media_ptr, ULONG64 logical_sector,
105 VOID *buffer_ptr, ULONG sectors, UCHAR sector_type)
106 {
107 #ifndef FX_DISABLE_CACHE
108 FX_CACHED_SECTOR *cache_entry;
109 FX_CACHED_SECTOR *previous_cache_entry;
110 ULONG64 end_sector;
111 #endif /* FX_DISABLE_CACHE */
112
113 #ifdef FX_ENABLE_FAULT_TOLERANT
114 UINT status;
115 #endif /* FX_ENABLE_FAULT_TOLERANT */
116
117
118 #ifndef FX_MEDIA_STATISTICS_DISABLE
119
120 /* Determine if the request is for FAT sector. */
121 if (sector_type == FX_FAT_SECTOR)
122 {
123
124 /* Increment the number of FAT sector reads. */
125 media_ptr -> fx_media_fat_sector_reads++;
126 }
127
128 /* Increment the number of logical sectors read. */
129 media_ptr -> fx_media_logical_sector_reads++;
130 #endif
131
132 /* Extended port-specific processing macro, which is by default defined to white space. */
133 FX_UTILITY_LOGICAL_SECTOR_READ_EXTENSION
134
135 #ifndef FX_DISABLE_CACHE
136 /* Determine if the request is for the internal media buffer area. */
137 if ((((UCHAR *)buffer_ptr) >= media_ptr -> fx_media_memory_buffer) &&
138 (((UCHAR *)buffer_ptr) <= media_ptr -> fx_media_sector_cache_end))
139 {
140
141 /* Internal cache buffer is requested. */
142
143 /* Examine the logical sector cache. */
144 cache_entry = _fx_utility_logical_sector_cache_entry_read(media_ptr, logical_sector, &previous_cache_entry);
145
146 /* Was the sector found? */
147 if (cache_entry == FX_NULL)
148 {
149
150 /* Yes, the sector was found. Return success! */
151 return(FX_SUCCESS);
152 }
153
154 /* At this point, we need to read in a sector from the media. */
155
156 #ifndef FX_MEDIA_STATISTICS_DISABLE
157
158 /* Increment the number of logical sectors cache read misses. */
159 media_ptr -> fx_media_logical_sector_cache_read_misses++;
160 #endif
161
162 #ifndef FX_MEDIA_STATISTICS_DISABLE
163
164 /* If trace is enabled, insert this event into the trace buffer. */
165 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_LOG_SECTOR_CACHE_MISS, media_ptr, logical_sector, media_ptr -> fx_media_logical_sector_cache_read_misses, media_ptr -> fx_media_sector_cache_size, FX_TRACE_INTERNAL_EVENTS, 0, 0)
166 #else
167
168 /* If trace is enabled, insert this event into the trace buffer. */
169 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_LOG_SECTOR_CACHE_MISS, media_ptr, logical_sector, 0, media_ptr -> fx_media_sector_cache_size, FX_TRACE_INTERNAL_EVENTS, 0, 0)
170 #endif
171
172 /* First, check and see if the last used entry has been
173 modified. */
174 if ((cache_entry -> fx_cached_sector_valid) &&
175 (cache_entry -> fx_cached_sector_buffer_dirty))
176 {
177
178 /* Yes, we need to flush this buffer out to the physical media
179 before we read in the new buffer. */
180
181 #ifndef FX_MEDIA_STATISTICS_DISABLE
182
183 /* Increment the number of driver write sector(s) requests. */
184 media_ptr -> fx_media_driver_write_requests++;
185 #endif
186
187 /* Build write request to the driver. */
188 media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
189 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
190 media_ptr -> fx_media_driver_buffer = cache_entry -> fx_cached_sector_memory_buffer;
191 #ifdef FX_DRIVER_USE_64BIT_LBA
192 media_ptr -> fx_media_driver_logical_sector = cache_entry -> fx_cached_sector;
193 #else
194 media_ptr -> fx_media_driver_logical_sector = (ULONG)cache_entry -> fx_cached_sector;
195 #endif
196 media_ptr -> fx_media_driver_sectors = 1;
197 media_ptr -> fx_media_driver_sector_type = cache_entry -> fx_cached_sector_type;
198
199 /* Determine if the sector is a data sector or a system sector. */
200 if (cache_entry -> fx_cached_sector_type != FX_DATA_SECTOR)
201 {
202
203 /* System sector is present. */
204 media_ptr -> fx_media_driver_system_write = FX_TRUE;
205 }
206
207 /* If trace is enabled, insert this event into the trace buffer. */
208 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, cache_entry -> fx_cached_sector, 1, cache_entry -> fx_cached_sector_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0)
209
210 /* Invoke the driver to write the sector. */
211 (media_ptr -> fx_media_driver_entry) (media_ptr);
212
213 /* Clear the system write flag. */
214 media_ptr -> fx_media_driver_system_write = FX_FALSE;
215
216 /* Check for successful completion. */
217 if (media_ptr -> fx_media_driver_status)
218 {
219
220 /* Error writing a cached sector out. Return the
221 error status. */
222 return(media_ptr -> fx_media_driver_status);
223 }
224
225 /* Clear the buffer dirty flag since it has been flushed
226 out. */
227 cache_entry -> fx_cached_sector_buffer_dirty = FX_FALSE;
228
229 /* Decrement the number of outstanding dirty cache entries. */
230 media_ptr -> fx_media_sector_cache_dirty_count--;
231 }
232
233 /* At this point, we can go out and setup this cached sector
234 entry. */
235
236 /* Compare against logical sector to make sure it is valid. */
237 if (logical_sector >= media_ptr -> fx_media_total_sectors)
238 {
239 return(FX_SECTOR_INVALID);
240 }
241
242 #ifndef FX_MEDIA_STATISTICS_DISABLE
243
244 /* Increment the number of driver read sector(s) requests. */
245 media_ptr -> fx_media_driver_read_requests++;
246 #endif
247
248 /* Build Read request to the driver. */
249 media_ptr -> fx_media_driver_request = FX_DRIVER_READ;
250 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
251 media_ptr -> fx_media_driver_buffer = cache_entry -> fx_cached_sector_memory_buffer;
252 #ifdef FX_DRIVER_USE_64BIT_LBA
253 media_ptr -> fx_media_driver_logical_sector = logical_sector;
254 #else
255 media_ptr -> fx_media_driver_logical_sector = (ULONG)logical_sector;
256 #endif
257 media_ptr -> fx_media_driver_sectors = 1;
258 media_ptr -> fx_media_driver_sector_type = sector_type;
259
260 /* Determine if the sector is a data sector or a system sector. */
261 if (sector_type == FX_DATA_SECTOR)
262 {
263
264 /* Data sector is present. */
265 media_ptr -> fx_media_driver_data_sector_read = FX_TRUE;
266 }
267
268 /* If trace is enabled, insert this event into the trace buffer. */
269 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_READ, media_ptr, logical_sector, 1, cache_entry -> fx_cached_sector_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0)
270
271 /* Invoke the driver to read the sector. */
272 (media_ptr -> fx_media_driver_entry) (media_ptr);
273
274 /* Clear data sector is present flag. */
275 media_ptr -> fx_media_driver_data_sector_read = FX_FALSE;
276
277 /* Determine if the read was successful. */
278 if (media_ptr -> fx_media_driver_status == FX_SUCCESS)
279 {
280
281 /* Remember the sector number. */
282 cache_entry -> fx_cached_sector = logical_sector;
283
284 /* Make the cache entry valid. */
285 cache_entry -> fx_cached_sector_valid = FX_TRUE;
286
287 /* Remember the sector type. */
288 cache_entry -> fx_cached_sector_type = sector_type;
289
290 /* Place this entry that the head of the cached sector
291 list. */
292
293 /* Determine if we need to update the last used list. */
294 if (previous_cache_entry)
295 {
296
297 /* Yes, the current entry is not at the front of the list
298 so we need to change the order. */
299
300 /* Link the previous entry to this entry's next pointer. */
301 previous_cache_entry -> fx_cached_sector_next_used =
302 cache_entry -> fx_cached_sector_next_used;
303
304 /* Place this entry at the head of the list. */
305 cache_entry -> fx_cached_sector_next_used =
306 media_ptr -> fx_media_sector_cache_list_ptr;
307 media_ptr -> fx_media_sector_cache_list_ptr = cache_entry;
308 }
309
310 #ifdef FX_ENABLE_FAULT_TOLERANT
311 if (media_ptr -> fx_media_fault_tolerant_enabled &&
312 (media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_STARTED) &&
313 (sector_type == FX_DIRECTORY_SECTOR))
314 {
315
316 /* Read sector from log file. */
317 status = _fx_fault_tolerant_read_directory_sector(media_ptr, logical_sector, cache_entry -> fx_cached_sector_memory_buffer, 1);
318
319 /* Check for successful completion. */
320 if (status)
321 {
322
323 /* Return the error status. */
324 return(status);
325 }
326 }
327 #endif /* FX_ENABLE_FAULT_TOLERANT */
328 }
329 else
330 {
331
332 /* Invalidate the cache entry on read errors. */
333 cache_entry -> fx_cached_sector_valid = FX_FALSE;
334
335 /* Put all ones in the sector value. */
336 cache_entry -> fx_cached_sector = (~(ULONG64)0);
337 }
338
339 /* Simply setup the pointer to this buffer and return. */
340 media_ptr -> fx_media_memory_buffer = cache_entry -> fx_cached_sector_memory_buffer;
341
342 /* Return the driver status. */
343 return(media_ptr -> fx_media_driver_status);
344 }
345 #else
346 if ((logical_sector == media_ptr -> fx_media_memory_buffer_sector) && (sectors == 1) && (buffer_ptr == media_ptr -> fx_media_memory_buffer))
347 {
348 #ifdef FX_ENABLE_FAULT_TOLERANT
349 if (media_ptr -> fx_media_fault_tolerant_enabled &&
350 (media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_STARTED) &&
351 (sector_type == FX_DIRECTORY_SECTOR))
352 {
353
354 /* Read sector from log file. */
355 status = _fx_fault_tolerant_read_directory_sector(media_ptr, logical_sector, buffer_ptr, 1);
356
357 /* Check for successful completion. */
358 if (status)
359 {
360
361 /* Return the error status. */
362 return(status);
363 }
364 }
365 #endif /* FX_ENABLE_FAULT_TOLERANT */
366 return(FX_SUCCESS);
367 }
368 #endif
369 else
370 {
371
372 /* Direct I/O to application buffer area. */
373
374 /* Compare against logical sector to make sure it is valid. */
375 if ((logical_sector + sectors - 1) > (ULONG)media_ptr -> fx_media_total_sectors)
376 {
377 return(FX_SECTOR_INVALID);
378 }
379
380 #ifndef FX_DISABLE_CACHE
381 /* Attempt to fill the beginning of the buffer from cached sectors. */
382 while (sectors)
383 {
384
385 /* Determine if the sector is in the cache. */
386 if (_fx_utility_logical_sector_cache_entry_read(media_ptr, logical_sector, &previous_cache_entry))
387 {
388
389 /* Not in the cache - get out of the loop! */
390 break;
391 }
392
393 /* Yes, sector is in the cache. Copy the data from the cache to the destination buffer. */
394 _fx_utility_memory_copy(media_ptr -> fx_media_memory_buffer, buffer_ptr, media_ptr -> fx_media_bytes_per_sector); /* Use case of memcpy is verified. */
395
396 /* Advance the destination buffer. */
397 buffer_ptr = ((UCHAR *)buffer_ptr) + media_ptr -> fx_media_bytes_per_sector;
398
399 /* Advance the sector and decrement the number of sectors left. */
400 logical_sector++;
401 sectors--;
402 }
403
404 /* Calculate the end sector. */
405 end_sector = logical_sector + sectors - 1;
406
407 /* Attempt to fill the end of the buffer from the opposite direction. */
408 while (sectors)
409 {
410
411 /* Determine if the sector is in the cache. */
412 if (_fx_utility_logical_sector_cache_entry_read(media_ptr, end_sector, &previous_cache_entry))
413 {
414
415 /* Not in the cache - get out of the loop! */
416 break;
417 }
418
419 /* Yes, sector is in the cache. Copy the data from the cache to the destination buffer. */
420 _fx_utility_memory_copy(media_ptr -> fx_media_memory_buffer, /* Use case of memcpy is verified. */
421 ((UCHAR *)buffer_ptr) + ((sectors - 1) * media_ptr -> fx_media_bytes_per_sector),
422 media_ptr -> fx_media_bytes_per_sector);
423
424 /* Move sector to previous sector and decrement the number of sectors left. */
425 end_sector--;
426 sectors--;
427 }
428
429 /* Determine if there are still sectors left to read. */
430 if (sectors == 0)
431 {
432
433 /* No more sectors to read - return success! */
434 return(FX_SUCCESS);
435 }
436
437 /* Flush and invalidate any entries in the cache that are in this direct I/O read request range. */
438 _fx_utility_logical_sector_flush(media_ptr, logical_sector, (ULONG64) sectors, FX_TRUE);
439 #endif /* FX_DISABLE_CACHE */
440
441 #ifndef FX_MEDIA_STATISTICS_DISABLE
442
443 /* Increment the number of driver read sector(s) requests. */
444 media_ptr -> fx_media_driver_read_requests++;
445 #endif
446
447 /* Build read request to the driver. */
448 media_ptr -> fx_media_driver_request = FX_DRIVER_READ;
449 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
450 media_ptr -> fx_media_driver_buffer = buffer_ptr;
451 #ifdef FX_DRIVER_USE_64BIT_LBA
452 media_ptr -> fx_media_driver_logical_sector = logical_sector;
453 #else
454 media_ptr -> fx_media_driver_logical_sector = (ULONG)logical_sector;
455 #endif
456 media_ptr -> fx_media_driver_sectors = sectors;
457 media_ptr -> fx_media_driver_sector_type = sector_type;
458
459 /* Determine if the sector is a data sector or a system sector. */
460 if (sector_type == FX_DATA_SECTOR)
461 {
462
463 /* Data sector is present. */
464 media_ptr -> fx_media_driver_data_sector_read = FX_TRUE;
465 }
466
467 /* If trace is enabled, insert this event into the trace buffer. */
468 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_READ, media_ptr, logical_sector, sectors, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
469
470 /* Invoke the driver to read the sector. */
471 (media_ptr -> fx_media_driver_entry) (media_ptr);
472
473 /* Clear data sector is present flag. */
474 media_ptr -> fx_media_driver_data_sector_read = FX_FALSE;
475
476 #ifdef FX_DISABLE_CACHE
477 if ((media_ptr -> fx_media_driver_status == FX_SUCCESS) && (sectors == 1) && (buffer_ptr == media_ptr -> fx_media_memory_buffer))
478 {
479 media_ptr -> fx_media_memory_buffer_sector = logical_sector;
480 #ifdef FX_ENABLE_FAULT_TOLERANT
481 if (media_ptr -> fx_media_fault_tolerant_enabled &&
482 (media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_STARTED) &&
483 (sector_type == FX_DIRECTORY_SECTOR))
484 {
485
486 /* Read sector from log file. */
487 status = _fx_fault_tolerant_read_directory_sector(media_ptr, logical_sector, buffer_ptr, 1);
488
489 /* Check for successful completion. */
490 if (status)
491 {
492
493 /* Return the error status. */
494 return(status);
495 }
496 }
497 #endif /* FX_ENABLE_FAULT_TOLERANT */
498 return(FX_SUCCESS);
499 }
500 #endif /* FX_DISABLE_CACHE */
501
502 #ifndef FX_DISABLE_DIRECT_DATA_READ_CACHE_FILL
503
504 /* Determine if the read was successful and if number of sectors just read will
505 reasonably fit into the cache. */
506 if ((media_ptr -> fx_media_driver_status == FX_SUCCESS) && (sectors < (media_ptr -> fx_media_sector_cache_size / 4)))
507 {
508
509 /* Yes, read of direct sectors was successful. */
510
511 /* Copy the sectors directly read into the cache so they are available on
512 subsequent read requests. */
513 while (sectors)
514 {
515
516 /* Attempt to read the cache entry. */
517 cache_entry = _fx_utility_logical_sector_cache_entry_read(media_ptr, logical_sector, &previous_cache_entry);
518
519 /* Extended port-specific processing macro, which is by default defined to white space. */
520 FX_UTILITY_LOGICAL_SECTOR_READ_EXTENSION_1
521
522 /* At this point, a cache entry should always be present since we invalidated
523 the cache over this sector range previously. In any case, check for the error
524 condition. */
525 if (cache_entry == FX_NULL)
526 {
527
528 /* This case should never happen, however, if it does simply give up on updating the
529 cache with the sectors from the direct read. */
530 return(FX_SUCCESS);
531 }
532
533 /* Determine if the cache entry is dirty and needs to be written out before it is used. */
534 if ((cache_entry -> fx_cached_sector_valid) &&
535 (cache_entry -> fx_cached_sector_buffer_dirty))
536 {
537
538 /* Yes, we need to flush this buffer out to the physical media
539 before we read in the new buffer. */
540
541 #ifndef FX_MEDIA_STATISTICS_DISABLE
542
543 /* Increment the number of driver write sector(s) requests. */
544 media_ptr -> fx_media_driver_write_requests++;
545 #endif
546
547 /* Build write request to the driver. */
548 media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE;
549 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
550 media_ptr -> fx_media_driver_buffer = cache_entry -> fx_cached_sector_memory_buffer;
551 #ifdef FX_DRIVER_USE_64BIT_LBA
552 media_ptr -> fx_media_driver_logical_sector = cache_entry -> fx_cached_sector;
553 #else
554 media_ptr -> fx_media_driver_logical_sector = (ULONG)cache_entry -> fx_cached_sector;
555 #endif
556 media_ptr -> fx_media_driver_sectors = 1;
557 media_ptr -> fx_media_driver_sector_type = cache_entry -> fx_cached_sector_type;
558
559 /* Only data sectors may be dirty when FX_FAULT_TOLERANT is defined */
560 #ifndef FX_FAULT_TOLERANT
561 /* Determine if the sector is a data sector or a system sector. */
562 if (cache_entry -> fx_cached_sector_type != FX_DATA_SECTOR)
563 {
564
565 /* System sector is present. */
566 media_ptr -> fx_media_driver_system_write = FX_TRUE;
567 }
568 #endif /* FX_FAULT_TOLERANT */
569
570 /* If trace is enabled, insert this event into the trace buffer. */
571 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, cache_entry -> fx_cached_sector, 1, cache_entry -> fx_cached_sector_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0)
572
573 /* Invoke the driver to write the sector. */
574 (media_ptr -> fx_media_driver_entry) (media_ptr);
575
576 /* Clear the system write flag. */
577 media_ptr -> fx_media_driver_system_write = FX_FALSE;
578
579 /* Check for successful completion. */
580 if (media_ptr -> fx_media_driver_status)
581 {
582
583 /* Error writing a cached sector out. Return the
584 error status. */
585 return(media_ptr -> fx_media_driver_status);
586 }
587
588 /* Clear the buffer dirty flag since it has been flushed
589 out. */
590 cache_entry -> fx_cached_sector_buffer_dirty = FX_FALSE;
591
592 /* Decrement the number of outstanding dirty cache entries. */
593 media_ptr -> fx_media_sector_cache_dirty_count--;
594 }
595
596 /* Now setup the cache entry with information from the new sector. */
597
598 /* Remember the sector number. */
599 cache_entry -> fx_cached_sector = logical_sector;
600
601 /* Make the cache entry valid. */
602 cache_entry -> fx_cached_sector_valid = FX_TRUE;
603
604 /* Remember the sector type. */
605 cache_entry -> fx_cached_sector_type = sector_type;
606
607 /* Place this entry that the head of the cached sector
608 list. */
609
610 /* Determine if we need to update the last used list. */
611 if (previous_cache_entry)
612 {
613
614 /* Yes, the current entry is not at the front of the list
615 so we need to change the order. */
616
617 /* Link the previous entry to this entry's next pointer. */
618 previous_cache_entry -> fx_cached_sector_next_used =
619 cache_entry -> fx_cached_sector_next_used;
620
621 /* Place this entry at the head of the list. */
622 cache_entry -> fx_cached_sector_next_used =
623 media_ptr -> fx_media_sector_cache_list_ptr;
624 media_ptr -> fx_media_sector_cache_list_ptr = cache_entry;
625 }
626
627 /* Copy the data from the destination buffer to the cache entry. */
628 _fx_utility_memory_copy(buffer_ptr, /* Use case of memcpy is verified. */
629 cache_entry -> fx_cached_sector_memory_buffer,
630 media_ptr -> fx_media_bytes_per_sector);
631
632 /* Advance the destination buffer. */
633 buffer_ptr = ((UCHAR *)buffer_ptr) + media_ptr -> fx_media_bytes_per_sector;
634
635 /* Advance the source sector and decrement the sector count. */
636 logical_sector++;
637 sectors--;
638 }
639 }
640 #endif
641
642 /* Return the driver status. */
643 return(media_ptr -> fx_media_driver_status);
644 }
645 }
646
647