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