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_synchronize_cache          PORTABLE C      */
37 /*                                                           6.1.10       */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function performs a SYNCHRONIZE_CACHE command in 32 or 16      */
45 /*    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 the CBWCB          */
53 /*    scsi_command                          SCSI command                  */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    Completion Status                                                   */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    (ux_slave_class_storage_media_status) Get media status              */
62 /*    (ux_slave_class_storage_media_flush)  Flush media                   */
63 /*    _ux_device_class_storage_csw_send     Send CSW                      */
64 /*    _ux_device_stack_endpoint_stall       Stall endpoint                */
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 /*                                                                        */
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 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
81 /*                                            added standalone support,   */
82 /*                                            resulting in version 6.1.10 */
83 /*                                                                        */
84 /**************************************************************************/
_ux_device_class_storage_synchronize_cache(UX_SLAVE_CLASS_STORAGE * storage,ULONG lun,UX_SLAVE_ENDPOINT * endpoint_in,UX_SLAVE_ENDPOINT * endpoint_out,UCHAR * cbwcb,UCHAR scsi_command)85 UINT  _ux_device_class_storage_synchronize_cache(UX_SLAVE_CLASS_STORAGE *storage, ULONG lun,
86                                                  UX_SLAVE_ENDPOINT *endpoint_in,
87                                                  UX_SLAVE_ENDPOINT *endpoint_out, UCHAR *cbwcb, UCHAR scsi_command)
88 {
89 
90 UINT                    status;
91 ULONG                   lba;
92 USHORT                  number_blocks;
93 ULONG                   media_status;
94 
95 #if !defined(UX_DEVICE_STANDALONE)
96 UCHAR                   flags;
97 #endif
98 
99 
100     UX_PARAMETER_NOT_USED(endpoint_out);
101     UX_PARAMETER_NOT_USED(scsi_command);
102 
103     /* By default status is passed.  */
104     storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PASSED;
105 
106     /* Is there not an implementation?  */
107     if (storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_flush == UX_NULL)
108     {
109 
110         /* This means the application is not using a cache.  */
111 
112         /* Return success.  */
113         return(UX_SUCCESS);
114     }
115 
116     /* Get the LBA and number of blocks from the CBWCB in 16 bits.  */
117     lba           =         _ux_utility_long_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_LBA);
118     number_blocks = (USHORT)_ux_utility_short_get_big_endian(cbwcb + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_NUMBER_OF_BLOCKS);
119 
120     /* If trace is enabled, insert this event into the trace buffer.  */
121     UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_STORAGE_SYNCHRONIZE_CACHE, storage, lun, lba, number_blocks, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
122 
123     /* Obtain the status of the device.  */
124     status =  storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_status(storage,
125                             lun, storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_id, &media_status);
126 
127     /* Update the request sense.  */
128     storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = media_status;
129 
130     /* If there is a problem, return a failed command.  */
131     if (status != UX_SUCCESS)
132     {
133 
134         /* We have a problem, media status error. Return a bad completion and wait for the
135            REQUEST_SENSE command.  */
136 #if !defined(UX_DEVICE_STANDALONE)
137         _ux_device_stack_endpoint_stall(endpoint_in);
138 #else
139         UX_PARAMETER_NOT_USED(endpoint_in);
140         storage -> ux_device_class_storage_cmd_state = UX_DEVICE_CLASS_STORAGE_CMD_ERR;
141 #endif
142 
143         storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED;
144 
145         /* We are done here.  */
146         return(UX_ERROR);
147     }
148 
149     /* Now it's OK to perform synchronize cache.  */
150 
151 #if defined(UX_DEVICE_STANDALONE)
152 
153     /* Next: Disk (SYNC).  */
154     storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_DISK_WAIT;
155     storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_OP_START;
156     storage -> ux_device_class_storage_cmd_state = UX_DEVICE_CLASS_STORAGE_CMD_DISK_OP;
157 
158     storage -> ux_device_class_storage_cmd_lba = lba;
159     storage -> ux_device_class_storage_cmd_n_lb = number_blocks;
160 
161 #else
162 
163     /* Get the flags.  */
164     flags =  *(cbwcb + UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS);
165 
166     /* If the immediate bit is set, we return a CSW before flush.  */
167     if ((flags & UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS_IMMED) != 0)
168         _ux_device_class_storage_csw_send(storage, lun, endpoint_in, UX_SLAVE_CLASS_STORAGE_CSW_PASSED);
169 
170     /* Send the flush command to the local media.  */
171     status =  storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_media_flush(storage, lun, number_blocks, lba, &media_status);
172 
173     /* Update the request sense.  */
174     storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = media_status;
175 
176     /* If the immediate bit is set, we are already done, no matter what local operation status is.  */
177     if ((flags & UX_SLAVE_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS_IMMED) != 0)
178     {
179 
180         /* CSW skipped since already sent in this function.  */
181         UX_DEVICE_CLASS_STORAGE_CSW_SKIP(&storage -> ux_slave_class_storage_csw_status) = UX_TRUE;
182         return(status);
183     }
184 
185     /* If there is a problem, return a failed command.  */
186     if (status != UX_SUCCESS)
187     {
188 
189         /* We have a problem, request error. Return a bad completion and wait for the
190            REQUEST_SENSE command.  */
191         _ux_device_stack_endpoint_stall(endpoint_in);
192 
193         storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED;
194 
195         /* Return an error.  */
196         return(UX_ERROR);
197     }
198 #endif
199 
200     /* Return completion status.  */
201     return(status);
202 }
203