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)
317 hmsc->bot_data[3] = 0x08;
318 hmsc->bot_data[4] = (uint8_t)((blk_nbr - 1) >> 24);
319 hmsc->bot_data[5] = (uint8_t)((blk_nbr - 1) >> 16);
320 hmsc->bot_data[6] = (uint8_t)((blk_nbr - 1) >> 8);
321 hmsc->bot_data[7] = (uint8_t)(blk_nbr - 1);
323 hmsc->bot_data[8] = 0x02;
324 hmsc->bot_data[9] = (uint8_t)(blk_size >> 16);
325 hmsc->bot_data[10] = (uint8_t)(blk_size >> 8);
326 hmsc->bot_data[11] = (uint8_t)(blk_size);
328 hmsc->bot_data_length = 12;
333 * @brief SCSI_ModeSense6
334 * Process Mode Sense6 command
335 * @param lun: Logical unit number
336 * @param params: Command parameters
339 static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
341 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
342 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
345 hmsc->bot_data_length = len;
350 hmsc->bot_data[len] = MSC_Mode_Sense6_data[len];
356 * @brief SCSI_ModeSense10
357 * Process Mode Sense10 command
358 * @param lun: Logical unit number
359 * @param params: Command parameters
362 static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
365 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
366 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
368 hmsc->bot_data_length = len;
373 hmsc->bot_data[len] = MSC_Mode_Sense10_data[len];
379 * @brief SCSI_RequestSense
380 * Process Request Sense command
381 * @param lun: Logical unit number
382 * @param params: Command parameters
386 static int8_t SCSI_RequestSense (USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
389 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
390 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
392 for(i=0 ; i < REQUEST_SENSE_DATA_LEN ; i++)
394 hmsc->bot_data[i] = 0;
397 hmsc->bot_data[0] = 0x70;
398 hmsc->bot_data[7] = REQUEST_SENSE_DATA_LEN - 6;
400 if((hmsc->scsi_sense_head != hmsc->scsi_sense_tail)) {
402 hmsc->bot_data[2] = hmsc->scsi_sense[hmsc->scsi_sense_head].Skey;
403 hmsc->bot_data[12] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASCQ;
404 hmsc->bot_data[13] = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASC;
405 hmsc->scsi_sense_head++;
407 if (hmsc->scsi_sense_head == SENSE_LIST_DEEPTH)
409 hmsc->scsi_sense_head = 0;
412 hmsc->bot_data_length = REQUEST_SENSE_DATA_LEN;
414 if (params[4] <= REQUEST_SENSE_DATA_LEN)
416 hmsc->bot_data_length = params[4];
422 * @brief SCSI_SenseCode
423 * Load the last error code in the error list
424 * @param lun: Logical unit number
425 * @param sKey: Sense Key
426 * @param ASC: Additional Sense Key
430 void SCSI_SenseCode(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t sKey, uint8_t ASC)
432 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
433 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
435 hmsc->scsi_sense[hmsc->scsi_sense_tail].Skey = sKey;
436 hmsc->scsi_sense[hmsc->scsi_sense_tail].w.ASC = ASC << 8;
437 hmsc->scsi_sense_tail++;
438 if (hmsc->scsi_sense_tail == SENSE_LIST_DEEPTH)
440 hmsc->scsi_sense_tail = 0;
444 * @brief SCSI_StartStopUnit
445 * Process Start Stop Unit command
446 * @param lun: Logical unit number
447 * @param params: Command parameters
450 static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
452 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
453 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
455 hmsc->bot_data_length = 0;
461 * Process Read10 command
462 * @param lun: Logical unit number
463 * @param params: Command parameters
466 static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
468 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
469 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
471 if(hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
474 /* case 10 : Ho <> Di */
476 if ((hmsc->cbw.bmFlags & 0x80) != 0x80)
485 if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
494 hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) | \
495 ((uint32_t)params[3] << 16) | \
496 ((uint32_t)params[4] << 8) | \
499 hmsc->scsi_blk_len = ((uint32_t)params[7] << 8) | \
504 if( SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr, hmsc->scsi_blk_len) < 0)
506 return -1; /* error */
509 hmsc->bot_state = USBD_BOT_DATA_IN;
511 /* cases 4,5 : Hi <> Dn */
512 if (hmsc->cbw.dDataLength != (hmsc->scsi_blk_len * hmsc->scsi_blk_size))
521 hmsc->bot_data_length = S2S_MSC_MEDIA_PACKET;
523 return SCSI_ProcessRead(pdev, lun);
527 * @brief SCSI_Write10
528 * Process Write10 command
529 * @param lun: Logical unit number
530 * @param params: Command parameters
534 static int8_t SCSI_Write10 (USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
536 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
537 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
540 if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
542 /* case 8 : Hi <> Do */
544 if ((hmsc->cbw.bmFlags & 0x80) == 0x80)
553 /* Check whether Media is ready */
554 if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
563 /* Check If media is write-protected */
564 if(((USBD_StorageTypeDef *)pdev->pUserData)->IsWriteProtected(lun) !=0 )
574 hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) | \
575 ((uint32_t)params[3] << 16) | \
576 ((uint32_t)params[4] << 8) | \
578 hmsc->scsi_blk_len = ((uint32_t)params[7] << 8) | \
581 /* check if LBA address is in the right range */
582 if(SCSI_CheckAddressRange(pdev,
585 hmsc->scsi_blk_len) < 0)
587 return -1; /* error */
590 len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
592 /* cases 3,11,13 : Hn,Ho <> D0 */
593 if (hmsc->cbw.dDataLength != len)
602 len = MIN(len, S2S_MSC_MEDIA_PACKET);
604 /* Prepare EP to receive first data packet */
605 hmsc->bot_state = USBD_BOT_DATA_OUT;
606 USBD_LL_PrepareReceive (pdev,
611 else /* Write Process ongoing */
613 return SCSI_ProcessWrite(pdev, lun);
620 * @brief SCSI_Verify10
621 * Process Verify10 command
622 * @param lun: Logical unit number
623 * @param params: Command parameters
627 static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun , uint8_t *params)
629 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
630 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
632 if ((params[1]& 0x02) == 0x02)
634 SCSI_SenseCode (pdev,
637 INVALID_FIELED_IN_COMMAND);
638 return -1; /* Error, Verify Mode Not supported*/
641 if(SCSI_CheckAddressRange(pdev,
644 hmsc->scsi_blk_len) < 0)
646 return -1; /* error */
648 hmsc->bot_data_length = 0;
653 * @brief SCSI_CheckAddressRange
654 * Check address range
655 * @param lun: Logical unit number
656 * @param blk_offset: first block address
657 * @param blk_nbr: number of block to be processed
660 static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef *pdev, uint8_t lun , uint32_t blk_offset , uint16_t blk_nbr)
662 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
663 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
665 // michael@codesrc.com: Re-check block limits in cause we have different values
666 // for different LUN's.
669 if(((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &blkNbr, &blkSize) != 0)
677 // global variables. wooo
678 hmsc->scsi_blk_size = blkSize;
679 hmsc->scsi_blk_nbr = blkNbr;
681 if ((blk_offset + blk_nbr) > blkNbr )
686 ADDRESS_OUT_OF_RANGE);
693 * @brief SCSI_ProcessRead
694 * Handle Read Process
695 * @param lun: Logical unit number
698 static int8_t SCSI_ProcessRead (USBD_HandleTypeDef *pdev, uint8_t lun)
700 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
701 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
703 uint32_t len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
705 len = MIN(len, S2S_MSC_MEDIA_PACKET);
707 // TODO there is a dcache issue here.
708 // work out how, and when, to flush cashes between sdio dma and usb dma
709 memset (hmsc->bot_data, 0xAA, len);
710 if( ((USBD_StorageTypeDef *)pdev->pUserData)->Read(lun ,
713 len / hmsc->scsi_blk_size) < 0)
719 UNRECOVERED_READ_ERROR);
724 USBD_LL_Transmit (pdev,
729 hmsc->scsi_blk_addr += (len / hmsc->scsi_blk_size);
730 hmsc->scsi_blk_len -= (len / hmsc->scsi_blk_size);
732 /* case 6 : Hi = Di */
733 hmsc->csw.dDataResidue -= len;
735 if (hmsc->scsi_blk_len == 0)
737 hmsc->bot_state = USBD_BOT_LAST_DATA_IN;
743 * @brief SCSI_ProcessWrite
744 * Handle Write Process
745 * @param lun: Logical unit number
749 static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef *pdev, uint8_t lun)
751 USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
752 USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
754 uint32_t len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
756 len = MIN(len, S2S_MSC_MEDIA_PACKET);
758 if(((USBD_StorageTypeDef *)pdev->pUserData)->Write(lun ,
761 len / hmsc->scsi_blk_size) < 0)
771 hmsc->scsi_blk_addr += (len / hmsc->scsi_blk_size);
772 hmsc->scsi_blk_len -= (len / hmsc->scsi_blk_size);
774 /* case 12 : Ho = Do */
775 hmsc->csw.dDataResidue -= len;
777 if (hmsc->scsi_blk_len == 0)
779 MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED);
783 len = MIN((hmsc->scsi_blk_len * hmsc->scsi_blk_size), S2S_MSC_MEDIA_PACKET);
784 /* Prepare EP to Receive next packet */
785 USBD_LL_PrepareReceive (pdev, MSC_EPOUT_ADDR, hmsc->bot_data, len);
804 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/