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