1 /*!
2     \file    usbd_msc_scsi.c
3     \brief   USB SCSI layer functions
4 
5     \version 2020-08-04, V1.1.0, firmware for GD32VF103
6 */
7 
8 /*
9     Copyright (c) 2020, GigaDevice Semiconductor Inc.
10 
11     Redistribution and use in source and binary forms, with or without modification,
12 are permitted provided that the following conditions are met:
13 
14     1. Redistributions of source code must retain the above copyright notice, this
15        list of conditions and the following disclaimer.
16     2. Redistributions in binary form must reproduce the above copyright notice,
17        this list of conditions and the following disclaimer in the documentation
18        and/or other materials provided with the distribution.
19     3. Neither the name of the copyright holder nor the names of its contributors
20        may be used to endorse or promote products derived from this software without
21        specific prior written permission.
22 
23     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 OF SUCH DAMAGE.
33 */
34 
35 #include "usbd_enum.h"
36 #include "usbd_msc_bbb.h"
37 #include "usbd_msc_scsi.h"
38 #include "usbd_msc_data.h"
39 
40 /* local function prototypes ('static') */
41 static int8_t scsi_test_unit_ready      (usb_core_driver *pudev, uint8_t lun, uint8_t *params);
42 static int8_t scsi_inquiry              (usb_core_driver *pudev, uint8_t lun, uint8_t *params);
43 static int8_t scsi_read_format_capacity (usb_core_driver *pudev, uint8_t lun, uint8_t *params);
44 static int8_t scsi_read_capacity10      (usb_core_driver *pudev, uint8_t lun, uint8_t *params);
45 static int8_t scsi_request_sense        (usb_core_driver *pudev, uint8_t lun, uint8_t *params);
46 static int8_t scsi_mode_sense6          (usb_core_driver *pudev, uint8_t lun, uint8_t *params);
47 static int8_t scsi_toc_cmd_read         (usb_core_driver *pudev, uint8_t lun, uint8_t *params);
48 static int8_t scsi_mode_sense10         (usb_core_driver *pudev, uint8_t lun, uint8_t *params);
49 static int8_t scsi_write10              (usb_core_driver *pudev, uint8_t lun, uint8_t *params);
50 static int8_t scsi_read10               (usb_core_driver *pudev, uint8_t lun, uint8_t *params);
51 static int8_t scsi_verify10             (usb_core_driver *pudev, uint8_t lun, uint8_t *params);
52 static int8_t scsi_process_read         (usb_core_driver *pudev, uint8_t lun);
53 static int8_t scsi_process_write        (usb_core_driver *pudev, uint8_t lun);
54 
55 static inline int8_t scsi_check_address_range  (usb_core_driver *pudev, uint8_t lun, uint32_t blk_offset, uint16_t blk_nbr);
56 static inline int8_t scsi_format_cmd           (usb_core_driver *pudev, uint8_t lun);
57 static inline int8_t scsi_start_stop_unit      (usb_core_driver *pudev, uint8_t lun, uint8_t *params);
58 static inline int8_t scsi_allow_medium_removal (usb_core_driver *pudev, uint8_t lun, uint8_t *params);
59 
60 /*!
61     \brief      process SCSI commands
62     \param[in]  pudev: pointer to USB device instance
63     \param[in]  lun: logical unit number
64     \param[in]  params: command parameters
65     \param[out] none
66     \retval     status
67 */
scsi_process_cmd(usb_core_driver * pudev,uint8_t lun,uint8_t * params)68 int8_t scsi_process_cmd(usb_core_driver *pudev, uint8_t lun, uint8_t *params)
69 {
70     switch (params[0]) {
71     case SCSI_TEST_UNIT_READY:
72         return scsi_test_unit_ready (pudev, lun, params);
73 
74     case SCSI_REQUEST_SENSE:
75         return scsi_request_sense (pudev, lun, params);
76 
77     case SCSI_INQUIRY:
78         return scsi_inquiry (pudev, lun, params);
79 
80     case SCSI_START_STOP_UNIT:
81         return scsi_start_stop_unit (pudev, lun, params);
82 
83     case SCSI_ALLOW_MEDIUM_REMOVAL:
84         return scsi_allow_medium_removal (pudev, lun, params);
85 
86     case SCSI_MODE_SENSE6:
87         return scsi_mode_sense6 (pudev, lun, params);
88 
89     case SCSI_MODE_SENSE10:
90         return scsi_mode_sense10 (pudev, lun, params);
91 
92     case SCSI_READ_FORMAT_CAPACITIES:
93         return scsi_read_format_capacity (pudev, lun, params);
94 
95     case SCSI_READ_CAPACITY10:
96         return scsi_read_capacity10 (pudev, lun, params);
97 
98     case SCSI_READ10:
99         return scsi_read10 (pudev, lun, params);
100 
101     case SCSI_WRITE10:
102         return scsi_write10 (pudev, lun, params);
103 
104     case SCSI_VERIFY10:
105         return scsi_verify10 (pudev, lun, params);
106 
107     case SCSI_FORMAT_UNIT:
108         return scsi_format_cmd (pudev, lun);
109 
110     case SCSI_READ_TOC_DATA:
111         return scsi_toc_cmd_read (pudev, lun, params);
112 
113     default:
114         scsi_sense_code (pudev, lun, ILLEGAL_REQUEST, INVALID_CDB);
115         return -1;
116     }
117 }
118 
119 /*!
120     \brief      load the last error code in the error list
121     \param[in]  pudev: pointer to USB device instance
122     \param[in]  lun: logical unit number
123     \param[in]  skey: sense key
124     \param[in]  asc: additional aense key
125     \param[out] none
126     \retval     none
127 */
scsi_sense_code(usb_core_driver * pudev,uint8_t lun,uint8_t skey,uint8_t asc)128 void scsi_sense_code (usb_core_driver *pudev, uint8_t lun, uint8_t skey, uint8_t asc)
129 {
130     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
131 
132     msc->scsi_sense[msc->scsi_sense_tail].SenseKey = skey;
133     msc->scsi_sense[msc->scsi_sense_tail].ASC = asc << 8U;
134     msc->scsi_sense_tail++;
135 
136     if (SENSE_LIST_DEEPTH == msc->scsi_sense_tail) {
137         msc->scsi_sense_tail = 0U;
138     }
139 }
140 
141 /*!
142     \brief      process SCSI Test Unit Ready command
143     \param[in]  pudev: pointer to USB device instance
144     \param[in]  lun: logical unit number
145     \param[in]  params: command parameters
146     \param[out] none
147     \retval     status
148 */
scsi_test_unit_ready(usb_core_driver * pudev,uint8_t lun,uint8_t * params)149 static int8_t scsi_test_unit_ready (usb_core_driver *pudev, uint8_t lun, uint8_t *params)
150 {
151     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
152 
153     /* case 9 : Hi > D0 */
154     if (0U != msc->bbb_cbw.dCBWDataTransferLength) {
155         scsi_sense_code (pudev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
156 
157         return -1;
158     }
159 
160     if (0 != usbd_mem_fops->mem_ready(lun)) {
161         scsi_sense_code(pudev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
162 
163         return -1;
164     }
165 
166     if (1U == msc->scsi_disk_pop) {
167         usbd_disconnect (pudev);
168     }
169 
170     msc->bbb_datalen = 0U;
171 
172     return 0;
173 }
174 
175 /*!
176     \brief      process Inquiry command
177     \param[in]  pudev: pointer to USB device instance
178     \param[in]  lun: logical unit number
179     \param[in]  params: command parameters
180     \param[out] none
181     \retval     status
182 */
scsi_inquiry(usb_core_driver * pudev,uint8_t lun,uint8_t * params)183 static int8_t scsi_inquiry (usb_core_driver *pudev, uint8_t lun, uint8_t *params)
184 {
185     uint8_t *page = NULL;
186     uint16_t len = 0U;
187 
188     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
189 
190     if (params[1] & 0x01U) {
191         /* Evpd is set */
192         page = (uint8_t *)msc_page00_inquiry_data;
193 
194         len = INQUIRY_PAGE00_LENGTH;
195     } else {
196         page = (uint8_t *)usbd_mem_fops->mem_inquiry_data[lun];
197 
198         len = (uint16_t)(page[4] + 5U);
199 
200         if (params[4] <= len) {
201             len = params[4];
202         }
203     }
204 
205     msc->bbb_datalen = len;
206 
207     while (len) {
208         len--;
209         msc->bbb_data[len] = page[len];
210     }
211 
212     return 0;
213 }
214 
215 /*!
216     \brief      process Read Capacity 10 command
217     \param[in]  pudev: pointer to USB device instance
218     \param[in]  lun: logical unit number
219     \param[in]  params: command parameters
220     \param[out] none
221     \retval     status
222 */
scsi_read_capacity10(usb_core_driver * pudev,uint8_t lun,uint8_t * params)223 static int8_t scsi_read_capacity10 (usb_core_driver *pudev, uint8_t lun, uint8_t *params)
224 {
225     uint32_t blk_num = usbd_mem_fops->mem_block_len[lun] - 1U;
226     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
227 
228     msc->scsi_blk_nbr[lun] = usbd_mem_fops->mem_block_len[lun];
229     msc->scsi_blk_size[lun] = usbd_mem_fops->mem_block_size[lun];
230 
231     msc->bbb_data[0] = (uint8_t)(blk_num >> 24U);
232     msc->bbb_data[1] = (uint8_t)(blk_num >> 16U);
233     msc->bbb_data[2] = (uint8_t)(blk_num >> 8U);
234     msc->bbb_data[3] = (uint8_t)(blk_num);
235 
236     msc->bbb_data[4] = (uint8_t)(msc->scsi_blk_size[lun] >> 24U);
237     msc->bbb_data[5] = (uint8_t)(msc->scsi_blk_size[lun] >> 16U);
238     msc->bbb_data[6] = (uint8_t)(msc->scsi_blk_size[lun] >> 8U);
239     msc->bbb_data[7] = (uint8_t)(msc->scsi_blk_size[lun]);
240 
241     msc->bbb_datalen = 8U;
242 
243     return 0;
244 }
245 
246 /*!
247     \brief      process Read Format Capacity command
248     \param[in]  pudev: pointer to USB device instance
249     \param[in]  lun: logical unit number
250     \param[in]  params: command parameters
251     \param[out] none
252     \retval     status
253 */
scsi_read_format_capacity(usb_core_driver * pudev,uint8_t lun,uint8_t * params)254 static int8_t scsi_read_format_capacity (usb_core_driver *pudev, uint8_t lun, uint8_t *params)
255 {
256     uint16_t i = 0U;
257     uint32_t blk_size = usbd_mem_fops->mem_block_size[lun];
258     uint32_t blk_num = usbd_mem_fops->mem_block_len[lun];
259     uint32_t blk_nbr = blk_num - 1U;
260 
261     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
262 
263     for (i = 0U; i < 12U; i++) {
264         msc->bbb_data[i] = 0U;
265     }
266 
267     msc->bbb_data[3] = 0x08U;
268     msc->bbb_data[4] = (uint8_t)(blk_nbr >> 24U);
269     msc->bbb_data[5] = (uint8_t)(blk_nbr >> 16U);
270     msc->bbb_data[6] = (uint8_t)(blk_nbr >>  8U);
271     msc->bbb_data[7] = (uint8_t)(blk_nbr);
272 
273     msc->bbb_data[8] = 0x02U;
274     msc->bbb_data[9] = (uint8_t)(blk_size >> 16U);
275     msc->bbb_data[10] = (uint8_t)(blk_size >> 8U);
276     msc->bbb_data[11] = (uint8_t)(blk_size);
277 
278     msc->bbb_datalen = 12U;
279 
280     return 0;
281 }
282 
283 /*!
284     \brief      process Mode Sense6 command
285     \param[in]  pudev: pointer to USB device instance
286     \param[in]  lun: logical unit number
287     \param[in]  params: command parameters
288     \param[out] none
289     \retval     status
290 */
scsi_mode_sense6(usb_core_driver * pudev,uint8_t lun,uint8_t * params)291 static int8_t scsi_mode_sense6 (usb_core_driver *pudev, uint8_t lun, uint8_t *params)
292 {
293     uint16_t len = 8U;
294     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
295 
296     msc->bbb_datalen = len;
297 
298     while (len) {
299         len--;
300         msc->bbb_data[len] = msc_mode_sense6_data[len];
301     }
302 
303     return 0;
304 }
305 
306 /*!
307     \brief      process Mode Sense10 command
308     \param[in]  pudev: pointer to USB device instance
309     \param[in]  lun: logical unit number
310     \param[in]  params: command parameters
311     \param[out] none
312     \retval     status
313 */
scsi_mode_sense10(usb_core_driver * pudev,uint8_t lun,uint8_t * params)314 static int8_t scsi_mode_sense10 (usb_core_driver *pudev, uint8_t lun, uint8_t *params)
315 {
316     uint16_t len = 8U;
317     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
318 
319     msc->bbb_datalen = len;
320 
321     while (len) {
322         len--;
323         msc->bbb_data[len] = msc_mode_sense10_data[len];
324     }
325 
326     return 0;
327 }
328 
329 /*!
330     \brief      process Request Sense command
331     \param[in]  pudev: pointer to USB device instance
332     \param[in]  lun: logical unit number
333     \param[in]  params: command parameters
334     \param[out] none
335     \retval     status
336 */
scsi_request_sense(usb_core_driver * pudev,uint8_t lun,uint8_t * params)337 static int8_t scsi_request_sense (usb_core_driver *pudev, uint8_t lun, uint8_t *params)
338 {
339     uint8_t i = 0U;
340     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
341 
342     for (i = 0U; i < REQUEST_SENSE_DATA_LEN; i++) {
343         msc->bbb_data[i] = 0U;
344     }
345 
346     msc->bbb_data[0] = 0x70U;
347     msc->bbb_data[7] = REQUEST_SENSE_DATA_LEN - 6U;
348 
349     if ((msc->scsi_sense_head != msc->scsi_sense_tail)) {
350         msc->bbb_data[2] = msc->scsi_sense[msc->scsi_sense_head].SenseKey;
351         msc->bbb_data[12] = msc->scsi_sense[msc->scsi_sense_head].ASCQ;
352         msc->bbb_data[13] = msc->scsi_sense[msc->scsi_sense_head].ASC;
353         msc->scsi_sense_head++;
354 
355         if (msc->scsi_sense_head == SENSE_LIST_DEEPTH) {
356             msc->scsi_sense_head = 0U;
357         }
358     }
359 
360     msc->bbb_datalen = USB_MIN(REQUEST_SENSE_DATA_LEN, params[4]);
361 
362     return 0;
363 }
364 
365 /*!
366     \brief      process Start Stop Unit command
367     \param[in]  pudev: pointer to USB device instance
368     \param[in]  lun: logical unit number
369     \param[in]  params: command parameters
370     \param[out] none
371     \retval     status
372 */
scsi_start_stop_unit(usb_core_driver * pudev,uint8_t lun,uint8_t * params)373 static inline int8_t scsi_start_stop_unit (usb_core_driver *pudev, uint8_t lun, uint8_t *params)
374 {
375     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
376 
377     msc->bbb_datalen = 0U;
378     msc->scsi_disk_pop = 1U;
379 
380     return 0;
381 }
382 
383 /*!
384     \brief      process Allow Medium Removal command
385     \param[in]  pudev: pointer to USB device instance
386     \param[in]  lun: logical unit number
387     \param[in]  params: command parameters
388     \param[out] none
389     \retval     status
390 */
scsi_allow_medium_removal(usb_core_driver * pudev,uint8_t lun,uint8_t * params)391 static inline int8_t scsi_allow_medium_removal (usb_core_driver *pudev, uint8_t lun, uint8_t *params)
392 {
393     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
394 
395     msc->bbb_datalen = 0U;
396 
397     return 0;
398 }
399 
400 /*!
401     \brief      process Read10 command
402     \param[in]  pudev: pointer to USB device instance
403     \param[in]  lun: logical unit number
404     \param[in]  params: command parameters
405     \param[out] none
406     \retval     status
407 */
scsi_read10(usb_core_driver * pudev,uint8_t lun,uint8_t * params)408 static int8_t scsi_read10 (usb_core_driver *pudev, uint8_t lun, uint8_t *params)
409 {
410     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
411 
412     if (msc->bbb_state == BBB_IDLE) {
413         /* direction is from device to host */
414         if (0x80U != (msc->bbb_cbw.bmCBWFlags & 0x80U)) {
415             scsi_sense_code (pudev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
416 
417             return -1;
418         }
419 
420         if (0 != usbd_mem_fops->mem_ready(lun)) {
421             scsi_sense_code (pudev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
422 
423             return -1;
424         }
425 
426         msc->scsi_blk_addr = (params[2] << 24U) | (params[3] << 16U) | \
427                              (params[4] << 8U) |  params[5];
428 
429         msc->scsi_blk_len = (params[7] << 8U) | params[8];
430 
431         if (scsi_check_address_range (pudev, lun, msc->scsi_blk_addr, (uint16_t)msc->scsi_blk_len) < 0) {
432             return -1; /* error */
433         }
434 
435         msc->bbb_state = BBB_DATA_IN;
436 
437         msc->scsi_blk_addr *= msc->scsi_blk_size[lun];
438         msc->scsi_blk_len  *= msc->scsi_blk_size[lun];
439 
440         /* cases 4,5 : Hi <> Dn */
441         if (msc->bbb_cbw.dCBWDataTransferLength != msc->scsi_blk_len) {
442             scsi_sense_code (pudev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
443 
444             return -1;
445         }
446     }
447 
448     msc->bbb_datalen = MSC_MEDIA_PACKET_SIZE;
449 
450     return scsi_process_read (pudev, lun);
451 }
452 
453 /*!
454     \brief      process Write10 command
455     \param[in]  pudev: pointer to USB device instance
456     \param[in]  lun: logical unit number
457     \param[in]  params: command parameters
458     \param[out] none
459     \retval     status
460 */
scsi_write10(usb_core_driver * pudev,uint8_t lun,uint8_t * params)461 static int8_t scsi_write10 (usb_core_driver *pudev, uint8_t lun, uint8_t *params)
462 {
463     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
464 
465     if (BBB_IDLE == msc->bbb_state) {
466         /* case 8 : Hi <> Do */
467         if (0x80U == (msc->bbb_cbw.bmCBWFlags & 0x80U)) {
468             scsi_sense_code (pudev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
469 
470             return -1;
471         }
472 
473         /* check whether media is ready */
474         if (0 != usbd_mem_fops->mem_ready(lun)) {
475             scsi_sense_code (pudev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
476 
477             return -1;
478         }
479 
480         /* check if media is write-protected */
481         if (0 != usbd_mem_fops->mem_protected(lun)) {
482             scsi_sense_code (pudev, lun, NOT_READY, WRITE_PROTECTED);
483 
484             return -1;
485         }
486 
487         msc->scsi_blk_addr = (params[2] << 24U) | (params[3] << 16U) | \
488                              (params[4] << 8U) |  params[5];
489 
490         msc->scsi_blk_len = (params[7] << 8U) | params[8];
491 
492         /* check if LBA address is in the right range */
493         if (scsi_check_address_range (pudev, lun, msc->scsi_blk_addr, (uint16_t)msc->scsi_blk_len) < 0) {
494             return -1; /* error */
495         }
496 
497         msc->scsi_blk_addr *= msc->scsi_blk_size[lun];
498         msc->scsi_blk_len  *= msc->scsi_blk_size[lun];
499 
500         /* cases 3,11,13 : Hn,Ho <> D0 */
501         if (msc->bbb_cbw.dCBWDataTransferLength != msc->scsi_blk_len) {
502             scsi_sense_code (pudev, msc->bbb_cbw.bCBWLUN, ILLEGAL_REQUEST, INVALID_CDB);
503 
504             return -1;
505         }
506 
507         /* prepare endpoint to receive first data packet */
508         msc->bbb_state = BBB_DATA_OUT;
509 
510         usbd_ep_recev (pudev,
511                        MSC_OUT_EP,
512                        msc->bbb_data,
513                        USB_MIN (msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE));
514     } else { /* write process ongoing */
515         return scsi_process_write (pudev, lun);
516     }
517 
518     return 0;
519 }
520 
521 /*!
522     \brief      process Verify10 command
523     \param[in]  pudev: pointer to USB device instance
524     \param[in]  lun: logical unit number
525     \param[in]  params: command parameters
526     \param[out] none
527     \retval     status
528 */
scsi_verify10(usb_core_driver * pudev,uint8_t lun,uint8_t * params)529 static int8_t scsi_verify10 (usb_core_driver *pudev, uint8_t lun, uint8_t *params)
530 {
531     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
532 
533     if (0x02U == (params[1] & 0x02U)) {
534         scsi_sense_code (pudev, lun, ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);
535 
536         return -1; /* error, verify mode not supported*/
537     }
538 
539     if (scsi_check_address_range (pudev, lun, msc->scsi_blk_addr, (uint16_t)msc->scsi_blk_len) < 0) {
540         return -1; /* error */
541     }
542 
543     msc->bbb_datalen = 0U;
544 
545     return 0;
546 }
547 
548 /*!
549     \brief      check address range
550     \param[in]  pudev: pointer to USB device instance
551     \param[in]  lun: logical unit number
552     \param[in]  blk_offset: block offset
553     \param[in]  blk_nbr: number of block to be processed
554     \param[out] none
555     \retval     status
556 */
scsi_check_address_range(usb_core_driver * pudev,uint8_t lun,uint32_t blk_offset,uint16_t blk_nbr)557 static inline int8_t scsi_check_address_range (usb_core_driver *pudev, uint8_t lun, uint32_t blk_offset, uint16_t blk_nbr)
558 {
559     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
560 
561     if ((blk_offset + blk_nbr) > msc->scsi_blk_nbr[lun]) {
562         scsi_sense_code (pudev, lun, ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
563 
564         return -1;
565     }
566 
567     return 0;
568 }
569 
570 /*!
571     \brief      handle read process
572     \param[in]  pudev: pointer to USB device instance
573     \param[in]  lun: logical unit number
574     \param[out] none
575     \retval     status
576 */
scsi_process_read(usb_core_driver * pudev,uint8_t lun)577 static int8_t scsi_process_read (usb_core_driver *pudev, uint8_t lun)
578 {
579     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
580 
581     uint32_t len = USB_MIN(msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE);
582 
583     if (usbd_mem_fops->mem_read(lun,
584                                 msc->bbb_data,
585                                 msc->scsi_blk_addr,
586                                 (uint16_t)(len / msc->scsi_blk_size[lun])) < 0) {
587         scsi_sense_code(pudev, lun, HARDWARE_ERROR, UNRECOVERED_READ_ERROR);
588 
589         return -1;
590     }
591 
592     usbd_ep_send (pudev, MSC_IN_EP, msc->bbb_data, len);
593 
594     msc->scsi_blk_addr += len;
595     msc->scsi_blk_len  -= len;
596 
597     /* case 6 : Hi = Di */
598     msc->bbb_csw.dCSWDataResidue -= len;
599 
600     if (0U == msc->scsi_blk_len) {
601         msc->bbb_state = BBB_LAST_DATA_IN;
602     }
603 
604     return 0;
605 }
606 
607 /*!
608     \brief      handle write process
609     \param[in]  pudev: pointer to USB device instance
610     \param[in]  lun: logical unit number
611     \param[out] none
612     \retval     status
613 */
scsi_process_write(usb_core_driver * pudev,uint8_t lun)614 static int8_t scsi_process_write (usb_core_driver *pudev, uint8_t lun)
615 {
616     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
617 
618     uint32_t len = USB_MIN(msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE);
619 
620     if (usbd_mem_fops->mem_write (lun,
621                                   msc->bbb_data,
622                                   msc->scsi_blk_addr,
623                                   (uint16_t)(len / msc->scsi_blk_size[lun])) < 0) {
624         scsi_sense_code(pudev, lun, HARDWARE_ERROR, WRITE_FAULT);
625 
626         return -1;
627     }
628 
629     msc->scsi_blk_addr += len;
630     msc->scsi_blk_len  -= len;
631 
632     /* case 12 : Ho = Do */
633     msc->bbb_csw.dCSWDataResidue -= len;
634 
635     if (0U == msc->scsi_blk_len) {
636         msc_bbb_csw_send (pudev, CSW_CMD_PASSED);
637     } else {
638         /* prapare endpoint to receive next packet */
639         usbd_ep_recev (pudev,
640                        MSC_OUT_EP,
641                        msc->bbb_data,
642                        USB_MIN (msc->scsi_blk_len, MSC_MEDIA_PACKET_SIZE));
643     }
644 
645     return 0;
646 }
647 
648 /*!
649     \brief      process Format Unit command
650     \param[in]  pudev: pointer to USB device instance
651     \param[in]  lun: logical unit number
652     \param[out] none
653     \retval     status
654 */
scsi_format_cmd(usb_core_driver * pudev,uint8_t lun)655 static inline int8_t scsi_format_cmd (usb_core_driver *pudev, uint8_t lun)
656 {
657     return 0;
658 }
659 
660 /*!
661     \brief      process Read_Toc command
662     \param[in]  pudev: pointer to USB device instance
663     \param[in]  lun: logical unit number
664     \param[in]  params: command parameters
665     \param[out] none
666     \retval     status
667 */
scsi_toc_cmd_read(usb_core_driver * pudev,uint8_t lun,uint8_t * params)668 static int8_t scsi_toc_cmd_read (usb_core_driver *pudev, uint8_t lun, uint8_t *params)
669 {
670     uint8_t* pPage;
671     uint16_t len;
672 
673     usbd_msc_handler *msc = (usbd_msc_handler *)pudev->dev.class_data[USBD_MSC_INTERFACE];
674 
675     pPage = (uint8_t *)&usbd_mem_fops->mem_toc_data[lun * READ_TOC_CMD_LEN];
676     len = (uint16_t)pPage[1] + 2U;
677 
678     msc->bbb_datalen = len;
679 
680     while (len) {
681         len--;
682         msc->bbb_data[len] = pPage[len];
683     }
684 
685     return 0;
686 }
687