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