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