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