2 ******************************************************************************
3 * @file usbd_msc_scsi.c
4 * @author MCD Application Team
7 * @brief This file provides all the USBD SCSI layer functions.
8 ******************************************************************************
11 * <h2><center>© COPYRIGHT 2015 STMicroelectronics</center></h2>
13 * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
14 * You may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at:
17 * http://www.st.com/software_license_agreement_liberty_v2
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS,
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
25 ******************************************************************************
28 /* Includes ------------------------------------------------------------------*/
29 #include "usbd_composite.h"
30 #include "usbd_msc_bot.h"
31 #include "usbd_msc_scsi.h"
33 #include "usbd_msc_data.h"
37 /** @addtogroup STM32_USB_DEVICE_LIBRARY
42 /** @defgroup MSC_SCSI
43 * @brief Mass storage SCSI layer module
47 /** @defgroup MSC_SCSI_Private_TypesDefinitions
55 /** @defgroup MSC_SCSI_Private_Defines
64 /** @defgroup MSC_SCSI_Private_Macros
72 /** @defgroup MSC_SCSI_Private_Variables
81 /** @defgroup MSC_SCSI_Private_FunctionPrototypes
84 static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
85 static int8_t SCSI_Inquiry(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
86 static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
87 static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
88 static int8_t SCSI_RequestSense (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
89 static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
90 static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
91 static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
92 static int8_t SCSI_Write10(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
93 static int8_t SCSI_Read10(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
94 static int8_t SCSI_Verify10(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
95 static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef
*pdev
,
99 static int8_t SCSI_ProcessRead (USBD_HandleTypeDef
*pdev
,
102 static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef
*pdev
,
109 /** @defgroup MSC_SCSI_Private_Functions
115 * @brief SCSI_ProcessCmd
116 * Process SCSI commands
117 * @param pdev: device instance
118 * @param lun: Logical unit number
119 * @param params: Command parameters
122 int8_t SCSI_ProcessCmd(USBD_HandleTypeDef
*pdev
,
129 case SCSI_TEST_UNIT_READY
:
130 return SCSI_TestUnitReady(pdev
, lun
, params
);
132 case SCSI_REQUEST_SENSE
:
133 return SCSI_RequestSense (pdev
, lun
, params
);
135 return SCSI_Inquiry(pdev
, lun
, params
);
137 case SCSI_START_STOP_UNIT
:
138 return SCSI_StartStopUnit(pdev
, lun
, params
);
140 case SCSI_ALLOW_MEDIUM_REMOVAL
:
141 return SCSI_StartStopUnit(pdev
, lun
, params
);
143 case SCSI_MODE_SENSE6
:
144 return SCSI_ModeSense6 (pdev
, lun
, params
);
146 case SCSI_MODE_SENSE10
:
147 return SCSI_ModeSense10 (pdev
, lun
, params
);
149 case SCSI_READ_FORMAT_CAPACITIES
:
150 return SCSI_ReadFormatCapacity(pdev
, lun
, params
);
152 case SCSI_READ_CAPACITY10
:
153 return SCSI_ReadCapacity10(pdev
, lun
, params
);
156 return SCSI_Read10(pdev
, lun
, params
);
159 return SCSI_Write10(pdev
, lun
, params
);
162 return SCSI_Verify10(pdev
, lun
, params
);
175 * @brief SCSI_TestUnitReady
176 * Process SCSI Test Unit Ready Command
177 * @param lun: Logical unit number
178 * @param params: Command parameters
181 static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
183 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
184 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
186 /* case 9 : Hi > D0 */
187 if (hmsc
->cbw
.dDataLength
!= 0)
196 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->IsReady(lun
) !=0 )
203 hmsc
->bot_state
= USBD_BOT_NO_DATA
;
206 hmsc
->bot_data_length
= 0;
211 * @brief SCSI_Inquiry
212 * Process Inquiry command
213 * @param lun: Logical unit number
214 * @param params: Command parameters
217 static int8_t SCSI_Inquiry(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
222 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
223 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
225 if (params
[1] & 0x01)/*Evpd is set*/
227 pPage
= (uint8_t *)MSC_Page00_Inquiry_Data
;
228 len
= LENGTH_INQUIRY_PAGE00
;
229 if (params
[4] <= len
)
233 memcpy(hmsc
->bot_data
, pPage
, len
);
237 len
= ((USBD_StorageTypeDef
*)pdev
->pUserData
)->Inquiry(lun
, hmsc
->bot_data
, params
[4]);
239 if (params
[4] <= len
)
244 hmsc
->bot_data_length
= len
;
250 * @brief SCSI_ReadCapacity10
251 * Process Read Capacity 10 command
252 * @param lun: Logical unit number
253 * @param params: Command parameters
256 static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
258 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
259 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
261 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->GetCapacity(lun
, &hmsc
->scsi_blk_nbr
, &hmsc
->scsi_blk_size
) != 0)
272 hmsc
->bot_data
[0] = (uint8_t)((hmsc
->scsi_blk_nbr
- 1) >> 24);
273 hmsc
->bot_data
[1] = (uint8_t)((hmsc
->scsi_blk_nbr
- 1) >> 16);
274 hmsc
->bot_data
[2] = (uint8_t)((hmsc
->scsi_blk_nbr
- 1) >> 8);
275 hmsc
->bot_data
[3] = (uint8_t)(hmsc
->scsi_blk_nbr
- 1);
277 hmsc
->bot_data
[4] = (uint8_t)(hmsc
->scsi_blk_size
>> 24);
278 hmsc
->bot_data
[5] = (uint8_t)(hmsc
->scsi_blk_size
>> 16);
279 hmsc
->bot_data
[6] = (uint8_t)(hmsc
->scsi_blk_size
>> 8);
280 hmsc
->bot_data
[7] = (uint8_t)(hmsc
->scsi_blk_size
);
282 hmsc
->bot_data_length
= 8;
287 * @brief SCSI_ReadFormatCapacity
288 * Process Read Format Capacity command
289 * @param lun: Logical unit number
290 * @param params: Command parameters
293 static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
295 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
296 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
302 for(i
=0 ; i
< 12 ; i
++)
304 hmsc
->bot_data
[i
] = 0;
307 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->GetCapacity(lun
, &blk_nbr
, &blk_size
) != 0)
309 // Capacity List Header
314 hmsc
->bot_data
[3] = 0x08; // Capacity List Length (8 bytes, 1 descriptor)
316 // Number of blocks. MAXIMUM
317 // 0x400000 is 2TB worth of 512 blocks.
318 hmsc
->bot_data
[4] = 0x00;
319 hmsc
->bot_data
[5] = 0x3F;
320 hmsc
->bot_data
[6] = 0xFF;
321 hmsc
->bot_data
[7] = 0xFF;
323 hmsc
->bot_data
[8] = 0x03; // Descriptor code - No media.
324 hmsc
->bot_data
[9] = 0x00;
325 hmsc
->bot_data
[10] = 0x02; // 0x200 512 bytes
326 hmsc
->bot_data
[11] = 0x00;
330 hmsc
->bot_data
[3] = 0x08;
331 hmsc
->bot_data
[4] = (uint8_t)((blk_nbr
- 1) >> 24);
332 hmsc
->bot_data
[5] = (uint8_t)((blk_nbr
- 1) >> 16);
333 hmsc
->bot_data
[6] = (uint8_t)((blk_nbr
- 1) >> 8);
334 hmsc
->bot_data
[7] = (uint8_t)(blk_nbr
- 1);
336 hmsc
->bot_data
[8] = 0x02; // Descriptor code - Formatted media
337 hmsc
->bot_data
[9] = (uint8_t)(blk_size
>> 16);
338 hmsc
->bot_data
[10] = (uint8_t)(blk_size
>> 8);
339 hmsc
->bot_data
[11] = (uint8_t)(blk_size
);
342 hmsc
->bot_data_length
= 12;
347 * @brief SCSI_ModeSense6
348 * Process Mode Sense6 command
349 * @param lun: Logical unit number
350 * @param params: Command parameters
353 static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
355 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
356 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
359 hmsc
->bot_data_length
= len
;
364 hmsc
->bot_data
[len
] = MSC_Mode_Sense6_data
[len
];
370 * @brief SCSI_ModeSense10
371 * Process Mode Sense10 command
372 * @param lun: Logical unit number
373 * @param params: Command parameters
376 static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
379 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
380 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
382 hmsc
->bot_data_length
= len
;
387 hmsc
->bot_data
[len
] = MSC_Mode_Sense10_data
[len
];
393 * @brief SCSI_RequestSense
394 * Process Request Sense command
395 * @param lun: Logical unit number
396 * @param params: Command parameters
400 static int8_t SCSI_RequestSense (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
403 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
404 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
406 for(i
=0 ; i
< REQUEST_SENSE_DATA_LEN
; i
++)
408 hmsc
->bot_data
[i
] = 0;
411 hmsc
->bot_data
[0] = 0x70;
412 hmsc
->bot_data
[7] = REQUEST_SENSE_DATA_LEN
- 6;
414 if((hmsc
->scsi_sense_head
!= hmsc
->scsi_sense_tail
)) {
416 hmsc
->bot_data
[2] = hmsc
->scsi_sense
[hmsc
->scsi_sense_head
].Skey
;
417 hmsc
->bot_data
[12] = hmsc
->scsi_sense
[hmsc
->scsi_sense_head
].w
.b
.ASCQ
;
418 hmsc
->bot_data
[13] = hmsc
->scsi_sense
[hmsc
->scsi_sense_head
].w
.b
.ASC
;
419 hmsc
->scsi_sense_head
++;
421 if (hmsc
->scsi_sense_head
== SENSE_LIST_DEEPTH
)
423 hmsc
->scsi_sense_head
= 0;
426 hmsc
->bot_data_length
= REQUEST_SENSE_DATA_LEN
;
428 if (params
[4] <= REQUEST_SENSE_DATA_LEN
)
430 hmsc
->bot_data_length
= params
[4];
436 * @brief SCSI_SenseCode
437 * Load the last error code in the error list
438 * @param lun: Logical unit number
439 * @param sKey: Sense Key
440 * @param ASC: Additional Sense Key
444 void SCSI_SenseCode(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t sKey
, uint8_t ASC
)
446 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
447 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
449 hmsc
->scsi_sense
[hmsc
->scsi_sense_tail
].Skey
= sKey
;
450 hmsc
->scsi_sense
[hmsc
->scsi_sense_tail
].w
.ASC
= ASC
<< 8;
451 hmsc
->scsi_sense_tail
++;
452 if (hmsc
->scsi_sense_tail
== SENSE_LIST_DEEPTH
)
454 hmsc
->scsi_sense_tail
= 0;
458 * @brief SCSI_StartStopUnit
459 * Process Start Stop Unit command
460 * @param lun: Logical unit number
461 * @param params: Command parameters
464 static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
466 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
467 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
469 hmsc
->bot_data_length
= 0;
475 * Process Read10 command
476 * @param lun: Logical unit number
477 * @param params: Command parameters
480 static int8_t SCSI_Read10(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
482 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
483 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
485 if(hmsc
->bot_state
== USBD_BOT_IDLE
) /* Idle */
488 /* case 10 : Ho <> Di */
490 if ((hmsc
->cbw
.bmFlags
& 0x80) != 0x80)
499 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->IsReady(lun
) !=0 )
508 hmsc
->scsi_blk_addr
= ((uint32_t)params
[2] << 24) | \
509 ((uint32_t)params
[3] << 16) | \
510 ((uint32_t)params
[4] << 8) | \
513 hmsc
->scsi_blk_len
= ((uint32_t)params
[7] << 8) | \
518 if( SCSI_CheckAddressRange(pdev
, lun
, hmsc
->scsi_blk_addr
, hmsc
->scsi_blk_len
) < 0)
520 return -1; /* error */
523 hmsc
->bot_state
= USBD_BOT_DATA_IN
;
525 /* cases 4,5 : Hi <> Dn */
526 if (hmsc
->cbw
.dDataLength
!= (hmsc
->scsi_blk_len
* hmsc
->scsi_blk_size
))
535 hmsc
->bot_data_length
= S2S_MSC_MEDIA_PACKET
;
537 return SCSI_ProcessRead(pdev
, lun
);
541 * @brief SCSI_Write10
542 * Process Write10 command
543 * @param lun: Logical unit number
544 * @param params: Command parameters
548 static int8_t SCSI_Write10 (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
550 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
551 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
554 if (hmsc
->bot_state
== USBD_BOT_IDLE
) /* Idle */
556 /* case 8 : Hi <> Do */
558 if ((hmsc
->cbw
.bmFlags
& 0x80) == 0x80)
567 /* Check whether Media is ready */
568 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->IsReady(lun
) !=0 )
577 /* Check If media is write-protected */
578 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->IsWriteProtected(lun
) !=0 )
588 hmsc
->scsi_blk_addr
= ((uint32_t)params
[2] << 24) | \
589 ((uint32_t)params
[3] << 16) | \
590 ((uint32_t)params
[4] << 8) | \
592 hmsc
->scsi_blk_len
= ((uint32_t)params
[7] << 8) | \
595 /* check if LBA address is in the right range */
596 if(SCSI_CheckAddressRange(pdev
,
599 hmsc
->scsi_blk_len
) < 0)
601 return -1; /* error */
604 len
= hmsc
->scsi_blk_len
* hmsc
->scsi_blk_size
;
606 /* cases 3,11,13 : Hn,Ho <> D0 */
607 if (hmsc
->cbw
.dDataLength
!= len
)
616 len
= MIN(len
, S2S_MSC_MEDIA_PACKET
);
618 /* Prepare EP to receive first data packet */
619 hmsc
->bot_state
= USBD_BOT_DATA_OUT
;
620 USBD_LL_PrepareReceive (pdev
,
625 else /* Write Process ongoing */
627 return SCSI_ProcessWrite(pdev
, lun
);
634 * @brief SCSI_Verify10
635 * Process Verify10 command
636 * @param lun: Logical unit number
637 * @param params: Command parameters
641 static int8_t SCSI_Verify10(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
643 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
644 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
646 if ((params
[1]& 0x02) == 0x02)
648 SCSI_SenseCode (pdev
,
651 INVALID_FIELED_IN_COMMAND
);
652 return -1; /* Error, Verify Mode Not supported*/
655 if(SCSI_CheckAddressRange(pdev
,
658 hmsc
->scsi_blk_len
) < 0)
660 return -1; /* error */
662 hmsc
->bot_data_length
= 0;
667 * @brief SCSI_CheckAddressRange
668 * Check address range
669 * @param lun: Logical unit number
670 * @param blk_offset: first block address
671 * @param blk_nbr: number of block to be processed
674 static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint32_t blk_offset
, uint16_t blk_nbr
)
676 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
677 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
679 // michael@codesrc.com: Re-check block limits in cause we have different values
680 // for different LUN's.
683 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->GetCapacity(lun
, &blkNbr
, &blkSize
) != 0)
691 // global variables. wooo
692 hmsc
->scsi_blk_size
= blkSize
;
693 hmsc
->scsi_blk_nbr
= blkNbr
;
695 if ((blk_offset
+ blk_nbr
) > blkNbr
)
700 ADDRESS_OUT_OF_RANGE
);
707 * @brief SCSI_ProcessRead
708 * Handle Read Process
709 * @param lun: Logical unit number
712 static int8_t SCSI_ProcessRead (USBD_HandleTypeDef
*pdev
, uint8_t lun
)
714 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
715 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
717 uint32_t len
= hmsc
->scsi_blk_len
* hmsc
->scsi_blk_size
;
719 len
= MIN(len
, S2S_MSC_MEDIA_PACKET
);
721 // TODO there is a dcache issue here.
722 // work out how, and when, to flush cashes between sdio dma and usb dma
723 memset (hmsc
->bot_data
, 0xAA, len
);
724 if( ((USBD_StorageTypeDef
*)pdev
->pUserData
)->Read(lun
,
727 len
/ hmsc
->scsi_blk_size
) < 0)
733 UNRECOVERED_READ_ERROR
);
738 USBD_LL_Transmit (pdev
,
743 hmsc
->scsi_blk_addr
+= (len
/ hmsc
->scsi_blk_size
);
744 hmsc
->scsi_blk_len
-= (len
/ hmsc
->scsi_blk_size
);
746 /* case 6 : Hi = Di */
747 hmsc
->csw
.dDataResidue
-= len
;
749 if (hmsc
->scsi_blk_len
== 0)
751 hmsc
->bot_state
= USBD_BOT_LAST_DATA_IN
;
757 * @brief SCSI_ProcessWrite
758 * Handle Write Process
759 * @param lun: Logical unit number
763 static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef
*pdev
, uint8_t lun
)
765 USBD_CompositeClassData
*classData
= (USBD_CompositeClassData
*) pdev
->pClassData
;
766 USBD_MSC_BOT_HandleTypeDef
*hmsc
= &(classData
->msc
);
768 uint32_t len
= hmsc
->scsi_blk_len
* hmsc
->scsi_blk_size
;
770 len
= MIN(len
, S2S_MSC_MEDIA_PACKET
);
772 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->Write(lun
,
775 len
/ hmsc
->scsi_blk_size
) < 0)
785 hmsc
->scsi_blk_addr
+= (len
/ hmsc
->scsi_blk_size
);
786 hmsc
->scsi_blk_len
-= (len
/ hmsc
->scsi_blk_size
);
788 /* case 12 : Ho = Do */
789 hmsc
->csw
.dDataResidue
-= len
;
791 if (hmsc
->scsi_blk_len
== 0)
793 MSC_BOT_SendCSW (pdev
, USBD_CSW_CMD_PASSED
);
797 len
= MIN((hmsc
->scsi_blk_len
* hmsc
->scsi_blk_size
), S2S_MSC_MEDIA_PACKET
);
798 /* Prepare EP to Receive next packet */
799 USBD_LL_PrepareReceive (pdev
, MSC_EPOUT_ADDR
, hmsc
->bot_data
, len
);
818 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/