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);
171 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
172 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
173 hmsc->bot_state = USBD_BOT_NO_DATA;
182 * @brief SCSI_TestUnitReady
183 * Process SCSI Test Unit Ready Command
184 * @param lun: Logical unit number
185 * @param params: Command parameters
188 static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
190 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
191 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
193 /* case 9 : Hi > D0 */
194 if (hmsc->cbw.dDataLength != 0)
203 if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
210 hmsc->bot_state = USBD_BOT_NO_DATA;
213 hmsc->bot_data_length = 0;
218 * @brief SCSI_Inquiry
219 * Process Inquiry command
220 * @param lun: Logical unit number
221 * @param params: Command parameters
224 static int8_t SCSI_Inquiry(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
229 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
230 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
232 if (params[1] & 0x01)/*Evpd is set*/
234 pPage = (uint8_t *)MSC_Page00_Inquiry_Data;
235 len = LENGTH_INQUIRY_PAGE00;
236 if (params[4] <= len)
240 memcpy(hmsc->bot_data, pPage, len);
244 len = ((USBD_StorageTypeDef *)pdev->pUserData)->Inquiry(lun, hmsc->bot_data, params[4]);
246 if (params[4] <= len)
251 hmsc->bot_data_length = len;
257 * @brief SCSI_ReadCapacity10
258 * Process Read Capacity 10 command
259 * @param lun: Logical unit number
260 * @param params: Command parameters
263 static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
265 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
266 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
268 if(((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size) != 0)
274 hmsc->bot_state = USBD_BOT_NO_DATA;
280 hmsc->bot_data[0] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 24);
281 hmsc->bot_data[1] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 16);
282 hmsc->bot_data[2] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 8);
283 hmsc->bot_data[3] = (uint8_t)(hmsc->scsi_blk_nbr - 1);
285 hmsc->bot_data[4] = (uint8_t)(hmsc->scsi_blk_size >> 24);
286 hmsc->bot_data[5] = (uint8_t)(hmsc->scsi_blk_size >> 16);
287 hmsc->bot_data[6] = (uint8_t)(hmsc->scsi_blk_size >> 8);
288 hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_size);
290 hmsc->bot_data_length = 8;
295 * @brief SCSI_ReadFormatCapacity
296 * Process Read Format Capacity command
297 * @param lun: Logical unit number
298 * @param params: Command parameters
301 static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
303 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
304 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
310 for(i=0 ; i < 12 ; i++)
312 hmsc->bot_data[i] = 0;
315 if(((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &blk_nbr, &blk_size) != 0)
317 // Capacity List Header
322 hmsc->bot_data[3] = 0x08; // Capacity List Length (8 bytes, 1 descriptor)
324 // Number of blocks. MAXIMUM
325 // 0x400000 is 2TB worth of 512 blocks.
326 hmsc->bot_data[4] = 0x00;
327 hmsc->bot_data[5] = 0x3F;
328 hmsc->bot_data[6] = 0xFF;
329 hmsc->bot_data[7] = 0xFF;
331 hmsc->bot_data[8] = 0x03; // Descriptor code - No media.
332 hmsc->bot_data[9] = 0x00;
333 hmsc->bot_data[10] = 0x02; // 0x200 512 bytes
334 hmsc->bot_data[11] = 0x00;
338 hmsc->bot_data[3] = 0x08;
339 hmsc->bot_data[4] = (uint8_t)((blk_nbr - 1) >> 24);
340 hmsc->bot_data[5] = (uint8_t)((blk_nbr - 1) >> 16);
341 hmsc->bot_data[6] = (uint8_t)((blk_nbr - 1) >> 8);
342 hmsc->bot_data[7] = (uint8_t)(blk_nbr - 1);
344 hmsc->bot_data[8] = 0x02; // Descriptor code - Formatted media
345 hmsc->bot_data[9] = (uint8_t)(blk_size >> 16);
346 hmsc->bot_data[10] = (uint8_t)(blk_size >> 8);
347 hmsc->bot_data[11] = (uint8_t)(blk_size);
350 hmsc->bot_data_length = 12;
355 * @brief SCSI_ModeSense6
356 * Process Mode Sense6 command
357 * @param lun: Logical unit number
358 * @param params: Command parameters
361 static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
363 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
364 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
367 hmsc->bot_data_length = len;
372 hmsc->bot_data[len] = MSC_Mode_Sense6_data[len];
378 * @brief SCSI_ModeSense10
379 * Process Mode Sense10 command
380 * @param lun: Logical unit number
381 * @param params: Command parameters
384 static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
387 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
388 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
390 hmsc->bot_data_length = len;
395 hmsc->bot_data[len] = MSC_Mode_Sense10_data[len];
401 * @brief SCSI_RequestSense
402 * Process Request Sense command
403 * @param lun: Logical unit number
404 * @param params: Command parameters
408 static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
411 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
412 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
414 for(i=0 ; i < REQUEST_SENSE_DATA_LEN ; i++)
416 hmsc->bot_data[i] = 0;
419 hmsc->bot_data[0] = 0x70;
420 hmsc->bot_data[7] = REQUEST_SENSE_DATA_LEN - 6;
422 if((hmsc->scsi_sense_head != hmsc->scsi_sense_tail)) {
424 hmsc->bot_data[2] = hmsc->scsi_sense[hmsc->scsi_sense_head].Skey;
425 hmsc->bot_data[12] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASCQ;
426 hmsc->bot_data[13] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASC;
427 hmsc->scsi_sense_head++;
429 if (hmsc->scsi_sense_head == SENSE_LIST_DEEPTH)
431 hmsc->scsi_sense_head = 0;
434 hmsc->bot_data_length = REQUEST_SENSE_DATA_LEN;
436 if (params[4] <= REQUEST_SENSE_DATA_LEN)
438 hmsc->bot_data_length = params[4];
444 * @brief SCSI_SenseCode
445 * Load the last error code in the error list
446 * @param lun: Logical unit number
447 * @param sKey: Sense Key
448 * @param ASC: Additional Sense Key
452 void SCSI_SenseCode(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t sKey, uint8_t ASC)
454 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
455 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
457 hmsc->scsi_sense[hmsc->scsi_sense_tail].Skey = sKey;
458 hmsc->scsi_sense[hmsc->scsi_sense_tail].w.ASC = ASC << 8;
459 hmsc->scsi_sense_tail++;
460 if (hmsc->scsi_sense_tail == SENSE_LIST_DEEPTH)
462 hmsc->scsi_sense_tail = 0;
466 * @brief SCSI_StartStopUnit
467 * Process Start Stop Unit command
468 * @param lun: Logical unit number
469 * @param params: Command parameters
472 static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
474 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
475 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
477 hmsc->bot_data_length = 0;
483 * Process Read10 command
484 * @param lun: Logical unit number
485 * @param params: Command parameters
488 static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
490 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
491 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
493 if(hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
496 /* case 10 : Ho <> Di */
498 if ((hmsc->cbw.bmFlags & 0x80) != 0x80)
507 if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
516 hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) | \
517 ((uint32_t)params[3] << 16) | \
518 ((uint32_t)params[4] << 8) | \
521 hmsc->scsi_blk_len = ((uint32_t)params[7] << 8) | \
526 if( SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr, hmsc->scsi_blk_len) < 0)
528 return -1; /* error */
531 hmsc->bot_state = USBD_BOT_DATA_IN;
533 /* cases 4,5 : Hi <> Dn */
534 if (hmsc->cbw.dDataLength != (hmsc->scsi_blk_len * hmsc->scsi_blk_size))
543 hmsc->bot_data_length = S2S_MSC_MEDIA_PACKET;
545 return SCSI_ProcessRead(pdev, lun);
549 * @brief SCSI_Write10
550 * Process Write10 command
551 * @param lun: Logical unit number
552 * @param params: Command parameters
556 static int8_t SCSI_Write10 (USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
558 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
559 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
562 if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
564 /* case 8 : Hi <> Do */
566 if ((hmsc->cbw.bmFlags & 0x80) == 0x80)
575 /* Check whether Media is ready */
576 if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
585 /* Check If media is write-protected */
586 if(((USBD_StorageTypeDef *)pdev->pUserData)->IsWriteProtected(lun) !=0 )
596 hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) | \
597 ((uint32_t)params[3] << 16) | \
598 ((uint32_t)params[4] << 8) | \
600 hmsc->scsi_blk_len = ((uint32_t)params[7] << 8) | \
603 /* check if LBA address is in the right range */
604 if(SCSI_CheckAddressRange(pdev,
607 hmsc->scsi_blk_len) < 0)
609 return -1; /* error */
612 len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
614 /* cases 3,11,13 : Hn,Ho <> D0 */
615 if (hmsc->cbw.dDataLength != len)
624 len = MIN(len, S2S_MSC_MEDIA_PACKET);
626 /* Prepare EP to receive first data packet */
627 hmsc->bot_state = USBD_BOT_DATA_OUT;
628 USBD_LL_PrepareReceive (pdev,
633 else /* Write Process ongoing */
635 return SCSI_ProcessWrite(pdev, lun);
642 * @brief SCSI_Verify10
643 * Process Verify10 command
644 * @param lun: Logical unit number
645 * @param params: Command parameters
649 static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
651 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
652 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
654 if ((params[1]& 0x02) == 0x02)
656 SCSI_SenseCode (pdev,
659 INVALID_FIELED_IN_COMMAND);
660 return -1; /* Error, Verify Mode Not supported*/
663 if(SCSI_CheckAddressRange(pdev,
666 hmsc->scsi_blk_len) < 0)
668 return -1; /* error */
670 hmsc->bot_data_length = 0;
675 * @brief SCSI_CheckAddressRange
676 * Check address range
677 * @param lun: Logical unit number
678 * @param blk_offset: first block address
679 * @param blk_nbr: number of block to be processed
682 static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev, uint8_t lun , uint32_t blk_offset , uint16_t blk_nbr)
684 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
685 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
687 // michael@codesrc.com: Re-check block limits in cause we have different values
688 // for different LUN's.
691 if(((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &blkNbr, &blkSize) != 0)
699 // global variables. wooo
700 hmsc->scsi_blk_size = blkSize;
701 hmsc->scsi_blk_nbr = blkNbr;
703 if ((blk_offset + blk_nbr) > blkNbr )
708 ADDRESS_OUT_OF_RANGE);
715 * @brief SCSI_ProcessRead
716 * Handle Read Process
717 * @param lun: Logical unit number
720 static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev, uint8_t lun)
722 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
723 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
725 uint32_t len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
727 len = MIN(len, S2S_MSC_MEDIA_PACKET);
729 if( ((USBD_StorageTypeDef *)pdev->pUserData)->Read(lun ,
732 len / hmsc->scsi_blk_size) < 0)
738 UNRECOVERED_READ_ERROR);
743 USBD_LL_Transmit (pdev,
748 hmsc->scsi_blk_addr += (len / hmsc->scsi_blk_size);
749 hmsc->scsi_blk_len -= (len / hmsc->scsi_blk_size);
751 /* case 6 : Hi = Di */
752 hmsc->csw.dDataResidue -= len;
754 if (hmsc->scsi_blk_len == 0)
756 hmsc->bot_state = USBD_BOT_LAST_DATA_IN;
762 * @brief SCSI_ProcessWrite
763 * Handle Write Process
764 * @param lun: Logical unit number
768 static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev, uint8_t lun)
770 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
771 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
773 uint32_t len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
775 len = MIN(len, S2S_MSC_MEDIA_PACKET);
777 if(((USBD_StorageTypeDef *)pdev->pUserData)->Write(lun ,
780 len / hmsc->scsi_blk_size) < 0)
790 hmsc->scsi_blk_addr += (len / hmsc->scsi_blk_size);
791 hmsc->scsi_blk_len -= (len / hmsc->scsi_blk_size);
793 /* case 12 : Ho = Do */
794 hmsc->csw.dDataResidue -= len;
796 if (hmsc->scsi_blk_len == 0)
798 MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED);
802 len = MIN((hmsc->scsi_blk_len * hmsc->scsi_blk_size), S2S_MSC_MEDIA_PACKET);
803 /* Prepare EP to Receive next packet */
804 USBD_LL_PrepareReceive (pdev, MSC_EPOUT_ADDR, hmsc->bot_data, len);
823 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/