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 VOID _ux_host_class_storage_read_initialize(UX_HOST_CLASS_STORAGE *storage,
34                 ULONG sector_start, ULONG sector_count);
35 
36 VOID
37 #else
38 static inline VOID
39 #endif
_ux_host_class_storage_read_initialize(UX_HOST_CLASS_STORAGE * storage,ULONG sector_start,ULONG sector_count)40 _ux_host_class_storage_read_initialize(UX_HOST_CLASS_STORAGE *storage,
41                 ULONG sector_start, ULONG sector_count)
42 {
43 UCHAR       *cbw;
44 UCHAR       *cbw_cb;
45 ULONG       command_length;
46 
47     /* Use a pointer for the cbw, easier to manipulate.  */
48     cbw = (UCHAR *)storage -> ux_host_class_storage_cbw;
49     cbw_cb = cbw + UX_HOST_CLASS_STORAGE_CBW_CB;
50 
51     /* Get the Read Command Length.  */
52 #ifdef UX_HOST_CLASS_STORAGE_INCLUDE_LEGACY_PROTOCOL_SUPPORT
53     if (storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceSubClass ==
54         UX_HOST_CLASS_STORAGE_SUBCLASS_UFI)
55         command_length =  UX_HOST_CLASS_STORAGE_READ_COMMAND_LENGTH_UFI;
56     else
57         command_length =  UX_HOST_CLASS_STORAGE_READ_COMMAND_LENGTH_SBC;
58 #else
59     command_length =  UX_HOST_CLASS_STORAGE_READ_COMMAND_LENGTH_SBC;
60 #endif
61 
62     /* Initialize the CBW for this command.  */
63     _ux_host_class_storage_cbw_initialize(storage,
64                     UX_HOST_CLASS_STORAGE_DATA_IN,
65                     sector_count * storage -> ux_host_class_storage_sector_size,
66                     command_length);
67 
68     /* Prepare the MEDIA READ command block.  */
69     *(cbw_cb + UX_HOST_CLASS_STORAGE_READ_OPERATION) =  UX_HOST_CLASS_STORAGE_SCSI_READ16;
70 
71     /* Store the sector start (LBA field).  */
72     _ux_utility_long_put_big_endian(cbw_cb + UX_HOST_CLASS_STORAGE_READ_LBA, sector_start);
73 
74     /* Store the number of sectors to read.  */
75     _ux_utility_short_put_big_endian(cbw_cb + UX_HOST_CLASS_STORAGE_READ_TRANSFER_LENGTH, (USHORT) sector_count);
76 }
77 
78 
79 /**************************************************************************/
80 /*                                                                        */
81 /*  FUNCTION                                               RELEASE        */
82 /*                                                                        */
83 /*    _ux_host_class_storage_media_read                   PORTABLE C      */
84 /*                                                           6.2.1        */
85 /*  AUTHOR                                                                */
86 /*                                                                        */
87 /*    Chaoqiong Xiao, Microsoft Corporation                               */
88 /*                                                                        */
89 /*  DESCRIPTION                                                           */
90 /*                                                                        */
91 /*    This function will read one or more logical sector from the media.  */
92 /*                                                                        */
93 /*  INPUT                                                                 */
94 /*                                                                        */
95 /*    storage                               Pointer to storage class      */
96 /*    sector_start                          Starting sector               */
97 /*    sector_count                          Number of sectors to read     */
98 /*    data_pointer                          Pointer to data to read       */
99 /*                                                                        */
100 /*  OUTPUT                                                                */
101 /*                                                                        */
102 /*    Completion Status                                                   */
103 /*                                                                        */
104 /*  CALLS                                                                 */
105 /*                                                                        */
106 /*    _ux_host_class_storage_cbw_initialize Initialize the CBW            */
107 /*    _ux_host_class_storage_transport      Send command                  */
108 /*    _ux_utility_long_put_big_endian       Put 32-bit word               */
109 /*    _ux_utility_short_put_big_endian      Put 16-bit word               */
110 /*                                                                        */
111 /*  CALLED BY                                                             */
112 /*                                                                        */
113 /*    Storage Class                                                       */
114 /*                                                                        */
115 /*  RELEASE HISTORY                                                       */
116 /*                                                                        */
117 /*    DATE              NAME                      DESCRIPTION             */
118 /*                                                                        */
119 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
120 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
121 /*                                            resulting in version 6.1    */
122 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
123 /*                                            added standalone support,   */
124 /*                                            resulting in version 6.1.10 */
125 /*  03-08-2023     Chaoqiong Xiao           Modified comment(s),          */
126 /*                                            checked device removal,     */
127 /*                                            resulting in version 6.2.1  */
128 /*                                                                        */
129 /**************************************************************************/
_ux_host_class_storage_media_read(UX_HOST_CLASS_STORAGE * storage,ULONG sector_start,ULONG sector_count,UCHAR * data_pointer)130 UINT  _ux_host_class_storage_media_read(UX_HOST_CLASS_STORAGE *storage, ULONG sector_start,
131                                     ULONG sector_count, UCHAR *data_pointer)
132 {
133 #if defined(UX_HOST_STANDALONE)
134 UINT            status;
135     do {
136         status = _ux_host_class_storage_read_write_run(storage, UX_TRUE,
137                                     sector_start, sector_count, data_pointer);
138     } while(status == UX_STATE_WAIT);
139     if (status < UX_STATE_IDLE)
140         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
141     return(storage -> ux_host_class_storage_status);
142 #else
143 UINT            status;
144 UINT            media_retry;
145 
146     /* If trace is enabled, insert this event into the trace buffer.  */
147     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_STORAGE_MEDIA_READ, storage, sector_start, sector_count, data_pointer, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
148 
149     /* Reset the retry count.  */
150     media_retry =  UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RETRY;
151 
152     /* We may need several attempts.  */
153     while (media_retry-- != 0)
154     {
155 
156         /* Initialize CBW.  */
157         _ux_host_class_storage_read_initialize(storage, sector_start, sector_count);
158 
159         /* Send the command to transport layer.  */
160         status =  _ux_host_class_storage_transport(storage, data_pointer);
161         if (status != UX_SUCCESS)
162             return(status);
163 
164         /* Did the command succeed?  */
165         if (storage -> ux_host_class_storage_sense_code == UX_SUCCESS)
166         {
167 
168             /* Check for completeness of sector read.  */
169             if (storage -> ux_host_class_storage_data_phase_length != sector_count * storage -> ux_host_class_storage_sector_size)
170             {
171 
172                 /* This can happen if the device sent less data than the host
173                    requested. This does not fit our definition of success and
174                    retrying shouldn't change the outcome, so we return an error.  */
175 
176                 /* We got an error during read. Packet not complete.  */
177                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_DATA_LESS_THAN_EXPECTED);
178 
179                 /* Return to UX_MEDIA (default FileX).  */
180                 return(UX_ERROR);
181             }
182 
183             /* The read succeeded.  */
184             return(UX_SUCCESS);
185         }
186 
187         /* The command did not succeed. Retry.  */
188     }
189 
190     /* Check if the media in the device has been removed. If so
191        we have to tell UX_MEDIA (default FileX) that the media is closed.  */
192     return(UX_HOST_CLASS_STORAGE_SENSE_ERROR);
193 #endif
194 }
195 
196 
197 /**************************************************************************/
198 /*                                                                        */
199 /*  FUNCTION                                               RELEASE        */
200 /*                                                                        */
201 /*    _ux_host_class_storage_media_read                   PORTABLE C      */
202 /*                                                           6.3.0        */
203 /*  AUTHOR                                                                */
204 /*                                                                        */
205 /*    Chaoqiong Xiao, Microsoft Corporation                               */
206 /*                                                                        */
207 /*  DESCRIPTION                                                           */
208 /*                                                                        */
209 /*    This function checks errors in storage media read function call.    */
210 /*                                                                        */
211 /*  INPUT                                                                 */
212 /*                                                                        */
213 /*    storage                               Pointer to storage class      */
214 /*    sector_start                          Starting sector               */
215 /*    sector_count                          Number of sectors to read     */
216 /*    data_pointer                          Pointer to data to read       */
217 /*                                                                        */
218 /*  OUTPUT                                                                */
219 /*                                                                        */
220 /*    Status                                                              */
221 /*                                                                        */
222 /*  CALLS                                                                 */
223 /*                                                                        */
224 /*    _ux_host_class_storage_media_read     Read storage media            */
225 /*                                                                        */
226 /*  CALLED BY                                                             */
227 /*                                                                        */
228 /*    Application                                                         */
229 /*                                                                        */
230 /*  RELEASE HISTORY                                                       */
231 /*                                                                        */
232 /*    DATE              NAME                      DESCRIPTION             */
233 /*                                                                        */
234 /*  10-31-2023     Chaoqiong Xiao           Initial Version 6.3.0         */
235 /*                                                                        */
236 /**************************************************************************/
_uxe_host_class_storage_media_read(UX_HOST_CLASS_STORAGE * storage,ULONG sector_start,ULONG sector_count,UCHAR * data_pointer)237 UINT  _uxe_host_class_storage_media_read(UX_HOST_CLASS_STORAGE *storage, ULONG sector_start,
238                                     ULONG sector_count, UCHAR *data_pointer)
239 {
240 
241     /* Sanity checks.  */
242     if ((storage == UX_NULL) || (data_pointer == UX_NULL))
243         return(UX_INVALID_PARAMETER);
244 
245     /* Invoke storage media read function.  */
246     return(_ux_host_class_storage_media_read(storage, sector_start, sector_count, data_pointer));
247 }
248