2 ******************************************************************************
3 * @file usbd_msc_scsi.c
4 * @author MCD Application Team
6 * @date 11-December-2015
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_msc_bot.h"
30 #include "usbd_msc_scsi.h"
32 #include "usbd_msc_data.h"
36 /** @addtogroup STM32_USB_DEVICE_LIBRARY
41 /** @defgroup MSC_SCSI
42 * @brief Mass storage SCSI layer module
46 /** @defgroup MSC_SCSI_Private_TypesDefinitions
54 /** @defgroup MSC_SCSI_Private_Defines
63 /** @defgroup MSC_SCSI_Private_Macros
71 /** @defgroup MSC_SCSI_Private_Variables
80 /** @defgroup MSC_SCSI_Private_FunctionPrototypes
83 static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
84 static int8_t SCSI_Inquiry(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
85 static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
86 static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
87 static int8_t SCSI_RequestSense (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
88 static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
89 static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
90 static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
91 static int8_t SCSI_Write10(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
92 static int8_t SCSI_Read10(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
93 static int8_t SCSI_Verify10(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
);
94 static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef
*pdev
,
98 static int8_t SCSI_ProcessRead (USBD_HandleTypeDef
*pdev
,
101 static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef
*pdev
,
108 /** @defgroup MSC_SCSI_Private_Functions
114 * @brief SCSI_ProcessCmd
115 * Process SCSI commands
116 * @param pdev: device instance
117 * @param lun: Logical unit number
118 * @param params: Command parameters
121 int8_t SCSI_ProcessCmd(USBD_HandleTypeDef
*pdev
,
128 case SCSI_TEST_UNIT_READY
:
129 return SCSI_TestUnitReady(pdev
, lun
, params
);
131 case SCSI_REQUEST_SENSE
:
132 return SCSI_RequestSense (pdev
, lun
, params
);
134 return SCSI_Inquiry(pdev
, lun
, params
);
136 case SCSI_START_STOP_UNIT
:
137 return SCSI_StartStopUnit(pdev
, lun
, params
);
139 case SCSI_ALLOW_MEDIUM_REMOVAL
:
140 return SCSI_StartStopUnit(pdev
, lun
, params
);
142 case SCSI_MODE_SENSE6
:
143 return SCSI_ModeSense6 (pdev
, lun
, params
);
145 case SCSI_MODE_SENSE10
:
146 return SCSI_ModeSense10 (pdev
, lun
, params
);
148 case SCSI_READ_FORMAT_CAPACITIES
:
149 return SCSI_ReadFormatCapacity(pdev
, lun
, params
);
151 case SCSI_READ_CAPACITY10
:
152 return SCSI_ReadCapacity10(pdev
, lun
, params
);
155 return SCSI_Read10(pdev
, lun
, params
);
158 return SCSI_Write10(pdev
, lun
, params
);
161 return SCSI_Verify10(pdev
, lun
, params
);
174 * @brief SCSI_TestUnitReady
175 * Process SCSI Test Unit Ready Command
176 * @param lun: Logical unit number
177 * @param params: Command parameters
180 static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
182 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*)pdev
->pClassData
;
184 /* case 9 : Hi > D0 */
185 if (hmsc
->cbw
.dDataLength
!= 0)
194 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->IsReady(lun
) !=0 )
201 hmsc
->bot_state
= USBD_BOT_NO_DATA
;
204 hmsc
->bot_data_length
= 0;
209 * @brief SCSI_Inquiry
210 * Process Inquiry command
211 * @param lun: Logical unit number
212 * @param params: Command parameters
215 static int8_t SCSI_Inquiry(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
219 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*)pdev
->pClassData
;
221 if (params
[1] & 0x01)/*Evpd is set*/
223 pPage
= (uint8_t *)MSC_Page00_Inquiry_Data
;
224 len
= LENGTH_INQUIRY_PAGE00
;
229 pPage
= (uint8_t *)&((USBD_StorageTypeDef
*)pdev
->pUserData
)->pInquiry
[lun
* STANDARD_INQUIRY_DATA_LEN
];
232 if (params
[4] <= len
)
237 hmsc
->bot_data_length
= len
;
242 hmsc
->bot_data
[len
] = pPage
[len
];
248 * @brief SCSI_ReadCapacity10
249 * Process Read Capacity 10 command
250 * @param lun: Logical unit number
251 * @param params: Command parameters
254 static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
256 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*)pdev
->pClassData
;
258 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->GetCapacity(lun
, &hmsc
->scsi_blk_nbr
, &hmsc
->scsi_blk_size
) != 0)
269 hmsc
->bot_data
[0] = (uint8_t)((hmsc
->scsi_blk_nbr
- 1) >> 24);
270 hmsc
->bot_data
[1] = (uint8_t)((hmsc
->scsi_blk_nbr
- 1) >> 16);
271 hmsc
->bot_data
[2] = (uint8_t)((hmsc
->scsi_blk_nbr
- 1) >> 8);
272 hmsc
->bot_data
[3] = (uint8_t)(hmsc
->scsi_blk_nbr
- 1);
274 hmsc
->bot_data
[4] = (uint8_t)(hmsc
->scsi_blk_size
>> 24);
275 hmsc
->bot_data
[5] = (uint8_t)(hmsc
->scsi_blk_size
>> 16);
276 hmsc
->bot_data
[6] = (uint8_t)(hmsc
->scsi_blk_size
>> 8);
277 hmsc
->bot_data
[7] = (uint8_t)(hmsc
->scsi_blk_size
);
279 hmsc
->bot_data_length
= 8;
284 * @brief SCSI_ReadFormatCapacity
285 * Process Read Format Capacity command
286 * @param lun: Logical unit number
287 * @param params: Command parameters
290 static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
292 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*)pdev
->pClassData
;
298 for(i
=0 ; i
< 12 ; i
++)
300 hmsc
->bot_data
[i
] = 0;
303 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->GetCapacity(lun
, &blk_nbr
, &blk_size
) != 0)
313 hmsc
->bot_data
[3] = 0x08;
314 hmsc
->bot_data
[4] = (uint8_t)((blk_nbr
- 1) >> 24);
315 hmsc
->bot_data
[5] = (uint8_t)((blk_nbr
- 1) >> 16);
316 hmsc
->bot_data
[6] = (uint8_t)((blk_nbr
- 1) >> 8);
317 hmsc
->bot_data
[7] = (uint8_t)(blk_nbr
- 1);
319 hmsc
->bot_data
[8] = 0x02;
320 hmsc
->bot_data
[9] = (uint8_t)(blk_size
>> 16);
321 hmsc
->bot_data
[10] = (uint8_t)(blk_size
>> 8);
322 hmsc
->bot_data
[11] = (uint8_t)(blk_size
);
324 hmsc
->bot_data_length
= 12;
329 * @brief SCSI_ModeSense6
330 * Process Mode Sense6 command
331 * @param lun: Logical unit number
332 * @param params: Command parameters
335 static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
337 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*)pdev
->pClassData
;
339 hmsc
->bot_data_length
= len
;
344 hmsc
->bot_data
[len
] = MSC_Mode_Sense6_data
[len
];
350 * @brief SCSI_ModeSense10
351 * Process Mode Sense10 command
352 * @param lun: Logical unit number
353 * @param params: Command parameters
356 static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
359 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*)pdev
->pClassData
;
361 hmsc
->bot_data_length
= len
;
366 hmsc
->bot_data
[len
] = MSC_Mode_Sense10_data
[len
];
372 * @brief SCSI_RequestSense
373 * Process Request Sense command
374 * @param lun: Logical unit number
375 * @param params: Command parameters
379 static int8_t SCSI_RequestSense (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
382 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*)pdev
->pClassData
;
384 for(i
=0 ; i
< REQUEST_SENSE_DATA_LEN
; i
++)
386 hmsc
->bot_data
[i
] = 0;
389 hmsc
->bot_data
[0] = 0x70;
390 hmsc
->bot_data
[7] = REQUEST_SENSE_DATA_LEN
- 6;
392 if((hmsc
->scsi_sense_head
!= hmsc
->scsi_sense_tail
)) {
394 hmsc
->bot_data
[2] = hmsc
->scsi_sense
[hmsc
->scsi_sense_head
].Skey
;
395 hmsc
->bot_data
[12] = hmsc
->scsi_sense
[hmsc
->scsi_sense_head
].w
.b
.ASCQ
;
396 hmsc
->bot_data
[13] = hmsc
->scsi_sense
[hmsc
->scsi_sense_head
].w
.b
.ASC
;
397 hmsc
->scsi_sense_head
++;
399 if (hmsc
->scsi_sense_head
== SENSE_LIST_DEEPTH
)
401 hmsc
->scsi_sense_head
= 0;
404 hmsc
->bot_data_length
= REQUEST_SENSE_DATA_LEN
;
406 if (params
[4] <= REQUEST_SENSE_DATA_LEN
)
408 hmsc
->bot_data_length
= params
[4];
414 * @brief SCSI_SenseCode
415 * Load the last error code in the error list
416 * @param lun: Logical unit number
417 * @param sKey: Sense Key
418 * @param ASC: Additional Sense Key
422 void SCSI_SenseCode(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t sKey
, uint8_t ASC
)
424 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*)pdev
->pClassData
;
426 hmsc
->scsi_sense
[hmsc
->scsi_sense_tail
].Skey
= sKey
;
427 hmsc
->scsi_sense
[hmsc
->scsi_sense_tail
].w
.ASC
= ASC
<< 8;
428 hmsc
->scsi_sense_tail
++;
429 if (hmsc
->scsi_sense_tail
== SENSE_LIST_DEEPTH
)
431 hmsc
->scsi_sense_tail
= 0;
435 * @brief SCSI_StartStopUnit
436 * Process Start Stop Unit command
437 * @param lun: Logical unit number
438 * @param params: Command parameters
441 static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
443 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*) pdev
->pClassData
;
444 hmsc
->bot_data_length
= 0;
450 * Process Read10 command
451 * @param lun: Logical unit number
452 * @param params: Command parameters
455 static int8_t SCSI_Read10(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
457 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*) pdev
->pClassData
;
459 if(hmsc
->bot_state
== USBD_BOT_IDLE
) /* Idle */
462 /* case 10 : Ho <> Di */
464 if ((hmsc
->cbw
.bmFlags
& 0x80) != 0x80)
473 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->IsReady(lun
) !=0 )
482 hmsc
->scsi_blk_addr
= (params
[2] << 24) | \
483 (params
[3] << 16) | \
487 hmsc
->scsi_blk_len
= (params
[7] << 8) | \
492 if( SCSI_CheckAddressRange(pdev
, lun
, hmsc
->scsi_blk_addr
, hmsc
->scsi_blk_len
) < 0)
494 return -1; /* error */
497 hmsc
->bot_state
= USBD_BOT_DATA_IN
;
498 hmsc
->scsi_blk_addr
*= hmsc
->scsi_blk_size
;
499 hmsc
->scsi_blk_len
*= hmsc
->scsi_blk_size
;
501 /* cases 4,5 : Hi <> Dn */
502 if (hmsc
->cbw
.dDataLength
!= hmsc
->scsi_blk_len
)
511 hmsc
->bot_data_length
= MSC_MEDIA_PACKET
;
513 return SCSI_ProcessRead(pdev
, lun
);
517 * @brief SCSI_Write10
518 * Process Write10 command
519 * @param lun: Logical unit number
520 * @param params: Command parameters
524 static int8_t SCSI_Write10 (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
526 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*) pdev
->pClassData
;
528 if (hmsc
->bot_state
== USBD_BOT_IDLE
) /* Idle */
531 /* case 8 : Hi <> Do */
533 if ((hmsc
->cbw
.bmFlags
& 0x80) == 0x80)
542 /* Check whether Media is ready */
543 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->IsReady(lun
) !=0 )
552 /* Check If media is write-protected */
553 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->IsWriteProtected(lun
) !=0 )
563 hmsc
->scsi_blk_addr
= (params
[2] << 24) | \
564 (params
[3] << 16) | \
567 hmsc
->scsi_blk_len
= (params
[7] << 8) | \
570 /* check if LBA address is in the right range */
571 if(SCSI_CheckAddressRange(pdev
,
574 hmsc
->scsi_blk_len
) < 0)
576 return -1; /* error */
579 hmsc
->scsi_blk_addr
*= hmsc
->scsi_blk_size
;
580 hmsc
->scsi_blk_len
*= hmsc
->scsi_blk_size
;
582 /* cases 3,11,13 : Hn,Ho <> D0 */
583 if (hmsc
->cbw
.dDataLength
!= hmsc
->scsi_blk_len
)
592 /* Prepare EP to receive first data packet */
593 hmsc
->bot_state
= USBD_BOT_DATA_OUT
;
594 USBD_LL_PrepareReceive (pdev
,
597 MIN (hmsc
->scsi_blk_len
, MSC_MEDIA_PACKET
));
599 else /* Write Process ongoing */
601 return SCSI_ProcessWrite(pdev
, lun
);
608 * @brief SCSI_Verify10
609 * Process Verify10 command
610 * @param lun: Logical unit number
611 * @param params: Command parameters
615 static int8_t SCSI_Verify10(USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint8_t *params
)
617 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*) pdev
->pClassData
;
619 if ((params
[1]& 0x02) == 0x02)
621 SCSI_SenseCode (pdev
,
624 INVALID_FIELED_IN_COMMAND
);
625 return -1; /* Error, Verify Mode Not supported*/
628 if(SCSI_CheckAddressRange(pdev
,
631 hmsc
->scsi_blk_len
) < 0)
633 return -1; /* error */
635 hmsc
->bot_data_length
= 0;
640 * @brief SCSI_CheckAddressRange
641 * Check address range
642 * @param lun: Logical unit number
643 * @param blk_offset: first block address
644 * @param blk_nbr: number of block to be processed
647 static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef
*pdev
, uint8_t lun
, uint32_t blk_offset
, uint16_t blk_nbr
)
649 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*) pdev
->pClassData
;
651 if ((blk_offset
+ blk_nbr
) > hmsc
->scsi_blk_nbr
)
656 ADDRESS_OUT_OF_RANGE
);
663 * @brief SCSI_ProcessRead
664 * Handle Read Process
665 * @param lun: Logical unit number
668 static int8_t SCSI_ProcessRead (USBD_HandleTypeDef
*pdev
, uint8_t lun
)
670 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*)pdev
->pClassData
;
673 len
= MIN(hmsc
->scsi_blk_len
, MSC_MEDIA_PACKET
);
675 if( ((USBD_StorageTypeDef
*)pdev
->pUserData
)->Read(lun
,
677 hmsc
->scsi_blk_addr
/ hmsc
->scsi_blk_size
,
678 len
/ hmsc
->scsi_blk_size
) < 0)
684 UNRECOVERED_READ_ERROR
);
689 USBD_LL_Transmit (pdev
,
695 hmsc
->scsi_blk_addr
+= len
;
696 hmsc
->scsi_blk_len
-= len
;
698 /* case 6 : Hi = Di */
699 hmsc
->csw
.dDataResidue
-= len
;
701 if (hmsc
->scsi_blk_len
== 0)
703 hmsc
->bot_state
= USBD_BOT_LAST_DATA_IN
;
709 * @brief SCSI_ProcessWrite
710 * Handle Write Process
711 * @param lun: Logical unit number
715 static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef
*pdev
, uint8_t lun
)
718 USBD_MSC_BOT_HandleTypeDef
*hmsc
= (USBD_MSC_BOT_HandleTypeDef
*) pdev
->pClassData
;
720 len
= MIN(hmsc
->scsi_blk_len
, MSC_MEDIA_PACKET
);
722 if(((USBD_StorageTypeDef
*)pdev
->pUserData
)->Write(lun
,
724 hmsc
->scsi_blk_addr
/ hmsc
->scsi_blk_size
,
725 len
/ hmsc
->scsi_blk_size
) < 0)
735 hmsc
->scsi_blk_addr
+= len
;
736 hmsc
->scsi_blk_len
-= len
;
738 /* case 12 : Ho = Do */
739 hmsc
->csw
.dDataResidue
-= len
;
741 if (hmsc
->scsi_blk_len
== 0)
743 MSC_BOT_SendCSW (pdev
, USBD_CSW_CMD_PASSED
);
747 /* Prepare EP to Receive next packet */
748 USBD_LL_PrepareReceive (pdev
,
751 MIN (hmsc
->scsi_blk_len
, MSC_MEDIA_PACKET
));
770 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/