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 /**   NAND 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_nand_flash_sector_release                       PORTABLE C      */
43 /*                                                           6.2.1       */
44 /*  AUTHOR                                                                */
45 /*                                                                        */
46 /*    Xiuwen Cai, Microsoft Corporation                                   */
47 /*                                                                        */
48 /*  DESCRIPTION                                                           */
49 /*                                                                        */
50 /*    This function releases a logical sector from being managed in the   */
51 /*    NAND flash.                                                         */
52 /*                                                                        */
53 /*  INPUT                                                                 */
54 /*                                                                        */
55 /*    nand_flash                            NAND flash instance           */
56 /*    logical_sector                        Logical sector number         */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    return status                                                       */
61 /*                                                                        */
62 /*  CALLS                                                                 */
63 /*                                                                        */
64 /*    _lx_nand_flash_block_find             Find the mapped block         */
65 /*    lx_nand_flash_driver_pages_read       Read pages                    */
66 /*    _lx_nand_flash_block_allocate         Allocate block                */
67 /*    _lx_nand_flash_mapped_block_list_remove                             */
68 /*                                          Remove mapped block           */
69 /*    _lx_nand_flash_data_page_copy         Copy data pages               */
70 /*    _lx_nand_flash_free_block_list_add    Add free block to list        */
71 /*    _lx_nand_flash_block_mapping_set      Set block mapping             */
72 /*    _lx_nand_flash_driver_block_erase     Erase block                   */
73 /*    _lx_nand_flash_erase_count_set        Set erase count               */
74 /*    _lx_nand_flash_block_data_move        Move block data               */
75 /*    _lx_nand_flash_block_status_set       Set block status              */
76 /*    _lx_nand_flash_mapped_block_list_add  Add mapped block to list      */
77 /*    _lx_nand_flash_system_error           Internal system error handler */
78 /*    tx_mutex_get                          Get thread protection         */
79 /*    tx_mutex_put                          Release thread protection     */
80 /*                                                                        */
81 /*  CALLED BY                                                             */
82 /*                                                                        */
83 /*    Application Code                                                    */
84 /*                                                                        */
85 /*  RELEASE HISTORY                                                       */
86 /*                                                                        */
87 /*    DATE              NAME                      DESCRIPTION             */
88 /*                                                                        */
89 /*  03-08-2023     Xiuwen Cai               Initial Version 6.2.1        */
90 /*                                                                        */
91 /**************************************************************************/
_lx_nand_flash_sector_release(LX_NAND_FLASH * nand_flash,ULONG logical_sector)92 UINT  _lx_nand_flash_sector_release(LX_NAND_FLASH *nand_flash, ULONG logical_sector)
93 {
94 
95 UINT        status;
96 ULONG       block;
97 USHORT      block_status;
98 UCHAR       *spare_buffer_ptr;
99 ULONG       available_pages;
100 LONG        page;
101 UINT        release_sector = LX_FALSE;
102 ULONG       new_block;
103 USHORT      new_block_status;
104 
105 #ifdef LX_THREAD_SAFE_ENABLE
106 
107     /* Obtain the thread safe mutex.  */
108     tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER);
109 #endif
110 
111     /* Increment the number of release requests.  */
112     nand_flash -> lx_nand_flash_diagnostic_sector_release_requests++;
113 
114 
115     /* See if we can find the sector in the current mapping.  */
116     status = _lx_nand_flash_block_find(nand_flash, logical_sector, &block, &block_status);
117 
118     /* Check return status.   */
119     if (status != LX_SUCCESS)
120     {
121 
122         /* Call system error handler.  */
123         _lx_nand_flash_system_error(nand_flash, status, block, 0);
124 
125         /* Determine if the error is fatal.  */
126         if (status != LX_NAND_ERROR_CORRECTED)
127         {
128 #ifdef LX_THREAD_SAFE_ENABLE
129 
130             /* Release the thread safe mutex.  */
131             tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
132 #endif
133 
134             /* Return an error.  */
135             return(LX_ERROR);
136         }
137     }
138 
139     /* Determine if the block is mapped.  */
140     if (block != LX_NAND_BLOCK_UNMAPPED)
141     {
142 
143         /* Setup spare buffer pointer.  */
144         spare_buffer_ptr = (UCHAR*)nand_flash -> lx_nand_flash_page_buffer;
145 
146         /* Get available pages in this block.  */
147         available_pages = block_status & LX_NAND_BLOCK_STATUS_FULL ? nand_flash -> lx_nand_flash_pages_per_block : block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK;
148 
149         /* Determine if the pages are recorded sequentially.  */
150         if (block_status & LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL)
151         {
152 
153             /* Loop to search the logical page.  */
154             for (page = (LONG)available_pages - 1; page >= 0; page--)
155             {
156 
157                 /* Read a page.  */
158 #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
159                 status = (nand_flash -> lx_nand_flash_driver_pages_read)(nand_flash, block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1);
160 #else
161                 status = (nand_flash -> lx_nand_flash_driver_pages_read)(block, (ULONG)page, LX_NULL, spare_buffer_ptr, 1);
162 #endif
163 
164                 /* Check for an error from flash driver.   */
165                 if (status)
166                 {
167 
168                     /* Call system error handler.  */
169                     _lx_nand_flash_system_error(nand_flash, status, block, 0);
170 #ifdef LX_THREAD_SAFE_ENABLE
171 
172                     /* Release the thread safe mutex.  */
173                     tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
174 #endif
175 
176                     /* Return an error.  */
177                     return(LX_ERROR);
178                 }
179 
180                 /* Get the logical sector number from spare bytes, and check if it matches the addressed sector number.  */
181                 if ((LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]) & LX_NAND_PAGE_TYPE_USER_DATA_MASK) == logical_sector)
182                 {
183 
184                     /* Make sure the sector is not released.  */
185                     if ((LX_UTILITY_LONG_GET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset]) & (~LX_NAND_PAGE_TYPE_USER_DATA_MASK)) == (LX_NAND_PAGE_TYPE_USER_DATA))
186                     {
187 
188                         /* Set release sector flag.  */
189                         release_sector = LX_TRUE;
190                     }
191                 }
192             }
193         }
194         else
195         {
196 
197             /* Check if the logical sector is available.  */
198             if (logical_sector % nand_flash -> lx_nand_flash_pages_per_block < available_pages)
199             {
200 
201                 /* Set release sector flag.  */
202                 release_sector = LX_TRUE;
203             }
204         }
205 
206         /* Determine if the sector needs to be released.  */
207         if (release_sector)
208         {
209 
210             /* Check if the block is full.  */
211             if (block_status & LX_NAND_BLOCK_STATUS_FULL)
212             {
213 
214                 /* Allocate a new block.  */
215                 status = _lx_nand_flash_block_allocate(nand_flash, &new_block);
216 
217                 /* Check return status.   */
218                 if (status != LX_SUCCESS)
219                 {
220                     /* Call system error handler.  */
221                     _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
222 #ifdef LX_THREAD_SAFE_ENABLE
223 
224                     /* Release the thread safe mutex.  */
225                     tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
226 #endif
227 
228                     /* Return an error.  */
229                     return(LX_ERROR);
230 
231                 }
232 
233                 /* Set new block status to allocated.  */
234                 new_block_status = LX_NAND_BLOCK_STATUS_ALLOCATED;
235 
236                 /* Remove the old block from mapped block list.  */
237                 _lx_nand_flash_mapped_block_list_remove(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
238 
239                 /* Copy valid sector to new block.  */
240                 status = _lx_nand_flash_data_page_copy(nand_flash, logical_sector - (logical_sector % nand_flash -> lx_nand_flash_pages_per_block), block, block_status, new_block, &new_block_status, (logical_sector % nand_flash -> lx_nand_flash_pages_per_block));
241 
242                 /* Check for an error from flash driver.   */
243                 if (status)
244                 {
245 
246                     /* Call system error handler.  */
247                     _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
248 #ifdef LX_THREAD_SAFE_ENABLE
249 
250                     /* Release the thread safe mutex.  */
251                     tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
252 #endif
253 
254                     /* Return an error.  */
255                     return(LX_ERROR);
256                 }
257 
258                 /* Determine if there are sectors after the addressed sector need to be copied.  */
259                 if (logical_sector % nand_flash -> lx_nand_flash_pages_per_block < nand_flash -> lx_nand_flash_pages_per_block - 1)
260                 {
261 
262                     /* Copy valid sector to new block.  */
263                     status = _lx_nand_flash_data_page_copy(nand_flash, logical_sector + 1, block, block_status, new_block, &new_block_status, (nand_flash -> lx_nand_flash_pages_per_block - 1) - (logical_sector % nand_flash -> lx_nand_flash_pages_per_block));
264 
265                     /* Check for an error from flash driver.   */
266                     if (status)
267                     {
268 
269                         /* Call system error handler.  */
270                         _lx_nand_flash_system_error(nand_flash, status, new_block, 0);
271 #ifdef LX_THREAD_SAFE_ENABLE
272 
273                         /* Release the thread safe mutex.  */
274                         tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
275 #endif
276 
277                         /* Return an error.  */
278                         return(LX_ERROR);
279                     }
280                 }
281 
282                 /* Check new block status to see if there is valid pages in the block.  */
283                 if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) == 0)
284                 {
285 
286                     /* Add the block to free block list.  */
287                     _lx_nand_flash_free_block_list_add(nand_flash, new_block);
288 
289                     /* Set new block to unmapped.  */
290                     new_block = LX_NAND_BLOCK_UNMAPPED;
291                 }
292                 else
293                 {
294 
295                     /* Set new block status.  */
296                     status = _lx_nand_flash_block_status_set(nand_flash, new_block, new_block_status);
297 
298                     /* Check for an error from flash driver.   */
299                     if (status)
300                     {
301 
302                         /* Call system error handler.  */
303                         _lx_nand_flash_system_error(nand_flash, status, block, 0);
304 #ifdef LX_THREAD_SAFE_ENABLE
305 
306                         /* Release the thread safe mutex.  */
307                         tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
308 #endif
309 
310                         /* Return an error.  */
311                         return(LX_ERROR);
312                     }
313                 }
314 
315                 /* Update block mapping.  */
316                 _lx_nand_flash_block_mapping_set(nand_flash, logical_sector, new_block);
317 
318                 /* Erase old block.  */
319                 status = _lx_nand_flash_driver_block_erase(nand_flash, block, nand_flash -> lx_nand_flash_base_erase_count + nand_flash -> lx_nand_flash_erase_count_table[block] + 1);
320 
321                 /* Check for an error from flash driver.   */
322                 if (status)
323                 {
324 
325                     /* Call system error handler.  */
326                     _lx_nand_flash_system_error(nand_flash, status, block, 0);
327 #ifdef LX_THREAD_SAFE_ENABLE
328 
329                     /* Release the thread safe mutex.  */
330                     tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
331 #endif
332 
333                     /* Return an error.  */
334                     return(LX_ERROR);
335                 }
336 
337                 /* Update erase count for the old block.  */
338                 status = _lx_nand_flash_erase_count_set(nand_flash, block, (UCHAR)(nand_flash -> lx_nand_flash_erase_count_table[block] + 1));
339 
340                 /* Check for an error from flash driver.   */
341                 if (status)
342                 {
343 
344                     /* Call system error handler.  */
345                     _lx_nand_flash_system_error(nand_flash, status, block, 0);
346 #ifdef LX_THREAD_SAFE_ENABLE
347 
348                     /* Release the thread safe mutex.  */
349                     tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
350 #endif
351 
352                     /* Return an error.  */
353                     return(LX_ERROR);
354                 }
355 
356                 /* Check if the block has too many erases.  */
357                 if (nand_flash -> lx_nand_flash_erase_count_table[block] > LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA)
358                 {
359 
360                     /* Move data from less worn block.  */
361                     _lx_nand_flash_block_data_move(nand_flash, block);
362                 }
363                 else
364                 {
365 
366                     /* Set the block status to free.  */
367                     status = _lx_nand_flash_block_status_set(nand_flash, block, LX_NAND_BLOCK_STATUS_FREE);
368 
369                     /* Check for an error from flash driver.   */
370                     if (status)
371                     {
372 
373                         /* Call system error handler.  */
374                         _lx_nand_flash_system_error(nand_flash, status, block, 0);
375 #ifdef LX_THREAD_SAFE_ENABLE
376 
377                         /* Release the thread safe mutex.  */
378                         tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
379 #endif
380 
381                         /* Return an error.  */
382                         return(LX_ERROR);
383                     }
384 
385                     /* Add the block to free block list.  */
386                     _lx_nand_flash_free_block_list_add(nand_flash, block);
387                 }
388 
389                 /* Check if there is valid pages in the new block.  */
390                 if ((new_block_status & LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK) != 0)
391                 {
392 
393                     /* Add the new block to mapped block list.  */
394                     _lx_nand_flash_mapped_block_list_add(nand_flash, logical_sector / nand_flash -> lx_nand_flash_pages_per_block);
395                 }
396             }
397             else
398             {
399 
400                 /* Set page buffer to all 0xFF bytes.  */
401                 LX_MEMSET(nand_flash -> lx_nand_flash_page_buffer, 0xFF, nand_flash -> lx_nand_flash_bytes_per_page + nand_flash -> lx_nand_flash_spare_total_length);
402 
403                 /* Setup spare buffer pointer.  */
404                 spare_buffer_ptr = nand_flash -> lx_nand_flash_page_buffer + nand_flash -> lx_nand_flash_bytes_per_page;
405 
406                 /* Check if there is enough spare data for metadata block number.  */
407                 if (nand_flash -> lx_nand_flash_spare_data2_length >= sizeof(USHORT))
408                 {
409 
410                     /* Save metadata block number in spare bytes.  */
411                     LX_UTILITY_SHORT_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data2_offset], nand_flash -> lx_nand_flash_metadata_block_number);
412                 }
413 
414                 /* Set page type and sector address.  */
415                 LX_UTILITY_LONG_SET(&spare_buffer_ptr[nand_flash -> lx_nand_flash_spare_data1_offset], LX_NAND_PAGE_TYPE_USER_DATA_RELEASED | logical_sector);
416 
417                 /* Write the page.  */
418 #ifdef LX_NAND_ENABLE_CONTROL_BLOCK_FOR_DRIVER_INTERFACE
419                 status = (nand_flash -> lx_nand_flash_driver_pages_write)(nand_flash, block, available_pages, (UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1);
420 #else
421                 status = (nand_flash -> lx_nand_flash_driver_pages_write)(block, available_pages, (UCHAR*)nand_flash -> lx_nand_flash_page_buffer, spare_buffer_ptr, 1);
422 #endif
423 
424                 /* Check for an error from flash driver.   */
425                 if (status)
426                 {
427 
428                     /* Call system error handler.  */
429                     _lx_nand_flash_system_error(nand_flash, status, block, 0);
430 #ifdef LX_THREAD_SAFE_ENABLE
431 
432                     /* Release the thread safe mutex.  */
433                     tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
434 #endif
435 
436                     /* Return an error.  */
437                     return(LX_ERROR);
438                 }
439 
440                 /* Increase available pages count.  */
441                 available_pages++;
442 
443                 /* Check if available pages count reaches total pages per block.  */
444                 if (available_pages == nand_flash -> lx_nand_flash_pages_per_block)
445                 {
446 
447                     /* Set block full status flag.  */
448                     block_status |= LX_NAND_BLOCK_STATUS_FULL;
449                 }
450 
451                 /* Build block status word.  */
452                 block_status = (USHORT)(available_pages | (block_status & ~LX_NAND_BLOCK_STATUS_PAGE_NUMBER_MASK));
453 
454                 /* Set non sequential status flag.  */
455                 block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL;
456 
457                 /* Set block status.  */
458                 status = _lx_nand_flash_block_status_set(nand_flash, block, block_status);
459 
460                 /* Check for an error from flash driver.   */
461                 if (status)
462                 {
463 
464                     /* Call system error handler.  */
465                     _lx_nand_flash_system_error(nand_flash, status, block, 0);
466 #ifdef LX_THREAD_SAFE_ENABLE
467 
468                     /* Release the thread safe mutex.  */
469                     tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
470 #endif
471 
472                     /* Return an error.  */
473                     return(LX_ERROR);
474                 }
475             }
476         }
477     }
478 #ifdef LX_THREAD_SAFE_ENABLE
479 
480     /* Release the thread safe mutex.  */
481     tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
482 #endif
483 
484     /* Return status.  */
485     return(status);
486 }
487 
488