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 /**   Device 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_device_class_storage.h"
30 #include "ux_device_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_device_class_storage_read                       PORTABLE C      */
38 /*                                                           6.1.10       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function performs a READ command in 32 or 16 bits.             */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    storage                               Pointer to storage class      */
50 /*    endpoint_in                           Pointer to IN endpoint        */
51 /*    endpoint_out                          Pointer to OUT endpoint       */
52 /*    cbwcb                                 Pointer to CBWCB              */
53 /*    scsi_command                          SCSI command                  */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    Completion Status                                                   */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    (ux_slave_class_storage_media_read)   Read from media               */
62 /*    (ux_slave_class_storage_media_status) Get media status              */
63 /*    _ux_device_stack_endpoint_stall       Stall endpoint                */
64 /*    _ux_device_stack_transfer_request     Transfer request              */
65 /*    _ux_utility_long_get_big_endian       Get 32-bit big endian         */
66 /*    _ux_utility_short_get_big_endian      Get 16-bit big endian         */
67 /*    _ux_device_class_storage_csw_send     Send CSW                      */
68 /*                                                                        */
69 /*  CALLED BY                                                             */
70 /*                                                                        */
71 /*    Device Storage Class                                                */
72 /*                                                                        */
73 /*  RELEASE HISTORY                                                       */
74 /*                                                                        */
75 /*    DATE              NAME                      DESCRIPTION             */
76 /*                                                                        */
77 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
78 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
79 /*                                            optimized command logic,    */
80 /*                                            resulting in version 6.1    */
81 /*  12-31-2020     Chaoqiong Xiao           Modified comment(s),          */
82 /*                                            fixed USB CV test issues,   */
83 /*                                            resulting in version 6.1.3  */
84 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
85 /*                                            added standalone support,   */
86 /*                                            resulting in version 6.1.10 */
87 /*                                                                        */
88 /**************************************************************************/
_ux_device_class_storage_read(UX_SLAVE_CLASS_STORAGE * storage,ULONG lun,UX_SLAVE_ENDPOINT * endpoint_in,UX_SLAVE_ENDPOINT * endpoint_out,UCHAR * cbwcb,UCHAR scsi_command)89 UINT  _ux_device_class_storage_read(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun,
90                                             UX_SLAVE_ENDPOINT *endpoint_in,
91                                             UX_SLAVE_ENDPOINT *endpoint_out, UCHAR * cbwcb, UCHAR scsi_command)
92 {
93 
94 UINT                    status;
95 ULONG                   lba;
96 UX_SLAVE_TRANSFER       *transfer_request;
97 ULONG                   total_number_blocks;
98 ULONG                   media_status;
99 ULONG                   total_length;
100 
101 #if !defined(UX_DEVICE_STANDALONE)
102 ULONG                   number_blocks;
103 ULONG                   transfer_length;
104 ULONG                   done_length;
105 #endif
106 
107 
108     UX_PARAMETER_NOT_USED(endpoint_out);
109 
110     /* Get the LBA from the CBWCB.  */
111     lba =  _ux_utility_long_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_READ_LBA);
112 
113     /* The type of commands will tell us the width of the field containing the number
114        of sectors to read.  */
115     if (scsi_command == UX_SLAVE_CLASS_STORAGE_SCSI_READ16)
116 
117         /* Get the number of blocks from the CBWCB in 16 bits.  */
118         total_number_blocks =  _ux_utility_short_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_READ_TRANSFER_LENGTH_16);
119 
120     else
121 
122         /* Get the number of blocks from the CBWCB in 32 bits.  */
123         total_number_blocks =  _ux_utility_long_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_READ_TRANSFER_LENGTH_32);
124 
125     /* Obtain the pointer to the transfer request.  */
126     transfer_request =  &endpoint_in -> ux_slave_endpoint_transfer_request;
127 
128     /* Compute the total length to transfer and how much remains.  */
129     total_length =  total_number_blocks * storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_block_length;
130 
131     /* Default CSW to failed.  */
132     storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED;
133 
134 #if defined(UX_DEVICE_STANDALONE)
135 
136     /* Obtain the status of the device.  */
137     status =  storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_status(storage, lun,
138                                 storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_id, &media_status);
139 
140     /* Update the request sense.  */
141     storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = media_status;
142 
143     /* Update the request to use.  */
144     storage -> ux_device_class_storage_transfer = transfer_request;
145 
146     /* If there is a problem, return a failed command.  */
147     if (status != UX_SUCCESS)
148     {
149 
150         /* Update residue.  */
151         storage -> ux_slave_class_storage_csw_residue = storage -> ux_slave_class_storage_host_length;
152 
153         /* Return an error.  */
154         return(UX_ERROR);
155     }
156 
157     /* Next: Disk read -> Transfer (DATA).  */
158     storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_DISK_WAIT;
159     storage -> ux_device_class_storage_cmd_state = UX_DEVICE_CLASS_STORAGE_CMD_READ;
160     storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_OP_START;
161     storage -> ux_device_class_storage_buffer_state[0] = UX_DEVICE_CLASS_STORAGE_BUFFER_EMPTY;
162     storage -> ux_device_class_storage_buffer_state[1] = UX_DEVICE_CLASS_STORAGE_BUFFER_EMPTY;
163     storage -> ux_device_class_storage_buffer_usb = 1;
164     storage -> ux_device_class_storage_buffer_disk = 1;
165 
166     storage -> ux_device_class_storage_device_length = total_length;
167     storage -> ux_device_class_storage_data_length =
168         UX_MIN(total_length , storage -> ux_slave_class_storage_host_length);
169     storage -> ux_device_class_storage_data_count = 0;
170 
171     storage -> ux_device_class_storage_cmd_lba = lba;
172     storage -> ux_device_class_storage_cmd_n_lb = total_number_blocks;
173 
174 #else
175 
176     /* Check transfer length.  */
177 
178     /* Case (7).  Host length < device length.  */
179     if (total_length > storage -> ux_slave_class_storage_host_length)
180     {
181         _ux_device_stack_endpoint_stall(endpoint_in);
182         storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR;
183         return(UX_ERROR);
184     }
185 
186     /* Case (8). Hi <> Do.  */
187     if ((storage -> ux_slave_class_storage_cbw_flags & 0x80) == 0)
188     {
189         _ux_device_stack_endpoint_stall(endpoint_out);
190         storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR;
191         return(UX_ERROR);
192     }
193 
194     /* It may take several transfers to send the requested data.  */
195     done_length = 0;
196     while (total_number_blocks)
197     {
198 
199         /* Obtain the status of the device.  */
200         status =  storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_status(storage, lun,
201                                     storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_id, &media_status);
202 
203         /* Update the request sense.  */
204         storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = media_status;
205 
206         /* If there is a problem, return a failed command.  */
207         if (status != UX_SUCCESS)
208         {
209 
210             /* We have a problem, media status error. Return a bad completion and wait for the
211                REQUEST_SENSE command.  */
212             _ux_device_stack_endpoint_stall(endpoint_in);
213 
214             /* Update residue.  */
215             storage -> ux_slave_class_storage_csw_residue = storage -> ux_slave_class_storage_host_length - done_length;
216 
217             /* Return an error.  */
218             return(UX_ERROR);
219         }
220 
221         /* How much can we send in this transfer?  */
222         if (total_length > UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE)
223 
224             /* Compute the transfer length based on the maximum allowed.  */
225             transfer_length =  UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE;
226 
227         else
228 
229             /* Compute the transfer length based on what is left to transfer.  */
230             transfer_length =  total_length;
231 
232         /* Compute the number of blocks to transfer.  */
233         number_blocks = transfer_length / storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_block_length;
234 
235         /* If trace is enabled, insert this event into the trace buffer.  */
236         UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_STORAGE_READ, storage, lun, transfer_request -> ux_slave_transfer_request_data_pointer,
237                                 number_blocks, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
238 
239         /* Execute the read command from the local media.  */
240         status =  storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_read(storage, lun,
241                                                     transfer_request -> ux_slave_transfer_request_data_pointer, number_blocks, lba, &media_status);
242 
243         /* If there is a problem, return a failed command.  */
244         if (status != UX_SUCCESS)
245         {
246 
247             /* We have a problem, request error. Return a bad completion and wait for the
248                REQUEST_SENSE command.  */
249             _ux_device_stack_endpoint_stall(endpoint_in);
250 
251             /* Update residue.  */
252             storage -> ux_slave_class_storage_csw_residue = storage -> ux_slave_class_storage_host_length - done_length;
253 
254             /* And update the REQUEST_SENSE codes.  */
255             storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = media_status;
256 
257             /* Return an error.  */
258             return(UX_ERROR);
259         }
260 
261         /* Sends the data payload back to the caller.  */
262         status =  _ux_device_stack_transfer_request(transfer_request, transfer_length, transfer_length);
263 
264         /* Check the status.  */
265         if(status != UX_SUCCESS)
266         {
267 
268             /* We have a problem, request error. Return a bad completion and wait for the
269                REQUEST_SENSE command.  */
270             _ux_device_stack_endpoint_stall(endpoint_in);
271 
272             /* Update residue.  */
273             storage -> ux_slave_class_storage_csw_residue = storage -> ux_slave_class_storage_host_length - done_length;
274 
275             /* Update the REQUEST_SENSE codes.  */
276             storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status =
277                                                 UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00);
278 
279             /* Return an error.  */
280             return(UX_ERROR);
281 
282         }
283 
284         /* Update the LBA address.  */
285         lba += number_blocks;
286 
287         /* Update the length to remain.  */
288         total_length -= transfer_length;
289         done_length += transfer_length;
290 
291         /* Update the number of blocks to read.  */
292         total_number_blocks -= number_blocks;
293     }
294 
295     /* Case (4), (5). Host length too large.  */
296     if (storage -> ux_slave_class_storage_host_length > done_length)
297     {
298 
299         /* Stall Bulk-In.  */
300         _ux_device_stack_endpoint_stall(endpoint_in);
301 
302         /* Update residure.  */
303         storage -> ux_slave_class_storage_csw_residue = storage -> ux_slave_class_storage_host_length - done_length;
304     }
305 
306 #endif /* else defined(UX_DEVICE_STANDALONE) */
307 
308     /* Now we set the CSW with success.  */
309     storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PASSED;
310 
311     /* Return completion status.  */
312     return(UX_SUCCESS);
313 }
314