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 static inline VOID _ux_host_class_storage_inst_tasks_run(UX_HOST_CLASS_STORAGE *storage);
37 
38 static inline UINT _ux_host_class_storage_lun_is_removable(UX_HOST_CLASS_STORAGE *storage);
39 static inline UINT _ux_host_class_storage_lun_type_is_known(UX_HOST_CLASS_STORAGE *storage);
40 
41 static inline VOID _ux_host_class_storage_max_lun_save(UX_HOST_CLASS_STORAGE *storage);
42 static inline UINT _ux_host_class_storage_inquiry_save(UX_HOST_CLASS_STORAGE *storage);
43 static inline VOID _ux_host_class_storage_format_cap_save(UX_HOST_CLASS_STORAGE *storage);
44 static inline VOID _ux_host_class_storage_capacity_save(UX_HOST_CLASS_STORAGE *storage);
45 static inline VOID _ux_host_class_storage_unit_ready_check(UX_HOST_CLASS_STORAGE *storage);
46 
47 static inline VOID _ux_host_class_storage_lun_media_insert(UX_HOST_CLASS_STORAGE *storage);
48 
49 static inline UINT _ux_host_class_storage_transport_sense_check(UX_HOST_CLASS_STORAGE *storage);
50 
51 /**************************************************************************/
52 /*                                                                        */
53 /*  FUNCTION                                               RELEASE        */
54 /*                                                                        */
55 /*    _ux_host_class_storage_tasks_run                    PORTABLE C      */
56 /*                                                           6.2.0        */
57 /*  AUTHOR                                                                */
58 /*                                                                        */
59 /*    Chaoqiong Xiao, Microsoft Corporation                               */
60 /*                                                                        */
61 /*  DESCRIPTION                                                           */
62 /*                                                                        */
63 /*    This function is awaken every 2 seconds to check if there was a     */
64 /*    device insertion on a specific media. This is the only way we can   */
65 /*    remount a media after the storage instance has opened the media to  */
66 /*    UX_MEDIA (default FileX) and the media is either not present        */
67 /*    or was removed and is being re-inserted.                            */
68 /*                                                                        */
69 /*  INPUT                                                                 */
70 /*                                                                        */
71 /*    storage                               Pointer to storage instance   */
72 /*                                                                        */
73 /*  OUTPUT                                                                */
74 /*                                                                        */
75 /*    None                                                                */
76 /*                                                                        */
77 /*  CALLS                                                                 */
78 /*                                                                        */
79 /*    _ux_host_class_storage_device_reset   Reset device                  */
80 /*    _ux_host_class_storage_media_mount    Mount the media               */
81 /*    _ux_host_class_storage_unit_ready_test                              */
82 /*                                          Test for unit ready           */
83 /*    _ux_host_class_storage_media_characteristics_get                    */
84 /*                                          Get media characteristics     */
85 /*    _ux_host_class_storage_media_format_capacity_get                    */
86 /*                                          Get media format capacity     */
87 /*    _ux_utility_memory_free               Free memory block             */
88 /*                                                                        */
89 /*  CALLED BY                                                             */
90 /*                                                                        */
91 /*    USBX Host Stack                                                     */
92 /*                                                                        */
93 /*  RELEASE HISTORY                                                       */
94 /*                                                                        */
95 /*    DATE              NAME                      DESCRIPTION             */
96 /*                                                                        */
97 /*  01-31-2022     Chaoqiong Xiao           Initial Version 6.1.10        */
98 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
99 /*                                            fixed parameter/variable    */
100 /*                                            names conflict C++ keyword, */
101 /*                                            resulting in version 6.1.12 */
102 /*  10-31-2022     Chaoqiong Xiao           Modified comment(s),          */
103 /*                                            improved internal logic,    */
104 /*                                            resulting in version 6.2.0  */
105 /*                                                                        */
106 /**************************************************************************/
_ux_host_class_storage_tasks_run(UX_HOST_CLASS * storage_class)107 UINT  _ux_host_class_storage_tasks_run(UX_HOST_CLASS *storage_class)
108 {
109 UX_HOST_CLASS_STORAGE           *storage;
110 
111     /* Validate class entry.  */
112     if (storage_class -> ux_host_class_status != UX_USED ||
113         storage_class -> ux_host_class_entry_function != _ux_host_class_storage_entry)
114         return(UX_STATE_IDLE);
115 
116     /* Run for class instances.  */
117     storage = (UX_HOST_CLASS_STORAGE *)storage_class -> ux_host_class_first_instance;
118     while(storage)
119     {
120 
121         /* Run tasks for each storage instance.  */
122         storage -> ux_host_class_storage_flags |= UX_HOST_CLASS_STORAGE_FLAG_PROTECT;
123         _ux_host_class_storage_inst_tasks_run(storage);
124         storage -> ux_host_class_storage_flags &= ~UX_HOST_CLASS_STORAGE_FLAG_PROTECT;
125         storage = storage -> ux_host_class_storage_next_instance;
126     }
127     return(UX_STATE_WAIT);
128 }
129 
_ux_host_class_storage_inst_tasks_run(UX_HOST_CLASS_STORAGE * storage)130 static inline VOID _ux_host_class_storage_inst_tasks_run(UX_HOST_CLASS_STORAGE *storage)
131 {
132 UX_INTERRUPT_SAVE_AREA
133 UCHAR           state;
134 ULONG           tick_now, tick_elapsed;
135 UINT            status;
136 UX_TRANSFER     *trans;
137 UX_INTERFACE    *interface_ptr;
138 INT             immediate_state;
139 
140     /* If storage not live, start initialize.  */
141     if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_MOUNTING)
142     {
143         if (storage -> ux_host_class_storage_state_state == UX_STATE_RESET)
144         {
145 
146             /* Start initialize sequence Delay() - GetMaxLUN() - Inquiry() - GetFormatCapacity().  */
147             storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_DELAY_WAIT;
148             storage -> ux_host_class_storage_state_next = UX_HOST_CLASS_STORAGE_STATE_MAX_LUN_GET;
149             storage -> ux_host_class_storage_delay_start = _ux_utility_time_get();
150             storage -> ux_host_class_storage_delay_ms =
151                                 UX_MS_TO_TICK_NON_ZERO(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY);
152             return;
153         }
154 
155         /* OK to process states.  */
156     }
157     else if (storage -> ux_host_class_storage_state != UX_HOST_CLASS_INSTANCE_LIVE)
158     {
159 
160         /* No need to process states.  */
161         storage -> ux_host_class_storage_state_state = UX_STATE_RESET;
162         return;
163     }
164 
165     /* Handle read/write states.  */
166     if ((storage -> ux_host_class_storage_op_state == UX_STATE_WAIT) &&
167         (storage -> ux_host_class_storage_flags &
168          UX_HOST_CLASS_STORAGE_FLAG_CHECK_CURRENT) == 0)
169     {
170 
171         /* Run transport.  */
172         status = _ux_host_class_storage_transport_run(storage);
173 
174         /* Fatal error.  */
175         if (status < UX_STATE_IDLE)
176         {
177             storage -> ux_host_class_storage_op_state = UX_STATE_RESET;
178             return;
179         }
180 
181         /* Done with/without error.  */
182         if (status <= UX_STATE_NEXT)
183         {
184             storage -> ux_host_class_storage_op_state = UX_STATE_IDLE;
185             return;
186         }
187 
188         /* Keep waiting.  */
189         /* Main states are frozen in this case.  */
190         return;
191     }
192 
193     /* Handle main states.  */
194     immediate_state = UX_TRUE;
195     while(immediate_state)
196     {
197 
198         /* Get current state.  */
199         /* Initial check: delay()-GetMaxLUN()-Inquiry()-GetFormatCap()
200             process break on any error.  */
201         /* Regular check: delay()-TestReady()-Inquiry()-GetFormatCap()
202             process break on any error.  */
203         state = storage -> ux_host_class_storage_state_state;
204         switch(state)
205         {
206         case UX_HOST_CLASS_STORAGE_STATE_MAX_LUN_GET:
207 
208             /* Issue GetMaxLun().  */
209             status = _ux_host_class_storage_max_lun_get(storage);
210             if (UX_SUCCESS != status)
211             {
212 
213                 /* This fails storage activation.  */
214                 interface_ptr = storage -> ux_host_class_storage_interface;
215                 _ux_host_stack_class_instance_destroy(
216                     storage -> ux_host_class_storage_class, (VOID *) storage);
217                 interface_ptr -> ux_interface_class_instance =  (VOID *) UX_NULL;
218                 _ux_utility_memory_free(storage);
219                 return;
220             }
221 
222             /* Roll back to next state.  */
223             /* By default TRANSFER -> MAX_LUN_SAVE -> TEST_READY.  */
224             continue;
225 
226         case UX_HOST_CLASS_STORAGE_STATE_MAX_LUN_SAVE:
227             _ux_host_class_storage_max_lun_save(storage);
228 
229             /* Continue to start LUN 0 check from TEST_READY any way.  */
230             storage -> ux_host_class_storage_check_lun = 0;
231             storage -> ux_host_class_storage_state_state =
232                                         UX_HOST_CLASS_STORAGE_STATE_TEST_READY;
233 
234             /* Fall through.  */
235         case UX_HOST_CLASS_STORAGE_STATE_TEST_READY:
236 
237             /* Save the LUN for the follwing sequence to use.  */
238             storage -> ux_host_class_storage_lun =
239                                     storage -> ux_host_class_storage_check_lun;
240 
241             /* If storage is not live, skip to do INQUIRY.  */
242             if (storage -> ux_host_class_storage_state != UX_HOST_CLASS_INSTANCE_LIVE)
243             {
244                 storage -> ux_host_class_storage_state_state =
245                                             UX_HOST_CLASS_STORAGE_STATE_INQUIRY;
246                 continue;
247             }
248 
249             /* If LUN is not removable nor known, skip it to check next LUN.  */
250             if (!_ux_host_class_storage_lun_is_removable(storage) ||
251                 !_ux_host_class_storage_lun_type_is_known(storage))
252             {
253                 storage -> ux_host_class_storage_state_state =
254                                         UX_HOST_CLASS_STORAGE_STATE_NEXT_LUN;
255                 continue;
256             }
257 
258             /* Prepare TestUnitReady().  */
259             _ux_host_class_storage_unit_ready_test(storage);
260 
261             /* Roll back to next - TRANSPORT - TEST_CHECK.  */
262             continue;
263 
264         case UX_HOST_CLASS_STORAGE_STATE_TEST_CHECK:
265             _ux_host_class_storage_unit_ready_check(storage);
266 
267             /* Roll back to next - possible NEXT_LUN/INQUIRY/TEST_READY.  */
268             continue;
269 
270         case UX_HOST_CLASS_STORAGE_STATE_INQUIRY:
271             status = _ux_host_class_storage_media_characteristics_get(storage);
272             if (status != UX_SUCCESS)
273             {
274 
275                 /* There is error, break the regular check round.  */
276                 storage -> ux_host_class_storage_status = status;
277                 storage -> ux_host_class_storage_state_state =
278                                         UX_HOST_CLASS_STORAGE_STATE_CHECK_DONE;
279             }
280 
281             /* Roll back to normal next - TRANSPORT - INQUIRY_SAVE.  */
282             continue;
283 
284         case UX_HOST_CLASS_STORAGE_STATE_INQUIRY_SAVE:
285             status = _ux_host_class_storage_inquiry_save(storage);
286             if (status != UX_SUCCESS)
287             {
288 
289                 /* Check next LUN.  */
290                 storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_NEXT_LUN;
291                 continue;
292             }
293 
294             /* Next : GetFormatCapacity().  */
295             storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_FORMAT_CAP_GET;
296 
297             /* Fall through.  */
298         case UX_HOST_CLASS_STORAGE_STATE_FORMAT_CAP_GET:
299             status = _ux_host_class_storage_media_format_capacity_get(storage);
300             if (status != UX_SUCCESS)
301             {
302 
303                 /* This error breaks regular check round.  */
304                 storage -> ux_host_class_storage_status = status;
305                 storage -> ux_host_class_storage_state_state =
306                                         UX_HOST_CLASS_STORAGE_STATE_CHECK_DONE;
307             }
308 
309             /* Roll back to normal next - TRANSPORT - FORMAT_CAP_SAVE.  */
310             continue;
311 
312         case UX_HOST_CLASS_STORAGE_STATE_FORMAT_CAP_SAVE:
313             _ux_host_class_storage_format_cap_save(storage);
314 
315             /* Next : GetCapacity()  */
316             storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_CAP_GET;
317 
318             /* Fall through.  */
319         case UX_HOST_CLASS_STORAGE_STATE_CAP_GET:
320             status = _ux_host_class_storage_media_capacity_get(storage);
321             if (status != UX_SUCCESS)
322             {
323 
324                 /* This error breaks the regular check round.  */
325                 storage -> ux_host_class_storage_status = status;
326                 storage -> ux_host_class_storage_state_state =
327                                         UX_HOST_CLASS_STORAGE_STATE_CHECK_DONE;
328             }
329 
330             /* Roll back to normal next - TRANSPORT - CAP_SAVE.  */
331             continue;
332 
333         case UX_HOST_CLASS_STORAGE_STATE_CAP_SAVE:
334             _ux_host_class_storage_capacity_save(storage);
335 
336             /* Final step for a single LUN check, going to next LUN.  */
337             storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_NEXT_LUN;
338             continue;
339 
340         case UX_HOST_CLASS_STORAGE_STATE_CHECK_START:
341 
342             /* Get lock and start check sequence: ready - inquiry - formatCap - cap.  */
343             storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_LOCK_WAIT;
344             storage -> ux_host_class_storage_state_next = UX_HOST_CLASS_STORAGE_STATE_TEST_READY;
345 
346             /* Fall through.  */
347         case UX_HOST_CLASS_STORAGE_STATE_LOCK_WAIT:
348             UX_DISABLE
349             if (storage -> ux_host_class_storage_flags & UX_HOST_CLASS_STORAGE_FLAG_LOCK)
350             {
351 
352                 /* Locked, keep state to wait.  */
353                 UX_RESTORE
354                 return;
355             }
356 
357             /* I'm locking it.  */
358             storage -> ux_host_class_storage_flags |= UX_HOST_CLASS_STORAGE_FLAG_LOCK;
359             UX_RESTORE
360 
361             /* Next state.  */
362             storage -> ux_host_class_storage_state_state =
363                                     storage -> ux_host_class_storage_state_next;
364             continue;
365 
366         case UX_HOST_CLASS_STORAGE_STATE_NEXT_LUN:
367 
368             /* If it's immediate check for current LUN, we are done.  */
369             if (storage -> ux_host_class_storage_flags &
370                 UX_HOST_CLASS_STORAGE_FLAG_CHECK_CURRENT)
371             {
372 
373                 /* Go back to idle state.  */
374                 storage -> ux_host_class_storage_flags &=
375                                     ~UX_HOST_CLASS_STORAGE_FLAG_CHECK_CURRENT;
376                 storage -> ux_host_class_storage_state_state = UX_STATE_IDLE;
377                 continue;
378             }
379 
380             if (storage -> ux_host_class_storage_check_lun <
381                 storage -> ux_host_class_storage_max_lun)
382             {
383 
384                 /* Check next LUN.  */
385                 storage -> ux_host_class_storage_check_lun ++;
386                 storage -> ux_host_class_storage_state_state =
387                                         UX_HOST_CLASS_STORAGE_STATE_TEST_READY;
388             }
389             else
390             {
391 
392                 /* All LUN check is done.  */
393                 storage -> ux_host_class_storage_state_state =
394                                         UX_HOST_CLASS_STORAGE_STATE_CHECK_DONE;
395             }
396 
397             /* Roll back to next state.  */
398             continue;
399 
400         case UX_HOST_CLASS_STORAGE_STATE_TRANSPORT:
401             status = _ux_host_class_storage_transport_run(storage);
402 
403             /* Errors.  */
404             if (status < UX_STATE_NEXT)
405             {
406 
407                 /* Normal flow is broken, if there is data buffer, free it.  */
408                 if (storage -> ux_host_class_storage_trans_data)
409                     _ux_utility_memory_free(storage -> ux_host_class_storage_trans_data);
410 
411                 /* No further operations, reset state machine.  */
412                 storage -> ux_host_class_storage_state_state = UX_STATE_RESET;
413                 storage -> ux_host_class_storage_flags &= ~UX_HOST_CLASS_STORAGE_FLAG_LOCK;
414                 return;
415             }
416 
417             /* Next.  */
418             if (status == UX_STATE_NEXT)
419             {
420 
421                 /* If there is sense handled, rollback to next state.  */
422                 if (_ux_host_class_storage_transport_sense_check(storage))
423                 {
424 
425                     /* Normal flow is broken, if there is data buffer, free it.  */
426                     if (storage -> ux_host_class_storage_trans_data)
427                         _ux_utility_memory_free(storage -> ux_host_class_storage_trans_data);
428                     continue;
429                 }
430 
431                 storage -> ux_host_class_storage_state_state =
432                                     storage -> ux_host_class_storage_state_next;
433                 continue;
434             }
435 
436             /* Wait, state no change.  */
437             return;
438 
439         case UX_HOST_CLASS_STORAGE_STATE_TRANSFER:
440             trans = storage -> ux_host_class_storage_trans;
441             status = _ux_host_stack_transfer_run(trans);
442 
443             /* Keep waiting if not done.  */
444             if (status > UX_STATE_NEXT)
445                 return;
446 
447             /* Check status in next state.  */
448             storage -> ux_host_class_storage_state_state =
449                             storage -> ux_host_class_storage_state_next;
450             continue;
451 
452         case UX_HOST_CLASS_STORAGE_STATE_CHECK_DONE:
453 
454             /* If it's mounting, do immediate ready check again.  */
455             if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_MOUNTING)
456             {
457                 storage -> ux_host_class_storage_state = UX_HOST_CLASS_INSTANCE_LIVE;
458                 storage -> ux_host_class_storage_check_lun = 0;
459                 storage -> ux_host_class_storage_state_state =
460                                         UX_HOST_CLASS_STORAGE_STATE_TEST_READY;
461                 continue;
462             }
463 
464             /* Release the storage.  */
465             storage -> ux_host_class_storage_flags &= ~UX_HOST_CLASS_STORAGE_FLAG_LOCK;
466 
467             /* Main state idle.  */
468             storage -> ux_host_class_storage_state_state = UX_STATE_IDLE;
469             continue;
470 
471         case UX_HOST_CLASS_STORAGE_STATE_DELAY_WAIT:
472             tick_now = _ux_utility_time_get();
473             tick_elapsed = _ux_utility_time_elapsed(
474                 storage -> ux_host_class_storage_delay_start, tick_now);
475 
476             /* If no timeout, state no change, keep waiting.  */
477             if (tick_elapsed < storage -> ux_host_class_storage_delay_ms)
478                 return;
479 
480             /* Roll back to do next state.  */
481             storage -> ux_host_class_storage_state_state =
482                             storage -> ux_host_class_storage_state_next;
483             continue;
484 
485         case UX_STATE_IDLE:
486 
487             /* If it's not locked, start delay for checking.  */
488             UX_DISABLE
489             if ((storage -> ux_host_class_storage_flags & UX_HOST_CLASS_STORAGE_FLAG_LOCK) == 0)
490             {
491 
492                 /* Just keep regular checking from LUN 0.  */
493                 storage -> ux_host_class_storage_check_lun = 0;
494                 storage -> ux_host_class_storage_delay_start = _ux_utility_time_get();
495                 storage -> ux_host_class_storage_state_state =
496                                     UX_HOST_CLASS_STORAGE_STATE_DELAY_WAIT;
497                 storage -> ux_host_class_storage_state_next =
498                                     UX_HOST_CLASS_STORAGE_STATE_CHECK_START;
499                 storage -> ux_host_class_storage_delay_ms = UX_MS_TO_TICK(
500                                     UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME);
501                 UX_RESTORE
502                 continue;
503             }
504             UX_RESTORE
505 
506             /* Fall through.  */
507 
508         case UX_STATE_RESET: /* Fall through.  */
509         default:
510             break;
511         }
512 
513         /* Break the loop.  */
514         immediate_state = UX_FALSE;
515     }
516 }
517 
_ux_host_class_storage_max_lun_save(UX_HOST_CLASS_STORAGE * storage)518 static inline VOID _ux_host_class_storage_max_lun_save(UX_HOST_CLASS_STORAGE *storage)
519 {
520 UX_TRANSFER *trans = storage -> ux_host_class_storage_trans;
521 
522     /* By default max lun is 0.  */
523     storage -> ux_host_class_storage_max_lun = 0;
524 
525     /* MaxLuN can from success request.  */
526     if (trans)
527     {
528 
529         /* If success, save max LUN.  */
530         if (trans -> ux_transfer_request_completion_code == UX_SUCCESS &&
531             trans -> ux_transfer_request_actual_length == 1)
532         {
533             storage -> ux_host_class_storage_max_lun =
534                                 *trans -> ux_transfer_request_data_pointer;
535 
536             /* Is the max LUN index greater than our LUN array's?  */
537             if (storage -> ux_host_class_storage_max_lun > UX_MAX_HOST_LUN - 1)
538             {
539 
540                 /* Cap it off.  */
541                 storage -> ux_host_class_storage_max_lun =  UX_MAX_HOST_LUN - 1;
542 
543                 /* Notify application so it knows to increase UX_MAX_HOST_LUN.  */
544                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_MEMORY_ERROR);
545 
546                 /* If trace is enabled, insert this event into the trace buffer.  */
547                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_MEMORY_ERROR, storage, 0, 0, UX_TRACE_ERRORS, 0, 0)
548             }
549         }
550 
551         /* Allocated buffer for request must be freed here.  */
552         _ux_utility_memory_free(trans -> ux_transfer_request_data_pointer);
553     }
554 }
_ux_host_class_storage_inquiry_save(UX_HOST_CLASS_STORAGE * storage)555 static inline UINT _ux_host_class_storage_inquiry_save(UX_HOST_CLASS_STORAGE *storage)
556 {
557 UCHAR       *inquiry_response = storage -> ux_host_class_storage_trans_data;
558 UINT        lun_index = storage -> ux_host_class_storage_lun;
559     storage -> ux_host_class_storage_media_type = *(inquiry_response +
560                         UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_PERIPHERAL_TYPE);
561     storage -> ux_host_class_storage_lun_types[lun_index] =
562                                     storage -> ux_host_class_storage_media_type;
563     storage -> ux_host_class_storage_lun_removable_media_flags[lun_index] =
564                     *(inquiry_response +
565                         UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_REMOVABLE_MEDIA);
566 
567     /* Free response buffer.  */
568     _ux_utility_memory_free(inquiry_response);
569 
570     /* Set default sector size.  */
571     switch(storage -> ux_host_class_storage_media_type)
572     {
573     case UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK:
574     case UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK:
575         storage -> ux_host_class_storage_sector_size = UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT;
576         break;
577 
578     case UX_HOST_CLASS_STORAGE_MEDIA_CDROM:
579     case UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK:
580         storage -> ux_host_class_storage_sector_size = UX_HOST_CLASS_STORAGE_SECTOR_SIZE_OTHER;
581         break;
582 
583     default:
584 
585         /* Notify application so it knows to increase UX_MAX_HOST_LUN.  */
586         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_MEDIA_NOT_SUPPORTED);
587 
588         /* If trace is enabled, insert this event into the trace buffer.  */
589         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_MEDIA_NOT_SUPPORTED, storage, 0, 0, UX_TRACE_ERRORS, 0, 0)
590 
591         return(UX_HOST_CLASS_MEDIA_NOT_SUPPORTED);
592     }
593     return(UX_SUCCESS);
594 }
_ux_host_class_storage_capacity_save(UX_HOST_CLASS_STORAGE * storage)595 static inline VOID _ux_host_class_storage_capacity_save(UX_HOST_CLASS_STORAGE *storage)
596 {
597 UCHAR       *capacity_response = storage -> ux_host_class_storage_trans_data;
598 
599     /* If capacity response OK, save last LBA and LB size.  */
600     if (storage -> ux_host_class_storage_sense_code == 0)
601     {
602         storage -> ux_host_class_storage_last_sector_number =
603                     _ux_utility_long_get_big_endian(capacity_response +
604                                 UX_HOST_CLASS_STORAGE_READ_CAPACITY_DATA_LBA);
605         storage -> ux_host_class_storage_sector_size =
606                     _ux_utility_long_get_big_endian(capacity_response +
607                         UX_HOST_CLASS_STORAGE_READ_CAPACITY_DATA_SECTOR_SIZE);
608 
609         /* Media inserted to LUN.  */
610         _ux_host_class_storage_lun_media_insert(storage);
611     }
612 
613     /* Free allocated buffer.  */
614     _ux_utility_memory_free(capacity_response);
615 }
_ux_host_class_storage_format_cap_save(UX_HOST_CLASS_STORAGE * storage)616 static inline VOID _ux_host_class_storage_format_cap_save(UX_HOST_CLASS_STORAGE *storage)
617 {
618 UCHAR       *format_cap_response = storage -> ux_host_class_storage_trans_data;
619 
620     /* There is nothing to save.  */
621     /* Free allocated resource.  */
622     _ux_utility_memory_free(format_cap_response);
623 }
624 
_ux_host_class_storage_lun_scan(UX_HOST_CLASS_STORAGE * storage,ULONG do_unmount)625 static inline ULONG _ux_host_class_storage_lun_scan(UX_HOST_CLASS_STORAGE *storage,
626                                                     ULONG do_unmount)
627 {
628 UX_HOST_CLASS                       *class_inst;
629 UX_HOST_CLASS_STORAGE_MEDIA         *storage_media;
630 ULONG                               media_index;
631 ULONG                               n_found;
632 
633     /* We may need to unmount this partition if it was mounted before.
634         To do so, we need to parse the existing media instance and find out
635         if this partition was already mounted.  */
636     class_inst = storage -> ux_host_class_storage_class;
637     storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class_inst -> ux_host_class_media;
638 
639     /* Scan all instances of media.   */
640     for (media_index = 0, n_found = 0;
641         media_index < UX_HOST_CLASS_STORAGE_MAX_MEDIA;
642         storage_media++, media_index++)
643     {
644 
645         /* Check storage instance and lun number.  */
646         if (storage_media -> ux_host_class_storage_media_status != UX_USED)
647             continue;
648         if (storage_media -> ux_host_class_storage_media_storage != storage)
649             continue;
650         if (storage_media -> ux_host_class_storage_media_lun !=
651                                         storage -> ux_host_class_storage_lun)
652             continue;
653 
654         /* Found mounted media.  */
655         n_found ++;
656 
657         /* If no unmount, just check next media instance.  */
658         if (do_unmount == UX_FALSE)
659             continue;
660 
661         /* Free the storage media.  */
662         storage_media -> ux_host_class_storage_media_status = UX_UNUSED;
663 
664         /* Invoke callback for media removal.  */
665         if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
666         {
667 
668             /* Call system change function.  */
669             _ux_system_host ->  ux_system_host_change_function(UX_STORAGE_MEDIA_REMOVAL,
670                                 storage -> ux_host_class_storage_class,
671                                 (VOID *) storage_media);
672         }
673     }
674 
675     /* Return number of medias found and unmounted.  */
676     return(n_found);
677 }
678 
_ux_host_class_storage_unit_ready_check(UX_HOST_CLASS_STORAGE * storage)679 static inline VOID _ux_host_class_storage_unit_ready_check(UX_HOST_CLASS_STORAGE *storage)
680 {
681 ULONG           n;
682 
683     /* The LUN is ready.  */
684     if (storage -> ux_host_class_storage_sense_code == 0)
685     {
686 
687         /* Check if LUN is mounted.  */
688         n = _ux_host_class_storage_lun_scan(storage, UX_FALSE);
689 
690         /* If LUN is already mounted, check next LUN.  */
691         if (n > 0)
692         {
693 
694             /* LUN is mounted, just check next LUN.  */
695             storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_NEXT_LUN;
696             return;
697         }
698 
699         /* Next mounting steps : Inquiry() -> ReadFormatCapacity() -> mount().  */
700         storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_INQUIRY;
701         return;
702     }
703 
704     /* The LUN not ready cases have been done before.  */
705 
706     /* Just check next LUN.  */
707     storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_NEXT_LUN;
708 }
709 
_ux_host_class_storage_lun_is_removable(UX_HOST_CLASS_STORAGE * storage)710 static inline UINT _ux_host_class_storage_lun_is_removable(UX_HOST_CLASS_STORAGE *storage)
711 {
712 UINT    lun_index = storage -> ux_host_class_storage_lun;
713 UINT    removable = storage -> ux_host_class_storage_lun_removable_media_flags[lun_index] &
714                     UX_HOST_CLASS_STORAGE_MEDIA_REMOVABLE;
715     return(removable);
716 }
_ux_host_class_storage_lun_type_is_known(UX_HOST_CLASS_STORAGE * storage)717 static inline UINT _ux_host_class_storage_lun_type_is_known(UX_HOST_CLASS_STORAGE *storage)
718 {
719 UINT    lun_index = storage -> ux_host_class_storage_lun;
720 UINT    lun_type = storage -> ux_host_class_storage_lun_types[lun_index];
721     return((lun_type == UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK) ||
722            (lun_type == UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK) ||
723            (lun_type == UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK));
724 }
725 
_ux_host_class_storage_lun_media_insert(UX_HOST_CLASS_STORAGE * storage)726 static inline VOID _ux_host_class_storage_lun_media_insert(UX_HOST_CLASS_STORAGE *storage)
727 {
728 UX_HOST_CLASS                   *class_inst;
729 UX_HOST_CLASS_STORAGE_MEDIA     *storage_media;
730 INT                             media_index;
731 
732     /* Get class.  */
733     class_inst = storage -> ux_host_class_storage_class;
734 
735     /* Find a free media slot for inserted media.  */
736     storage_media =  (UX_HOST_CLASS_STORAGE_MEDIA *) class_inst -> ux_host_class_media;
737     for (media_index = 0; media_index < UX_HOST_CLASS_STORAGE_MAX_MEDIA;
738         storage_media ++, media_index ++)
739     {
740 
741         /* Skip used storage media slots.  */
742         if (storage_media -> ux_host_class_storage_media_status != UX_USED)
743         {
744 
745             /* Use this free storage media slot.  */
746             storage_media -> ux_host_class_storage_media_status = UX_USED;
747             storage_media -> ux_host_class_storage_media_storage = storage;
748 
749             /* Save media information.  */
750             storage_media -> ux_host_class_storage_media_lun = (UCHAR)storage -> ux_host_class_storage_lun;
751             storage_media -> ux_host_class_storage_media_sector_size = (USHORT)storage -> ux_host_class_storage_sector_size;
752             storage_media -> ux_host_class_storage_media_number_sectors = storage -> ux_host_class_storage_last_sector_number + 1;
753 
754             /* Invoke callback for media insertion.  */
755             if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
756             {
757 
758                 /* Call system change function.  */
759                 /* In standalone mode, no state running (read/write) expected in callback.  */
760                 _ux_system_host ->  ux_system_host_change_function(UX_STORAGE_MEDIA_INSERTION,
761                                     storage -> ux_host_class_storage_class, (VOID *) storage_media);
762             }
763 
764             /* Media saved OK.  */
765             return;
766         }
767     }
768 
769     /* No free slot.  */
770     return;
771 }
772 
_ux_host_class_storage_transport_sense_check(UX_HOST_CLASS_STORAGE * storage)773 static inline UINT _ux_host_class_storage_transport_sense_check(UX_HOST_CLASS_STORAGE *storage)
774 {
775 ULONG           sense_key;
776 
777     if (storage -> ux_host_class_storage_sense_code == 0)
778         return(UX_FALSE);
779 
780     sense_key = UX_HOST_CLASS_STORAGE_SENSE_KEY(storage -> ux_host_class_storage_sense_code);
781     switch(sense_key)
782     {
783     case UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY:
784 
785         /* Remove the mounted LUN media.  */
786         _ux_host_class_storage_lun_scan(storage, UX_TRUE);
787 
788         /* The LUN is not ready, check next any way.  */
789         storage -> ux_host_class_storage_state_state =
790                                         UX_HOST_CLASS_STORAGE_STATE_NEXT_LUN;
791 
792         /* We have changed state.  */
793         return(UX_TRUE);
794 
795     case UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION:
796 
797         /* Remove the mounted LUN media.  */
798         _ux_host_class_storage_lun_scan(storage, UX_TRUE);
799 
800         /* Do immediate ready check again.  */
801         storage -> ux_host_class_storage_state_state =
802                                     UX_HOST_CLASS_STORAGE_STATE_TEST_READY;
803 
804         /* We have changed state.  */
805         return(UX_TRUE);
806 
807     case UX_HOST_CLASS_STORAGE_SENSE_KEY_DATA_PROTECT:
808 
809         /* Fall through.  */
810     default:
811 
812         /* Nothing to do now.  */
813         break;
814     }
815 
816     /* State manated by others.  */
817     return(UX_FALSE);
818 }
819 #endif
820