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 /** USBX Component                                                        */
17 /**                                                                       */
18 /**   Storage Class                                                       */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 
24 /* Include necessary system files.  */
25 
26 #define UX_SOURCE_CODE
27 
28 #include "ux_api.h"
29 #include "ux_host_class_storage.h"
30 #include "ux_host_stack.h"
31 
32 
33 #if !defined(UX_HOST_STANDALONE)
34 /**************************************************************************/
35 /*                                                                        */
36 /*  FUNCTION                                               RELEASE        */
37 /*                                                                        */
38 /*    _ux_host_class_storage_thread_entry                 PORTABLE C      */
39 /*                                                           6.1.11       */
40 /*  AUTHOR                                                                */
41 /*                                                                        */
42 /*    Chaoqiong Xiao, Microsoft Corporation                               */
43 /*                                                                        */
44 /*  DESCRIPTION                                                           */
45 /*                                                                        */
46 /*    This function is awaken every 2 seconds to check if there was a     */
47 /*    device insertion on a specific media. This is the only way we can   */
48 /*    remount a media after the storage instance has opened the media to  */
49 /*    UX_MEDIA (default FileX) and the media is either not present        */
50 /*    or was removed and is being re-inserted.                            */
51 /*                                                                        */
52 /*    It's for RTOS mode.                                                 */
53 /*                                                                        */
54 /*  INPUT                                                                 */
55 /*                                                                        */
56 /*    class_address                         Class address                 */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    None                                                                */
61 /*                                                                        */
62 /*  CALLS                                                                 */
63 /*                                                                        */
64 /*    ux_media_close                        Close media                   */
65 /*    _ux_host_class_storage_device_reset   Reset device                  */
66 /*    _ux_host_class_storage_media_mount    Mount the media               */
67 /*    _ux_host_class_storage_unit_ready_test                              */
68 /*                                          Test for unit ready           */
69 /*    _ux_host_class_storage_media_characteristics_get                    */
70 /*                                          Get media characteristics     */
71 /*    _ux_host_class_storage_media_format_capacity_get                    */
72 /*                                          Get media format capacity     */
73 /*    _ux_utility_memory_free               Free memory block             */
74 /*    _ux_host_semaphore_get                Get a semaphore               */
75 /*    _ux_host_semaphore_put                Put a semaphore               */
76 /*    _ux_utility_delay_ms                  Thread sleep                  */
77 /*                                                                        */
78 /*  CALLED BY                                                             */
79 /*                                                                        */
80 /*    ThreadX                                                             */
81 /*                                                                        */
82 /*  RELEASE HISTORY                                                       */
83 /*                                                                        */
84 /*    DATE              NAME                      DESCRIPTION             */
85 /*                                                                        */
86 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
87 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
88 /*                                            added option to disable FX  */
89 /*                                            media integration, used UX_ */
90 /*                                            things instead of FX_       */
91 /*                                            things directly, used host  */
92 /*                                            class extension pointer for */
93 /*                                            class specific structured   */
94 /*                                            data,                       */
95 /*                                            resulting in version 6.1    */
96 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
97 /*                                            refined macros names,       */
98 /*                                            resulting in version 6.1.10 */
99 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
100 /*                                            internal clean up,          */
101 /*                                            resulting in version 6.1.11 */
102 /*                                                                        */
103 /**************************************************************************/
_ux_host_class_storage_thread_entry(ULONG class_address)104 VOID  _ux_host_class_storage_thread_entry(ULONG class_address)
105 {
106 
107 UX_HOST_CLASS                   *class_inst;
108 UX_HOST_CLASS_STORAGE           *storage;
109 UINT                            status;
110 ULONG                           lun_index;
111 UX_HOST_CLASS_STORAGE_MEDIA     *storage_media;
112 UINT                            media_index;
113 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
114 UX_MEDIA                        *media;
115 UCHAR                           *memory;
116 #endif
117 
118 
119     /* Setup pointer to class.  */
120     UX_THREAD_EXTENSION_PTR_GET(class_inst, UX_HOST_CLASS, class_address)
121 
122     /* This thread goes on forever once started.  */
123     while(1)
124     {
125 
126         /* We need to wake every 2 seconds or so.  */
127         _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME);
128 
129         /* We need to parse all the storage instances and check for a removable
130            media flag.  */
131         storage =  (UX_HOST_CLASS_STORAGE *) class_inst -> ux_host_class_first_instance;
132 
133         while (storage != UX_NULL)
134         {
135 
136             /* Check if the instance is live and the device is removable.  */
137             if ((storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE))
138             {
139 
140                 /* We need to ensure nobody is accessing this storage instance. We use
141                    the storage class instance semaphore to protect.  */
142                 status =  _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
143                 if (status != UX_SUCCESS)
144                     break;
145 
146                 /* Each LUN must be parsed and mounted.  */
147                 for (lun_index = 0; lun_index <= storage -> ux_host_class_storage_max_lun; lun_index++)
148                 {
149 
150                     if (storage -> ux_host_class_storage_lun_removable_media_flags[lun_index] != UX_HOST_CLASS_STORAGE_MEDIA_REMOVABLE)
151                         continue;
152 
153                     /* Check the type of LUN, we only deal with the ones we know how to mount.  */
154                     if ((storage -> ux_host_class_storage_lun_types[lun_index] == UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK) ||
155                         (storage -> ux_host_class_storage_lun_types[lun_index] == UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK) ||
156                         (storage -> ux_host_class_storage_lun_types[lun_index] == UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK))
157                     {
158 
159                         /* Set the LUN into the storage instance.  */
160                         storage -> ux_host_class_storage_lun =  lun_index;
161 
162                         /* Check if the device is now ready.  */
163                         status =  _ux_host_class_storage_unit_ready_test(storage);
164 
165                         /* If we have an transport failure here, we are in trouble! The storage device
166                            is in an unstable state and should be reset completely.  */
167                         if (status != UX_SUCCESS)
168                         {
169 
170                             /* Reset device.  */
171                             _ux_host_class_storage_device_reset(storage);
172                             break;
173                         }
174 
175                         /* Process relative to device status.  */
176                         switch(storage -> ux_host_class_storage_sense_code >> 16)
177                         {
178 
179                         case UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY:
180 
181                             /* We may need to unmount this partition if it was mounted before.
182                                To do so, we need to parse the existing media instance and find out
183                                if this partition was already mounted.  */
184 
185                             storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class_inst -> ux_host_class_media;
186 
187                             /* Scan all instances of media.  */
188                             for (media_index = 0; media_index < UX_HOST_CLASS_STORAGE_MAX_MEDIA;
189                                 storage_media++, media_index++)
190                             {
191 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
192                                 /* Get the UX_MEDIA (default FileX) Media attached to this media.  */
193                                 media =  &storage_media -> ux_host_class_storage_media;
194 
195                                 /* Check for the storage instance and lun number.  */
196                                 if ((ux_media_id_get(media) != 0) && (ux_media_driver_info_get(media) == (VOID *) storage) &&
197                                     (storage_media -> ux_host_class_storage_media_lun == storage -> ux_host_class_storage_lun))
198                                 {
199 
200                                     /* We preserve the memory used by this media.  */
201                                     memory =  storage_media -> ux_host_class_storage_media_memory;
202 
203                                     /* Let UX_MEDIA (default FileX) use this instance.  */
204                                     _ux_host_semaphore_put(&storage -> ux_host_class_storage_semaphore);
205 
206                                     /* Ask UX_MEDIA (default FileX) to unmount the partition.  */
207                                     ux_media_close(media);
208 
209                                     /* This device is now unmounted.  */
210                                     storage_media -> ux_host_class_storage_media_status = UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED;
211 
212                                     /* Reset the media ID.  */
213                                     ux_media_id_set(media, 0);
214 
215                                     /* Now, we protect the storage instance.  */
216                                     status =  _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
217                                     if (status != UX_SUCCESS)
218                                         break;
219 
220                                     /* Free the memory block used for data transfer on behalf of UX_MEDIA (default FileX).  */
221                                     _ux_utility_memory_free(memory);
222                                 }
223 #else
224 
225                                 /* Check storage instance and lun number.  */
226                                 if (storage_media -> ux_host_class_storage_media_status != UX_USED)
227                                     continue;
228                                 if (storage_media -> ux_host_class_storage_media_storage != storage)
229                                     continue;
230                                 if (storage_media -> ux_host_class_storage_media_lun != storage -> ux_host_class_storage_lun)
231                                     continue;
232 
233                                 /* Release the instance.  */
234                                 status = _ux_host_semaphore_put_rc(&storage -> ux_host_class_storage_semaphore);
235 
236                                 /* Free the storage media.  */
237                                 storage_media -> ux_host_class_storage_media_status = UX_UNUSED;
238 
239                                 /* Invoke callback for media removal.  */
240                                 if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
241                                 {
242 
243                                     /* Call system change function.  */
244                                     _ux_system_host ->  ux_system_host_change_function(UX_STORAGE_MEDIA_REMOVAL,
245                                                         storage -> ux_host_class_storage_class, (VOID *) storage_media);
246                                 }
247 
248                                 /* Now, we protect the storage instance.  */
249                                 status =  _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
250                                 if (status != UX_SUCCESS)
251                                     break;
252 #endif
253                             }
254                             break;
255 
256                             case UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION:
257 
258                                 /* We may need to unmount this partition if it was mounted before.
259                                    To do so, we need to parse the existing media instance and find out
260                                    if this partition was already mounted.  */
261                                 storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class_inst -> ux_host_class_media;
262 
263                                 /* Scan all instances of media.   */
264                                 for (media_index = 0; media_index < UX_HOST_CLASS_STORAGE_MAX_MEDIA;
265                                     storage_media++, media_index++)
266                                 {
267 
268 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
269                                     /* Get the UX_MEDIA (default FileX) Media attached to this media.  */
270                                     media = &storage_media -> ux_host_class_storage_media;
271 
272                                     /* Check for the storage instance and lun number. */
273                                     if ((ux_media_id_get(media) != 0) && (ux_media_driver_info_get(media) == (VOID *) storage) &&
274                                             (storage_media -> ux_host_class_storage_media_lun == storage -> ux_host_class_storage_lun))
275                                     {
276 
277                                         /* We preserve the memory used by this media.  */
278                                         memory =  storage_media -> ux_host_class_storage_media_memory;
279 
280                                         /* Let UX_MEDIA (default FileX) use this instance.  */
281                                         _ux_host_semaphore_put(&storage -> ux_host_class_storage_semaphore);
282 
283                                         /* Ask UX_MEDIA (default FileX) to unmount the partition.  */
284                                         ux_media_close(media);
285 
286                                         /* This device is now unmounted.  */
287                                         storage_media -> ux_host_class_storage_media_status =  UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED;
288 
289                                         /* Reset the media ID.  */
290                                         ux_media_id_set(media, 0);
291 
292                                         /* Now, we protect the storage instance.  */
293                                         status =  _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
294                                         if (status != UX_SUCCESS)
295                                             break;
296 
297                                         /* Free the memory block used for data transfer on behalf of FileX.  */
298                                         _ux_utility_memory_free(memory);
299                                     }
300 #else
301 
302                                     /* Check storage instance and lun number.  */
303                                     if (storage_media -> ux_host_class_storage_media_status != UX_USED)
304                                         continue;
305                                     if (storage_media -> ux_host_class_storage_media_storage != storage)
306                                         continue;
307                                     if (storage_media -> ux_host_class_storage_media_lun != storage -> ux_host_class_storage_lun)
308                                         continue;
309 
310                                     /* Release the instance.  */
311                                     status = _ux_host_semaphore_put_rc(&storage -> ux_host_class_storage_semaphore);
312 
313                                     /* Free the storage media.  */
314                                     storage_media -> ux_host_class_storage_media_status = UX_UNUSED;
315 
316                                     /* Invoke callback for media removal.  */
317                                     if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
318                                     {
319 
320                                         /* Call system change function.  */
321                                         _ux_system_host ->  ux_system_host_change_function(UX_STORAGE_MEDIA_REMOVAL,
322                                                             storage -> ux_host_class_storage_class, (VOID *) storage_media);
323                                     }
324 
325                                     /* Now, we protect the storage instance.  */
326                                     status =  _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
327                                     if (status != UX_SUCCESS)
328                                         break;
329 #endif
330                                 }
331 
332                                 /* Now, we need to retest the media to see if it is there.  */
333                                 status =  _ux_host_class_storage_unit_ready_test(storage);
334 
335                                 /* If we have an transport failure here, we are in trouble! The storage device
336                                    is in an unstable state and should be reset completely.  */
337                                 if (status != UX_SUCCESS)
338                                 {
339 
340                                     /* Reset device.  */
341                                     _ux_host_class_storage_device_reset(storage);
342                                     break;
343                                 }
344 
345                                 if (storage -> ux_host_class_storage_sense_code == 0)
346                                 {
347 
348                                     /* Get the media type supported by this storage device.  */
349                                     status =  _ux_host_class_storage_media_characteristics_get(storage);
350                                     if (status != UX_SUCCESS)
351                                         break;
352 
353                                     /* Get the format capacity of this storage device.  */
354                                     status =  _ux_host_class_storage_media_format_capacity_get(storage);
355                                     if (status != UX_SUCCESS)
356                                         break;
357 
358                                     /* Let UX_MEDIA (default FileX) use this instance.  */
359                                     _ux_host_semaphore_put(&storage -> ux_host_class_storage_semaphore);
360 
361 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
362 
363                                     /* The device seems to have been inserted, try to mount it.  */
364                                     _ux_host_class_storage_media_mount(storage, 0);
365 #else
366 
367                                     /* Find a free media slot for inserted media.  */
368                                     storage_media =  (UX_HOST_CLASS_STORAGE_MEDIA *) class_inst -> ux_host_class_media;
369                                     for (media_index = 0; media_index < UX_HOST_CLASS_STORAGE_MAX_MEDIA;
370                                         storage_media ++, media_index ++)
371                                     {
372 
373                                         /* Skip used storage media slots.  */
374                                         if (storage_media -> ux_host_class_storage_media_status == UX_USED)
375                                             continue;
376 
377                                         /* Use this free storage media slot.  */
378                                         storage_media -> ux_host_class_storage_media_status = UX_USED;
379                                         storage_media -> ux_host_class_storage_media_storage = storage;
380 
381                                         /* Save media information.  */
382                                         storage_media -> ux_host_class_storage_media_lun = (UCHAR)storage -> ux_host_class_storage_lun;
383                                         storage_media -> ux_host_class_storage_media_sector_size = (USHORT)storage -> ux_host_class_storage_sector_size;
384                                         storage_media -> ux_host_class_storage_media_number_sectors = storage -> ux_host_class_storage_last_sector_number + 1;
385 
386                                         /* Invoke callback for media insertion.  */
387                                         if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
388                                         {
389 
390                                             /* Call system change function.  */
391                                             _ux_system_host ->  ux_system_host_change_function(UX_STORAGE_MEDIA_INSERTION,
392                                                                 storage -> ux_host_class_storage_class, (VOID *) storage_media);
393                                         }
394                                     }
395 #endif
396 
397                                     /* Now, we protect the storage instance.  */
398                                     _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
399                                 }
400                                 break;
401 
402                             default:
403                                 break;
404                         }
405                     }
406                 }
407 
408                 /* Other threads are now allowed to access this storage instance.  */
409                 _ux_host_semaphore_put(&storage -> ux_host_class_storage_semaphore);
410             }
411 
412             /* Move to the next entry in the storage instances link.  */
413             storage =  storage -> ux_host_class_storage_next_instance;
414         }
415     }
416 }
417 #endif
418