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