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****/