1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
10 /**************************************************************************/
11 
12 
13 /**************************************************************************/
14 /**************************************************************************/
15 /**                                                                       */
16 /** LevelX Component                                                      */
17 /**                                                                       */
18 /**   NOR Flash                                                           */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 #define LX_SOURCE_CODE
24 
25 
26 /* Disable ThreadX error checking.  */
27 
28 #ifndef LX_DISABLE_ERROR_CHECKING
29 #define LX_DISABLE_ERROR_CHECKING
30 #endif
31 
32 
33 /* Include necessary system files.  */
34 
35 #include "lx_api.h"
36 
37 
38 /**************************************************************************/
39 /*                                                                        */
40 /*  FUNCTION                                               RELEASE        */
41 /*                                                                        */
42 /*    _lx_nor_flash_open                                  PORTABLE C      */
43 /*                                                           6.3.0        */
44 /*  AUTHOR                                                                */
45 /*                                                                        */
46 /*    William E. Lamie, Microsoft Corporation                             */
47 /*                                                                        */
48 /*  DESCRIPTION                                                           */
49 /*                                                                        */
50 /*    This function opens a NOR flash instance and ensures the NOR flash  */
51 /*    is in a coherent state.                                             */
52 /*                                                                        */
53 /*  INPUT                                                                 */
54 /*                                                                        */
55 /*    nor_flash                             NOR flash instance            */
56 /*    name                                  Name of NOR flash instance    */
57 /*    nor_driver_initialize                 Driver initialize             */
58 /*                                                                        */
59 /*  OUTPUT                                                                */
60 /*                                                                        */
61 /*    return status                                                       */
62 /*                                                                        */
63 /*  CALLS                                                                 */
64 /*                                                                        */
65 /*    (nor_driver_initialize)               Driver initialize             */
66 /*    _lx_nor_flash_driver_read             Driver read                   */
67 /*    _lx_nor_flash_driver_write            Driver write                  */
68 /*    (lx_nor_flash_driver_block_erased_verify)                           */
69 /*                                          NOR flash verify block erased */
70 /*    _lx_nor_flash_driver_block_erase      Driver block erase            */
71 /*    _lx_nor_flash_logical_sector_find     Find logical sector           */
72 /*    _lx_nor_flash_system_error            System error handler          */
73 /*    tx_mutex_create                       Create thread-safe mutex      */
74 /*                                                                        */
75 /*  CALLED BY                                                             */
76 /*                                                                        */
77 /*    Application Code                                                    */
78 /*                                                                        */
79 /*  RELEASE HISTORY                                                       */
80 /*                                                                        */
81 /*    DATE              NAME                      DESCRIPTION             */
82 /*                                                                        */
83 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
84 /*  09-30-2020     William E. Lamie         Modified comment(s),          */
85 /*                                            resulting in version 6.1    */
86 /*  11-09-2020     William E. Lamie         Modified comment(s),          */
87 /*                                            fixed compiler warnings,    */
88 /*                                            resulting in version 6.1.2  */
89 /*  12-30-2020     William E. Lamie         Modified comment(s),          */
90 /*                                            fixed compiler warnings,    */
91 /*                                            resulting in version 6.1.3  */
92 /*  06-02-2021     Bhupendra Naphade        Modified comment(s), and      */
93 /*                                            updated product constants   */
94 /*                                            resulting in version 6.1.7  */
95 /*  03-08-2023     Xiuwen Cai               Modified comment(s),          */
96 /*                                            added new driver interface, */
97 /*                                            resulting in version 6.2.1  */
98 /*  10-31-2023     Xiuwen Cai               Modified comment(s),          */
99 /*                                            added count for minimum     */
100 /*                                            erased blocks, added        */
101 /*                                            obsolete count cache,       */
102 /*                                            avoided clearing user       */
103 /*                                            extension in flash control  */
104 /*                                            block,                      */
105 /*                                            resulting in version 6.3.0  */
106 /*                                                                        */
107 /**************************************************************************/
_lx_nor_flash_open(LX_NOR_FLASH * nor_flash,CHAR * name,UINT (* nor_driver_initialize)(LX_NOR_FLASH *))108 UINT  _lx_nor_flash_open(LX_NOR_FLASH  *nor_flash, CHAR *name, UINT (*nor_driver_initialize)(LX_NOR_FLASH *))
109 {
110 ULONG           sectors_per_block;
111 ULONG           sector_map_words;
112 ULONG           bit_map_words;
113 ULONG           bit_map_mask;
114 ULONG           total_header_words;
115 ULONG           header_sectors;
116 ULONG           *block_word_ptr;
117 ULONG           block_word;
118 ULONG           temp;
119 ULONG           free_sectors;
120 ULONG           used_sectors;
121 ULONG           *new_map_entry;
122 ULONG           *new_sector_address;
123 ULONG           erased_count, min_erased_count, max_erased_count, temp_erased_count, min_erased_blocks;
124 ULONG           j, k, l;
125 UINT            status;
126 #ifdef LX_FREE_SECTOR_DATA_VERIFY
127 ULONG           *sector_word_ptr;
128 ULONG           sector_word;
129 #endif
130 LX_NOR_FLASH   *tail_ptr;
131 LX_INTERRUPT_SAVE_AREA
132 
133     LX_PARAMETER_NOT_USED(name);
134 
135     /* Clear the NOR flash control block. User extension is not cleared.  */
136     LX_MEMSET(nor_flash, 0, (ULONG)((UCHAR*)&(nor_flash -> lx_nor_flash_open_previous) - (UCHAR*)nor_flash) + sizeof(nor_flash -> lx_nor_flash_open_previous));
137 
138     /* Call the flash driver's initialization function.  */
139     (nor_driver_initialize)(nor_flash);
140 
141 #ifndef LX_DIRECT_READ
142 
143     /* Determine if the driver supplied a RAM buffer for reading the NOR sector if direct read is not
144        supported.  */
145     if (nor_flash -> lx_nor_flash_sector_buffer == LX_NULL)
146     {
147 
148         /* Return an error.  */
149         return(LX_NO_MEMORY);
150     }
151 #endif
152 
153     /* Setup the offset to the free bit map.  */
154     nor_flash -> lx_nor_flash_block_free_bit_map_offset =  sizeof(LX_NOR_FLASH_BLOCK_HEADER)/sizeof(ULONG);
155 
156     /* Calculate the number of bits we need in the free physical sector bit map.  Subtract 1 to account for the
157        flash block header itself. The case where multiple physical sectors are needed for certain sized flash
158        devices is handled below.  */
159     sectors_per_block =  (nor_flash -> lx_nor_flash_words_per_block / LX_NOR_SECTOR_SIZE) - 1;
160 
161     /* Calculate the number of words required for the sector map array.  */
162     sector_map_words =  sectors_per_block;
163 
164     /* Calculate the number of words we need for the free physical sector bit map.  */
165     bit_map_words =  (sectors_per_block + 31)/ 32;
166 
167     /* Save the number of bit map words.  */
168     nor_flash -> lx_nor_flash_block_bit_map_words =  bit_map_words;
169 
170     /* Setup the offset (in words) to the array of physical sector mapping.  */
171     nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset =  nor_flash -> lx_nor_flash_block_free_bit_map_offset + bit_map_words;
172 
173     /* Calculate the total number of words required for the flash block header.  */
174     total_header_words =  sizeof(LX_NOR_FLASH_BLOCK_HEADER)/sizeof(ULONG) + bit_map_words + sector_map_words;
175 
176     /* Determine if more physical sectors are needed, which can happen on large devices.  */
177     if (total_header_words <= LX_NOR_SECTOR_SIZE)
178     {
179 
180         /* Round up to the size of 1 physical sector.  */
181         total_header_words =  LX_NOR_SECTOR_SIZE;
182     }
183     else
184     {
185 
186         /* Otherwise calculate how many header sectors are necessary.  */
187         header_sectors =  (total_header_words-1)/LX_NOR_SECTOR_SIZE;
188 
189         /* Round up to the next sector.  */
190         header_sectors++;
191 
192         /* Compute the total header words, rounding to the next sector.  */
193         total_header_words =  header_sectors * LX_NOR_SECTOR_SIZE;
194 
195         /* Adjust the number of sectors per block.  */
196         sectors_per_block =  sectors_per_block - (header_sectors - 1);
197     }
198 
199     /* Save the offset to the sector area.  */
200     nor_flash -> lx_nor_flash_block_physical_sector_offset =  total_header_words;
201 
202     /* Save the physical sectors per block and total physical sectors.  */
203     nor_flash -> lx_nor_flash_physical_sectors_per_block =  sectors_per_block;
204     nor_flash -> lx_nor_flash_total_physical_sectors =      nor_flash -> lx_nor_flash_total_blocks * sectors_per_block;
205 
206     /* Build the free bit map mask, for the portion of the bit map that is less than 32 bits.  */
207     if ((sectors_per_block % 32) != 0)
208     {
209         bit_map_mask =  (ULONG)(1 << (sectors_per_block % 32));
210         bit_map_mask =  bit_map_mask - 1;
211     }
212     else
213     {
214 
215         /* Exactly 32 sectors for the bit map mask.  */
216         bit_map_mask =  LX_ALL_ONES;
217     }
218 
219     /* Save the free bit map mask in the control block.  */
220     nor_flash -> lx_nor_flash_block_bit_map_mask =  bit_map_mask;
221 
222     /* Setup default values for the max/min erased counts.  */
223     min_erased_count =  LX_ALL_ONES;
224     min_erased_blocks = 0;
225     max_erased_count =  0;
226 
227     /* Setup the block word pointer to the first word of the first block, which is effectively the
228        flash base address.  */
229     block_word_ptr =  nor_flash -> lx_nor_flash_base_address;
230 
231     /* Loop through the blocks to determine the minimum and maximum erase count.  */
232     for (l = 0; l < nor_flash -> lx_nor_flash_total_blocks; l++)
233     {
234 
235         /* Pickup the first word of the block. If the flash manager has executed before, this word contains the
236            erase count for the block. Otherwise, if the word is 0xFFFFFFFF, this flash block was either erased
237            or this is the first time it was used.  */
238 #ifdef LX_DIRECT_READ
239 
240         /* Read the word directly.  */
241         block_word =  *block_word_ptr;
242 #else
243 
244 
245 
246         status =  _lx_nor_flash_driver_read(nor_flash, block_word_ptr, &block_word, 1);
247 
248         /* Check for an error from flash driver. Drivers should never return an error..  */
249         if (status)
250         {
251 
252             /* Call system error handler.  */
253             _lx_nor_flash_system_error(nor_flash, status);
254 
255             /* Return an error.  */
256             return(LX_ERROR);
257         }
258 #endif
259 
260         /* Is the block erased?  */
261         if (((block_word & LX_BLOCK_ERASED) != LX_BLOCK_ERASED) && (block_word != LX_BLOCK_ERASE_STARTED))
262         {
263 
264             /* No, valid block.  Isolate the erased count.  */
265             erased_count =  (block_word & LX_BLOCK_ERASE_COUNT_MASK);
266 
267             /* Is the erased count the minimum?  */
268             if (erased_count == min_erased_count)
269             {
270 
271                 /* Yes, increment the minimum erased block count.  */
272                 min_erased_blocks++;
273             }
274 
275             /* Is this the new minimum?  */
276             if (erased_count < min_erased_count)
277             {
278 
279                 /* Yes, remember the new minimum.  */
280                 min_erased_count =  erased_count;
281 
282                 /* Reset the minimum erased block count.  */
283                 min_erased_blocks =  1;
284             }
285 
286             /* Is this the new maximum?  */
287             if (erased_count > max_erased_count)
288             {
289 
290                 /* Yes, remember the new maximum.  */
291                 max_erased_count =  erased_count;
292             }
293         }
294 
295         /* Move to the next flash block.  */
296         block_word_ptr =  block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
297     }
298 
299     /* If we haven't found any erased counts, we can assume the flash is completely erased and needs to
300        be setup for the first time.  */
301     if (min_erased_count == LX_ALL_ONES)
302     {
303 
304         /* Indicate that this is the initial format.  */
305         nor_flash -> lx_nor_flash_diagnostic_initial_format =  LX_TRUE;
306 
307         /* Setup the block word pointer to the first word of the first block, which is effectively the
308            flash base address.  */
309         block_word_ptr =  nor_flash -> lx_nor_flash_base_address;
310 
311         /* Loop through the blocks to setup the flash the fist time.  */
312         for (l = 0; l < nor_flash -> lx_nor_flash_total_blocks; l++)
313         {
314 
315             /* Setup the free bit map that corresponds to the free physical sectors in this
316                block. Note that we only need to setup the portion of the free bit map that doesn't
317                have sectors associated with it.  */
318             status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr+(nor_flash -> lx_nor_flash_block_free_bit_map_offset + (bit_map_words-1)) , &bit_map_mask, 1);
319 
320             /* Check for an error from flash driver. Drivers should never return an error..  */
321             if (status)
322             {
323 
324                 /* Call system error handler.  */
325                 _lx_nor_flash_system_error(nor_flash, status);
326 
327                 /* Return an error.  */
328                 return(LX_ERROR);
329             }
330 
331             /* Setup the initial erase count to 1.  */
332             block_word =  ((ULONG) 1);
333 
334             /* Write the initial erase count for the block.  */
335             status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &block_word, 1);
336 
337             /* Check for an error from flash driver. Drivers should never return an error..  */
338             if (status)
339             {
340 
341                 /* Call system error handler.  */
342                 _lx_nor_flash_system_error(nor_flash, status);
343 
344                 /* Return an error.  */
345                 return(LX_ERROR);
346             }
347 
348             /* Update the overall minimum and maximum erase count.  */
349             nor_flash -> lx_nor_flash_minimum_erase_count =  1;
350             nor_flash -> lx_nor_flash_minimum_erased_blocks =  nor_flash -> lx_nor_flash_total_blocks;
351             nor_flash -> lx_nor_flash_maximum_erase_count =  1;
352 
353             /* Update the number of free physical sectors.  */
354             nor_flash -> lx_nor_flash_free_physical_sectors =   nor_flash -> lx_nor_flash_free_physical_sectors + sectors_per_block;
355 
356             /* Move to the next flash block.  */
357             block_word_ptr =  block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
358         }
359     }
360     else
361     {
362 
363         /* At this point, we have a previously managed flash structure. This needs to be traversed to prepare for the
364            current flash operation.  */
365 
366         /* Default the flash free sector search to an invalid value.  */
367         nor_flash -> lx_nor_flash_free_block_search =  nor_flash -> lx_nor_flash_total_blocks;
368 
369         /* Setup the block word pointer to the first word of the first block, which is effectively the
370            flash base address.  */
371         block_word_ptr =  nor_flash -> lx_nor_flash_base_address;
372 
373         /* Loop through the blocks.  */
374         for (l = 0; l < nor_flash -> lx_nor_flash_total_blocks; l++)
375         {
376 
377             /* First, determine if this block has a valid erase count.  */
378 #ifdef LX_DIRECT_READ
379 
380             /* Read the word directly.  */
381             block_word =  *block_word_ptr;
382 #else
383             status =  _lx_nor_flash_driver_read(nor_flash, block_word_ptr, &block_word, 1);
384 
385             /* Check for an error from flash driver. Drivers should never return an error..  */
386             if (status)
387             {
388 
389                 /* Call system error handler.  */
390                 _lx_nor_flash_system_error(nor_flash, status);
391 
392                 /* Return an error.  */
393                 return(LX_ERROR);
394             }
395 #endif
396 
397             /* Is the block erased?  */
398             if (((block_word & LX_BLOCK_ERASED) == LX_BLOCK_ERASED) || (block_word == LX_BLOCK_ERASE_STARTED))
399             {
400 
401                 /* This can happen if we were previously in the process of erasing the flash block and a
402                    power interruption occurs.  It should only occur once though. */
403 
404                 /* Is this the first time?  */
405                 if (nor_flash -> lx_nor_flash_diagnostic_erased_block)
406                 {
407 
408                     /* No, this is a potential format error, since this should only happen once in a given
409                        NOR flash format.  */
410                     _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
411 
412                     /* Return an error.  */
413                     return(LX_ERROR);
414                 }
415 
416                 /* Increment the erased block diagnostic.  */
417                 nor_flash -> lx_nor_flash_diagnostic_erased_block++;
418 
419                 /* Check to see if the block is erased. */
420 #ifdef LX_NOR_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
421                 status =  (nor_flash -> lx_nor_flash_driver_block_erased_verify)(nor_flash, l);
422 #else
423                 status =  (nor_flash -> lx_nor_flash_driver_block_erased_verify)(l);
424 #endif
425 
426                 /* Is the block completely erased?  */
427                 if (status != LX_SUCCESS)
428                 {
429 
430                     /* Is this the first time?  */
431                     if (nor_flash -> lx_nor_flash_diagnostic_re_erase_block)
432                     {
433 
434                         /* No, this is a potential format error, since this should only happen once in a given
435                            NOR flash format.  */
436                         _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
437 
438                         /* Return an error.  */
439                         return(LX_ERROR);
440                     }
441 
442                     /* Increment the erased block diagnostic.  */
443                     nor_flash -> lx_nor_flash_diagnostic_re_erase_block++;
444 
445                     /* No, the block is not fully erased, erase it again.  */
446                     status =  _lx_nor_flash_driver_block_erase(nor_flash, l, max_erased_count);
447 
448                     /* Check for an error from flash driver. Drivers should never return an error..  */
449                     if (status)
450                     {
451 
452                         /* Call system error handler.  */
453                         _lx_nor_flash_system_error(nor_flash, status);
454 
455                         /* Return an error.  */
456                         return(LX_ERROR);
457                     }
458                 }
459 
460                 /* Setup the free bit map that corresponds to the free physical sectors in this
461                    block. Note that we only need to setup the portion of the free bit map that doesn't
462                    have sectors associated with it.  */
463                 status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr+(nor_flash -> lx_nor_flash_block_free_bit_map_offset + (bit_map_words-1)) , &bit_map_mask, 1);
464 
465                 /* Check for an error from flash driver. Drivers should never return an error..  */
466                 if (status)
467                 {
468 
469                     /* Call system error handler.  */
470                     _lx_nor_flash_system_error(nor_flash, status);
471 
472                     /* Return an error.  */
473                     return(LX_ERROR);
474                 }
475 
476                 /* Write the initial erase count for the block with upper bit set.  */
477                 temp_erased_count =  (max_erased_count | LX_BLOCK_ERASED);
478                 status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &temp_erased_count, 1);
479 
480                 /* Check for an error from flash driver. Drivers should never return an error..  */
481                 if (status)
482                 {
483 
484                     /* Call system error handler.  */
485                     _lx_nor_flash_system_error(nor_flash, status);
486 
487                     /* Return an error.  */
488                     return(LX_ERROR);
489                 }
490 
491                 /* Write the final initial erase count for the block.  */
492                 status =  _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &max_erased_count, 1);
493 
494                 /* Check for an error from flash driver. Drivers should never return an error..  */
495                 if (status)
496                 {
497 
498                     /* Call system error handler.  */
499                     _lx_nor_flash_system_error(nor_flash, status);
500 
501                     /* Return an error.  */
502                     return(LX_ERROR);
503                 }
504 
505                 /* Update the number of free physical sectors.  */
506                 nor_flash -> lx_nor_flash_free_physical_sectors =   nor_flash -> lx_nor_flash_free_physical_sectors + sectors_per_block;
507             }
508             else
509             {
510 
511                 /* Calculate the number of free sectors from the free sector bit map.  */
512                 free_sectors =  0;
513                 for (j = 0; j < bit_map_words; j++)
514                 {
515 
516                     /* Read this word of the free sector bit map.  */
517 #ifdef LX_DIRECT_READ
518 
519                     /* Read the word directly.  */
520                     block_word =  *(block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j);
521 #else
522                     status =  _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j), &block_word, 1);
523 
524                     /* Check for an error from flash driver. Drivers should never return an error..  */
525                     if (status)
526                     {
527 
528                         /* Call system error handler.  */
529                         _lx_nor_flash_system_error(nor_flash, status);
530 
531                         /* Return an error.  */
532                         return(LX_ERROR);
533                     }
534 #endif
535 
536                     /* Count the number of set bits (free sectors).  */
537                     for (k = 0; k < 32; k++)
538                     {
539 
540                         /* Is this sector free?  */
541                         if (block_word & 1)
542                         {
543                             /* Yes, this sector is free, increment the free sectors count.  */
544                             free_sectors++;
545 
546                             /* Determine if we need to update the search pointer.  */
547                             if (nor_flash -> lx_nor_flash_free_block_search == nor_flash -> lx_nor_flash_total_blocks)
548                             {
549 
550                                 /* Remember the block with free sectors.  */
551                                 nor_flash -> lx_nor_flash_free_block_search =  l;
552                             }
553                         }
554 
555                         /* Shift down the free sector.  */
556                         block_word =  block_word >> 1;
557                     }
558                 }
559 
560                 /* Update the number of free physical sectors.  */
561                 nor_flash -> lx_nor_flash_free_physical_sectors =   nor_flash -> lx_nor_flash_free_physical_sectors + free_sectors;
562 
563                 /* We need to now examine the mapping list.  */
564 
565                 /* Calculate how many non-free sectors there are - this includes valid and obsolete sectors.  */
566                 used_sectors =  sectors_per_block - free_sectors;
567 
568                 /* Now walk the list of logical-physical sector mapping.  */
569                 for (j = 0; j < sectors_per_block; j++)
570                 {
571 
572                     /* Read this word of the sector mapping list.  */
573 #ifdef LX_DIRECT_READ
574 
575                     /* Read the word directly.  */
576                     block_word =  *(block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j);
577 #else
578                     status =  _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
579 
580                     /* Check for an error from flash driver. Drivers should never return an error..  */
581                     if (status)
582                     {
583 
584                         /* Call system error handler.  */
585                         _lx_nor_flash_system_error(nor_flash, status);
586 
587                         /* Return an error.  */
588                         return(LX_ERROR);
589                     }
590 #endif
591 
592                     /* Determine if we are expecting to find a used sector.   */
593                     if (used_sectors)
594                     {
595 
596                         /* Yes, we expect this entry to be used.  */
597 
598                         /* Is this sector in-use?  */
599                         if ((block_word & LX_NOR_LOGICAL_SECTOR_MASK) != LX_NOR_LOGICAL_SECTOR_MASK)
600                         {
601 
602                             /* Determine if the valid bit is set and the superceded bit is clear. This indicates the block was
603                                about to become obsolete.  */
604                             if ((block_word & LX_NOR_PHYSICAL_SECTOR_VALID) && ((block_word & LX_NOR_PHYSICAL_SECTOR_SUPERCEDED) == 0))
605                             {
606 
607 
608                                 /* Increment the being obsoleted count.  */
609                                 nor_flash -> lx_nor_flash_diagnostic_sector_being_obsoleted++;
610 
611                                 /* Save the currently mapped physical sectors.  */
612                                 temp =  nor_flash -> lx_nor_flash_mapped_physical_sectors;
613 
614                                 /* Indicate all the physical sectors are mapped for the purpose of this search.  */
615                                 nor_flash -> lx_nor_flash_mapped_physical_sectors =  nor_flash -> lx_nor_flash_total_physical_sectors;
616 
617                                 /* Yes, this block was about to become obsolete. Perform a search for a logical sector entry that
618                                    has both of these bits set.  */
619                                 _lx_nor_flash_logical_sector_find(nor_flash, (block_word & LX_NOR_LOGICAL_SECTOR_MASK), LX_TRUE, &new_map_entry, &new_sector_address);
620 
621                                 /* Restore the number of mapped physical sectors.  */
622                                 nor_flash -> lx_nor_flash_mapped_physical_sectors =  temp;
623 
624                                 /* Determine if the new logical sector entry is present.  */
625                                 if (new_map_entry)
626                                 {
627 
628                                     /* Yes, make the current entry obsolete in favor of the new entry.  */
629                                     block_word =  block_word & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID);
630                                     status =  _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
631 
632                                     /* Check for an error from flash driver. Drivers should never return an error..  */
633                                     if (status)
634                                     {
635 
636                                         /* Call system error handler.  */
637                                         _lx_nor_flash_system_error(nor_flash, status);
638 
639                                         /* Return an error.  */
640                                         return(LX_ERROR);
641                                     }
642 
643                                     /* Is this the first time?  */
644                                     if (nor_flash -> lx_nor_flash_diagnostic_sector_obsoleted)
645                                     {
646 
647                                         /* No, this is a potential format error, since this should only happen once in a given
648                                            NOR flash format.  */
649                                         _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
650 
651                                         /* Return an error.  */
652                                         return(LX_ERROR);
653                                     }
654 
655                                     /* Increment the obsoleted count.  */
656                                     nor_flash -> lx_nor_flash_diagnostic_sector_obsoleted++;
657                                 }
658                             }
659                         }
660 
661                         /* Determine if the sector is free.  */
662                         else if (block_word == LX_NOR_PHYSICAL_SECTOR_FREE)
663                         {
664 
665                             /* A free entry when there are still used sectors implies that the sector was allocated and a power interruption
666                                took place prior to writing the new logical sector number into the list.  */
667 
668                             /* Is this the first time?  */
669                             if (nor_flash -> lx_nor_flash_diagnostic_mapping_invalidated)
670                             {
671 
672                                 /* No, this is a potential format error, since this should only happen once in a given
673                                    NOR flash format.  */
674                                 _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
675 
676                                 /* Return an error.  */
677                                 return(LX_ERROR);
678                             }
679 
680                             /* Write 0s out to this entry to invalidate the sector entry.  */
681                             block_word =  0;
682                             status =  _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
683 
684                             /* Check for an error from flash driver. Drivers should never return an error..  */
685                             if (status)
686                             {
687 
688                                 /* Call system error handler.  */
689                                 _lx_nor_flash_system_error(nor_flash, status);
690 
691                                 /* Return an error.  */
692                                 return(LX_ERROR);
693                             }
694 
695                             /* Increment the number of mapping invalidates.  */
696                             nor_flash -> lx_nor_flash_diagnostic_mapping_invalidated++;
697                         }
698 
699                         /* Yes, now determine if the sector is obsolete.  */
700                         if ((block_word & LX_NOR_PHYSICAL_SECTOR_VALID) == 0)
701                         {
702 
703                             /* Increment the number of obsolete sectors.  */
704                             nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
705                         }
706 
707                         /* Determine if the mapping for this sector isn't yet valid.  */
708                         else if (block_word & LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID)
709                         {
710 
711                             /* Yes, a power interruption or reset occurred while the sector mapping entry was being written.  */
712 
713                             /* Increment the number of obsolete sectors.  */
714                             nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
715 
716                             /* Increment the interrupted mapping counter.  */
717                             nor_flash -> lx_nor_flash_diagnostic_mapping_write_interrupted++;
718 
719                             /* Invalidate this entry - clearing valid bit, superceded bit and logical sector.  */
720                             block_word =  0;
721                             status =  _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
722 
723                             /* Check for an error from flash driver. Drivers should never return an error..  */
724                             if (status)
725                             {
726 
727                                 /* Call system error handler.  */
728                                 _lx_nor_flash_system_error(nor_flash, status);
729 
730                                 /* Return an error.  */
731                                 return(LX_ERROR);
732                             }
733                         }
734                         else
735                         {
736                             /* Increment the number of mapped physical sectors.  */
737                             nor_flash -> lx_nor_flash_mapped_physical_sectors++;
738                         }
739 
740                         /* Decrease the number of used sectors.  */
741                         used_sectors--;
742                     }
743                     else
744                     {
745 
746                         /* No more used sectors in this flash block.  */
747 
748                         /* In this case the entry must be free or there is a serious NOR flash format error present.  */
749                         if (block_word != LX_NOR_PHYSICAL_SECTOR_FREE)
750                         {
751 
752                             /* Increment the sector not free diagnostic.  */
753                             nor_flash -> lx_nor_flash_diagnostic_sector_not_free++;
754 
755                             /* NOR flash format.  */
756                             _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
757 
758                             /* Write 0s out to this entry to invalidate the sector entry.  */
759                             block_word =  0;
760                             status =  _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
761 
762                             /* Check for an error from flash driver. Drivers should never return an error..  */
763                             if (status)
764                             {
765 
766                                 /* Call system error handler.  */
767                                 _lx_nor_flash_system_error(nor_flash, status);
768 
769                                 /* Return an error.  */
770                                 return(LX_ERROR);
771                             }
772                         }
773 
774 #ifdef LX_FREE_SECTOR_DATA_VERIFY
775 
776                         /* Pickup address of the free sector data area.  */
777                         sector_word_ptr =  block_word_ptr + (nor_flash -> lx_nor_flash_block_physical_sector_offset) + (j * LX_NOR_SECTOR_SIZE);
778 
779                         /* Determine if the data for this sector is free.  */
780                         for (k = 0; k < LX_NOR_SECTOR_SIZE; k++)
781                         {
782 
783 #ifdef LX_DIRECT_READ
784 
785                             /* Read the word directly.  */
786                             sector_word =  *(sector_word_ptr);
787 #else
788                             status =  _lx_nor_flash_driver_read(nor_flash, (sector_word_ptr), &sector_word, 1);
789 
790                             /* Check for an error from flash driver. Drivers should never return an error..  */
791                             if (status)
792                             {
793 
794                                 /* Call system error handler.  */
795                                 _lx_nor_flash_system_error(nor_flash, status);
796 
797                                 /* Return an error.  */
798                                 return(LX_ERROR);
799                             }
800 #endif
801 
802                             /* Determine if this word is not available.  */
803                             if (sector_word != LX_NOR_PHYSICAL_SECTOR_FREE)
804                             {
805 
806                                 /* Increment the sector data not free diagnostic.  */
807                                 nor_flash -> lx_nor_flash_diagnostic_sector_data_not_free++;
808 
809                                 /* This is a format error.  */
810                                 _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
811 
812                                 /* Return an error.  */
813                                 return(LX_ERROR);
814                             }
815 
816                             /* Move to the next word in the sector.  */
817                             sector_word_ptr++;
818                         }
819 #endif
820                     }
821                 }
822             }
823 
824             /* Move to the next flash block.  */
825             block_word_ptr =  block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
826         }
827 
828         /* Update the overall minimum and maximum erase count.  */
829         nor_flash -> lx_nor_flash_minimum_erase_count =  min_erased_count;
830         nor_flash -> lx_nor_flash_minimum_erased_blocks =  min_erased_blocks;
831         nor_flash -> lx_nor_flash_maximum_erase_count =  max_erased_count;
832 
833         /* Determine if we need to update the free sector search pointer.  */
834         if (nor_flash -> lx_nor_flash_free_block_search == nor_flash -> lx_nor_flash_total_blocks)
835         {
836 
837             /* Just start at the beginning.  */
838             nor_flash -> lx_nor_flash_free_block_search =  0;
839         }
840     }
841 
842 #ifdef LX_THREAD_SAFE_ENABLE
843 
844     /* If the thread safe option is enabled, create a ThreadX mutex that will be used in all external APIs
845        in order to provide thread-safe operation.  */
846     status =  tx_mutex_create(&nor_flash -> lx_nor_flash_mutex, "NOR Flash Mutex", TX_NO_INHERIT);
847 
848     /* Determine if the mutex creation encountered an error.  */
849     if (status != LX_SUCCESS)
850     {
851 
852         /* Call system error handler, since this should not happen.  */
853         _lx_nor_flash_system_error(nor_flash, LX_SYSTEM_MUTEX_CREATE_FAILED);
854 
855         /* Return error to caller.  */
856         return(LX_ERROR);
857     }
858 #endif
859 
860     /* Enable the sector mapping cache.  */
861     nor_flash -> lx_nor_flash_sector_mapping_cache_enabled =  LX_TRUE;
862 
863     /* Initialize the last found block and sector markers.  */
864     nor_flash -> lx_nor_flash_found_block_search =   0;
865     nor_flash -> lx_nor_flash_found_sector_search =  0;
866 
867     /* Lockout interrupts.  */
868     LX_DISABLE
869 
870     /* At this point, the NOR flash has been opened successfully.  Place the
871        NOR flash control block on the linked list of currently opened NOR flashes.  */
872 
873     /* Set the NOR flash state to open.  */
874     nor_flash -> lx_nor_flash_state =  LX_NOR_FLASH_OPENED;
875 
876     /* Place the NOR flash control block on the list of opened NOR flashes.  First,
877        check for an empty list.  */
878     if (_lx_nor_flash_opened_count)
879     {
880 
881         /* List is not empty - other NOR flashes are open.  */
882 
883         /* Pickup tail pointer.  */
884         tail_ptr =  _lx_nor_flash_opened_ptr -> lx_nor_flash_open_previous;
885 
886         /* Place the new NOR flash control block in the list.  */
887         _lx_nor_flash_opened_ptr -> lx_nor_flash_open_previous =  nor_flash;
888         tail_ptr -> lx_nor_flash_open_next =                       nor_flash;
889 
890         /* Setup this NOR flash's opened links.  */
891         nor_flash -> lx_nor_flash_open_previous =  tail_ptr;
892         nor_flash -> lx_nor_flash_open_next =      _lx_nor_flash_opened_ptr;
893     }
894     else
895     {
896 
897         /* The opened NOR flash list is empty.  Add the NOR flash to empty list.  */
898         _lx_nor_flash_opened_ptr =                 nor_flash;
899         nor_flash -> lx_nor_flash_open_next =      nor_flash;
900         nor_flash -> lx_nor_flash_open_previous =  nor_flash;
901     }
902 
903     /* Increment the opened NOR flash counter.  */
904     _lx_nor_flash_opened_count++;
905 
906     /* Restore interrupts.  */
907     LX_RESTORE
908 
909     /* Return a successful completion.  */
910     return(LX_SUCCESS);
911 }
912 
913