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 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
12 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
13 * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
14 * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
15 * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
16 * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
18 * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
19 ******************************************************************************
22 /* Includes ------------------------------------------------------------------*/
23 #include "usbd_msc_bot.h"
24 #include "usbd_msc_scsi.h"
25 #include "usbd_msc_mem.h"
26 #include "usbd_msc_data.h"
30 /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
35 /** @defgroup MSC_SCSI
36 * @brief Mass storage SCSI layer module
40 /** @defgroup MSC_SCSI_Private_TypesDefinitions
48 /** @defgroup MSC_SCSI_Private_Defines
57 /** @defgroup MSC_SCSI_Private_Macros
65 /** @defgroup MSC_SCSI_Private_Variables
69 SCSI_Sense_TypeDef SCSI_Sense [SENSE_LIST_DEEPTH];
70 uint8_t SCSI_Sense_Head;
71 uint8_t SCSI_Sense_Tail;
73 uint32_t SCSI_blk_size;
74 uint32_t SCSI_blk_nbr;
76 uint32_t SCSI_blk_addr;
77 uint32_t SCSI_blk_len;
79 USB_OTG_CORE_HANDLE *cdev;
85 /** @defgroup MSC_SCSI_Private_FunctionPrototypes
88 static int8_t SCSI_TestUnitReady(uint8_t lun, uint8_t *params);
89 static int8_t SCSI_Inquiry(uint8_t lun, uint8_t *params);
90 static int8_t SCSI_ReadFormatCapacity(uint8_t lun, uint8_t *params);
91 static int8_t SCSI_ReadCapacity10(uint8_t lun, uint8_t *params);
92 static int8_t SCSI_RequestSense (uint8_t lun, uint8_t *params);
93 static int8_t SCSI_StartStopUnit(uint8_t lun, uint8_t *params);
94 static int8_t SCSI_ModeSense6 (uint8_t lun, uint8_t *params);
95 static int8_t SCSI_ModeSense10 (uint8_t lun, uint8_t *params);
96 static int8_t SCSI_Write10(uint8_t lun , uint8_t *params);
97 static int8_t SCSI_Read10(uint8_t lun , uint8_t *params);
98 static int8_t SCSI_Verify10(uint8_t lun, uint8_t *params);
99 static int8_t SCSI_CheckAddressRange (uint8_t lun ,
100 uint32_t blk_offset ,
102 static int8_t SCSI_ProcessRead (uint8_t lun);
104 static int8_t SCSI_ProcessWrite (uint8_t lun);
110 /** @defgroup MSC_SCSI_Private_Functions
116 * @brief SCSI_ProcessCmd
117 * Process SCSI commands
118 * @param pdev: device instance
119 * @param lun: Logical unit number
120 * @param params: Command parameters
123 int8_t SCSI_ProcessCmd(USB_OTG_CORE_HANDLE *pdev,
131 case SCSI_TEST_UNIT_READY:
132 return SCSI_TestUnitReady(lun, params);
134 case SCSI_REQUEST_SENSE:
135 return SCSI_RequestSense (lun, params);
137 return SCSI_Inquiry(lun, params);
139 case SCSI_START_STOP_UNIT:
140 return SCSI_StartStopUnit(lun, params);
142 case SCSI_ALLOW_MEDIUM_REMOVAL:
143 return SCSI_StartStopUnit(lun, params);
145 case SCSI_MODE_SENSE6:
146 return SCSI_ModeSense6 (lun, params);
148 case SCSI_MODE_SENSE10:
149 return SCSI_ModeSense10 (lun, params);
151 case SCSI_READ_FORMAT_CAPACITIES:
152 return SCSI_ReadFormatCapacity(lun, params);
154 case SCSI_READ_CAPACITY10:
155 return SCSI_ReadCapacity10(lun, params);
158 return SCSI_Read10(lun, params);
161 return SCSI_Write10(lun, params);
164 return SCSI_Verify10(lun, params);
176 * @brief SCSI_TestUnitReady
177 * Process SCSI Test Unit Ready Command
178 * @param lun: Logical unit number
179 * @param params: Command parameters
182 static int8_t SCSI_TestUnitReady(uint8_t lun, uint8_t *params)
185 /* case 9 : Hi > D0 */
186 if (MSC_BOT_cbw.dDataLength != 0)
188 SCSI_SenseCode(MSC_BOT_cbw.bLUN,
194 if(USBD_STORAGE_fops->IsReady(lun) !=0 )
206 * @brief SCSI_Inquiry
207 * Process Inquiry command
208 * @param lun: Logical unit number
209 * @param params: Command parameters
212 static int8_t SCSI_Inquiry(uint8_t lun, uint8_t *params)
217 if (params[1] & 0x01)/*Evpd is set*/
219 pPage = (uint8_t *)MSC_Page00_Inquiry_Data;
220 len = LENGTH_INQUIRY_PAGE00;
225 pPage = (uint8_t *)&USBD_STORAGE_fops->pInquiry[lun * USBD_STD_INQUIRY_LENGTH];
228 if (params[4] <= len)
233 MSC_BOT_DataLen = len;
238 MSC_BOT_Data[len] = pPage[len];
244 * @brief SCSI_ReadCapacity10
245 * Process Read Capacity 10 command
246 * @param lun: Logical unit number
247 * @param params: Command parameters
250 static int8_t SCSI_ReadCapacity10(uint8_t lun, uint8_t *params)
253 if(USBD_STORAGE_fops->GetCapacity(lun, &SCSI_blk_nbr, &SCSI_blk_size) != 0)
263 MSC_BOT_Data[0] = (uint8_t)(SCSI_blk_nbr - 1 >> 24);
264 MSC_BOT_Data[1] = (uint8_t)(SCSI_blk_nbr - 1 >> 16);
265 MSC_BOT_Data[2] = (uint8_t)(SCSI_blk_nbr - 1 >> 8);
266 MSC_BOT_Data[3] = (uint8_t)(SCSI_blk_nbr - 1);
268 MSC_BOT_Data[4] = (uint8_t)(SCSI_blk_size >> 24);
269 MSC_BOT_Data[5] = (uint8_t)(SCSI_blk_size >> 16);
270 MSC_BOT_Data[6] = (uint8_t)(SCSI_blk_size >> 8);
271 MSC_BOT_Data[7] = (uint8_t)(SCSI_blk_size);
278 * @brief SCSI_ReadFormatCapacity
279 * Process Read Format Capacity command
280 * @param lun: Logical unit number
281 * @param params: Command parameters
284 static int8_t SCSI_ReadFormatCapacity(uint8_t lun, uint8_t *params)
291 for(i=0 ; i < 12 ; i++)
296 if(USBD_STORAGE_fops->GetCapacity(lun, &blk_nbr, &blk_size) != 0)
305 MSC_BOT_Data[3] = 0x08;
306 MSC_BOT_Data[4] = (uint8_t)(blk_nbr - 1 >> 24);
307 MSC_BOT_Data[5] = (uint8_t)(blk_nbr - 1 >> 16);
308 MSC_BOT_Data[6] = (uint8_t)(blk_nbr - 1 >> 8);
309 MSC_BOT_Data[7] = (uint8_t)(blk_nbr - 1);
311 MSC_BOT_Data[8] = 0x02;
312 MSC_BOT_Data[9] = (uint8_t)(blk_size >> 16);
313 MSC_BOT_Data[10] = (uint8_t)(blk_size >> 8);
314 MSC_BOT_Data[11] = (uint8_t)(blk_size);
316 MSC_BOT_DataLen = 12;
321 * @brief SCSI_ModeSense6
322 * Process Mode Sense6 command
323 * @param lun: Logical unit number
324 * @param params: Command parameters
327 static int8_t SCSI_ModeSense6 (uint8_t lun, uint8_t *params)
331 MSC_BOT_DataLen = len;
336 MSC_BOT_Data[len] = MSC_Mode_Sense6_data[len];
342 * @brief SCSI_ModeSense10
343 * Process Mode Sense10 command
344 * @param lun: Logical unit number
345 * @param params: Command parameters
348 static int8_t SCSI_ModeSense10 (uint8_t lun, uint8_t *params)
352 MSC_BOT_DataLen = len;
357 MSC_BOT_Data[len] = MSC_Mode_Sense10_data[len];
363 * @brief SCSI_RequestSense
364 * Process Request Sense command
365 * @param lun: Logical unit number
366 * @param params: Command parameters
370 static int8_t SCSI_RequestSense (uint8_t lun, uint8_t *params)
374 for(i=0 ; i < REQUEST_SENSE_DATA_LEN ; i++)
379 MSC_BOT_Data[0] = 0x70;
380 MSC_BOT_Data[7] = REQUEST_SENSE_DATA_LEN - 6;
382 if((SCSI_Sense_Head != SCSI_Sense_Tail)) {
384 MSC_BOT_Data[2] = SCSI_Sense[SCSI_Sense_Head].Skey;
385 MSC_BOT_Data[12] = SCSI_Sense[SCSI_Sense_Head].w.b.ASCQ;
386 MSC_BOT_Data[13] = SCSI_Sense[SCSI_Sense_Head].w.b.ASC;
389 if (SCSI_Sense_Head == SENSE_LIST_DEEPTH)
394 MSC_BOT_DataLen = REQUEST_SENSE_DATA_LEN;
396 if (params[4] <= REQUEST_SENSE_DATA_LEN)
398 MSC_BOT_DataLen = params[4];
404 * @brief SCSI_SenseCode
405 * Load the last error code in the error list
406 * @param lun: Logical unit number
407 * @param sKey: Sense Key
408 * @param ASC: Additional Sense Key
412 void SCSI_SenseCode(uint8_t lun, uint8_t sKey, uint8_t ASC)
414 SCSI_Sense[SCSI_Sense_Tail].Skey = sKey;
415 SCSI_Sense[SCSI_Sense_Tail].w.ASC = ASC << 8;
417 if (SCSI_Sense_Tail == SENSE_LIST_DEEPTH)
423 * @brief SCSI_StartStopUnit
424 * Process Start Stop Unit command
425 * @param lun: Logical unit number
426 * @param params: Command parameters
429 static int8_t SCSI_StartStopUnit(uint8_t lun, uint8_t *params)
437 * Process Read10 command
438 * @param lun: Logical unit number
439 * @param params: Command parameters
442 static int8_t SCSI_Read10(uint8_t lun , uint8_t *params)
444 if(MSC_BOT_State == BOT_IDLE) /* Idle */
447 /* case 10 : Ho <> Di */
449 if ((MSC_BOT_cbw.bmFlags & 0x80) != 0x80)
451 SCSI_SenseCode(MSC_BOT_cbw.bLUN,
457 if(USBD_STORAGE_fops->IsReady(lun) !=0 )
465 SCSI_blk_addr = (params[2] << 24) | \
466 (params[3] << 16) | \
470 SCSI_blk_len = (params[7] << 8) | \
475 if( SCSI_CheckAddressRange(lun, SCSI_blk_addr, SCSI_blk_len) < 0)
477 return -1; /* error */
480 MSC_BOT_State = BOT_DATA_IN;
481 SCSI_blk_addr *= SCSI_blk_size;
482 SCSI_blk_len *= SCSI_blk_size;
484 /* cases 4,5 : Hi <> Dn */
485 if (MSC_BOT_cbw.dDataLength != SCSI_blk_len)
487 SCSI_SenseCode(MSC_BOT_cbw.bLUN,
493 MSC_BOT_DataLen = MSC_MEDIA_PACKET;
495 return SCSI_ProcessRead(lun);
499 * @brief SCSI_Write10
500 * Process Write10 command
501 * @param lun: Logical unit number
502 * @param params: Command parameters
506 static int8_t SCSI_Write10 (uint8_t lun , uint8_t *params)
508 if (MSC_BOT_State == BOT_IDLE) /* Idle */
511 /* case 8 : Hi <> Do */
513 if ((MSC_BOT_cbw.bmFlags & 0x80) == 0x80)
515 SCSI_SenseCode(MSC_BOT_cbw.bLUN,
521 /* Check whether Media is ready */
522 if(USBD_STORAGE_fops->IsReady(lun) !=0 )
530 /* Check If media is write-protected */
531 if(USBD_STORAGE_fops->IsWriteProtected(lun) !=0 )
540 SCSI_blk_addr = (params[2] << 24) | \
541 (params[3] << 16) | \
544 SCSI_blk_len = (params[7] << 8) | \
547 /* check if LBA address is in the right range */
548 if(SCSI_CheckAddressRange(lun, SCSI_blk_addr, SCSI_blk_len) < 0)
550 return -1; /* error */
553 SCSI_blk_addr *= SCSI_blk_size;
554 SCSI_blk_len *= SCSI_blk_size;
556 /* cases 3,11,13 : Hn,Ho <> D0 */
557 if (MSC_BOT_cbw.dDataLength != SCSI_blk_len)
559 SCSI_SenseCode(MSC_BOT_cbw.bLUN,
565 /* Prepare EP to receive first data packet */
566 MSC_BOT_State = BOT_DATA_OUT;
567 DCD_EP_PrepareRx (cdev,
570 MIN (SCSI_blk_len, MSC_MEDIA_PACKET));
572 else /* Write Process ongoing */
574 return SCSI_ProcessWrite(lun);
581 * @brief SCSI_Verify10
582 * Process Verify10 command
583 * @param lun: Logical unit number
584 * @param params: Command parameters
588 static int8_t SCSI_Verify10(uint8_t lun , uint8_t *params){
589 if ((params[1]& 0x02) == 0x02)
591 SCSI_SenseCode (lun, ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);
592 return -1; /* Error, Verify Mode Not supported*/
595 if(SCSI_CheckAddressRange(lun, SCSI_blk_addr, SCSI_blk_len) < 0)
597 return -1; /* error */
604 * @brief SCSI_CheckAddressRange
605 * Check address range
606 * @param lun: Logical unit number
607 * @param blk_offset: first block address
608 * @param blk_nbr: number of block to be processed
611 static int8_t SCSI_CheckAddressRange (uint8_t lun , uint32_t blk_offset , uint16_t blk_nbr)
614 if ((blk_offset + blk_nbr) > SCSI_blk_nbr )
616 SCSI_SenseCode(lun, ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
623 * @brief SCSI_ProcessRead
624 * Handle Read Process
625 * @param lun: Logical unit number
628 static int8_t SCSI_ProcessRead (uint8_t lun)
632 len = MIN(SCSI_blk_len , MSC_MEDIA_PACKET);
634 if( USBD_STORAGE_fops->Read(lun ,
636 SCSI_blk_addr / SCSI_blk_size,
637 len / SCSI_blk_size) < 0)
640 SCSI_SenseCode(lun, HARDWARE_ERROR, UNRECOVERED_READ_ERROR);
651 SCSI_blk_addr += len;
654 /* case 6 : Hi = Di */
655 MSC_BOT_csw.dDataResidue -= len;
657 if (SCSI_blk_len == 0)
659 MSC_BOT_State = BOT_LAST_DATA_IN;
665 * @brief SCSI_ProcessWrite
666 * Handle Write Process
667 * @param lun: Logical unit number
671 static int8_t SCSI_ProcessWrite (uint8_t lun)
675 len = MIN(SCSI_blk_len , MSC_MEDIA_PACKET);
677 if(USBD_STORAGE_fops->Write(lun ,
679 SCSI_blk_addr / SCSI_blk_size,
680 len / SCSI_blk_size) < 0)
682 SCSI_SenseCode(lun, HARDWARE_ERROR, WRITE_FAULT);
687 SCSI_blk_addr += len;
690 /* case 12 : Ho = Do */
691 MSC_BOT_csw.dDataResidue -= len;
693 if (SCSI_blk_len == 0)
695 MSC_BOT_SendCSW (cdev, CSW_CMD_PASSED);
699 /* Prapare EP to Receive next packet */
700 DCD_EP_PrepareRx (cdev,
703 MIN (SCSI_blk_len, MSC_MEDIA_PACKET));
722 /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/