2 ******************************************************************************
3 * @file usbh_msc_scsi.c
4 * @author MCD Application Team
7 * @brief This file implements the SCSI commands
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 "usbh_msc_core.h"
24 #include "usbh_msc_scsi.h"
25 #include "usbh_msc_bot.h"
26 #include "usbh_ioreq.h"
30 /** @addtogroup USBH_LIB
34 /** @addtogroup USBH_CLASS
38 /** @addtogroup USBH_MSC_CLASS
42 /** @defgroup USBH_MSC_SCSI
43 * @brief This file includes the mass storage related functions
48 /** @defgroup USBH_MSC_SCSI_Private_TypesDefinitions
52 MassStorageParameter_TypeDef USBH_MSC_Param;
57 /** @defgroup USBH_MSC_SCSI_Private_Defines
64 /** @defgroup USBH_MSC_SCSI_Private_Macros
72 /** @defgroup USBH_MSC_SCSI_Private_Variables
76 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
77 #if defined ( __ICCARM__ ) /*!< IAR Compiler */
78 #pragma data_alignment=4
80 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
81 __ALIGN_BEGIN uint8_t USBH_DataInBuffer[512] __ALIGN_END ;
83 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
84 #if defined ( __ICCARM__ ) /*!< IAR Compiler */
85 #pragma data_alignment=4
87 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
88 __ALIGN_BEGIN uint8_t USBH_DataOutBuffer[512] __ALIGN_END ;
94 /** @defgroup USBH_MSC_SCSI_Private_FunctionPrototypes
102 /** @defgroup USBH_MSC_SCSI_Exported_Variables
111 /** @defgroup USBH_MSC_SCSI_Private_Functions
119 * @brief USBH_MSC_TestUnitReady
120 * Issues 'Test unit ready' command to the device. Once the response
121 * received, it updates the status to upper layer.
125 uint8_t USBH_MSC_TestUnitReady (USB_OTG_CORE_HANDLE *pdev)
128 USBH_MSC_Status_TypeDef status = USBH_MSC_BUSY;
130 if(HCD_IsDeviceConnected(pdev))
132 switch(USBH_MSC_BOTXferParam.CmdStateMachine)
135 /*Prepare the CBW and relevent field*/
136 USBH_MSC_CBWData.field.CBWTransferLength = 0; /* No Data Transfer */
137 USBH_MSC_CBWData.field.CBWFlags = USB_EP_DIR_OUT;
138 USBH_MSC_CBWData.field.CBWLength = CBW_LENGTH_TEST_UNIT_READY;
139 USBH_MSC_BOTXferParam.pRxTxBuff = USBH_MSC_CSWData.CSWArray;
140 USBH_MSC_BOTXferParam.DataLength = USBH_MSC_CSW_MAX_LENGTH;
141 USBH_MSC_BOTXferParam.MSCStateCurrent = USBH_MSC_TEST_UNIT_READY;
143 for(index = CBW_CB_LENGTH; index != 0; index--)
145 USBH_MSC_CBWData.field.CBWCB[index] = 0x00;
148 USBH_MSC_CBWData.field.CBWCB[0] = OPCODE_TEST_UNIT_READY;
149 USBH_MSC_BOTXferParam.BOTState = USBH_MSC_SEND_CBW;
150 /* Start the transfer, then let the state
151 machine magage the other transactions */
152 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_USB_TRANSFERS;
153 USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_BUSY;
154 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_WAIT_STATUS;
156 status = USBH_MSC_BUSY;
159 case CMD_WAIT_STATUS:
160 if(USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_OK)
162 /* Commands successfully sent and Response Received */
163 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
165 status = USBH_MSC_OK;
167 else if ( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_FAIL )
170 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
171 status = USBH_MSC_FAIL;
174 else if ( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_PHASE_ERROR )
177 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
178 status = USBH_MSC_PHASE_ERROR;
191 * @brief USBH_MSC_ReadCapacity10
192 * Issue the read capacity command to the device. Once the response
193 * received, it updates the status to upper layer
197 uint8_t USBH_MSC_ReadCapacity10(USB_OTG_CORE_HANDLE *pdev)
200 USBH_MSC_Status_TypeDef status = USBH_MSC_BUSY;
202 if(HCD_IsDeviceConnected(pdev))
204 switch(USBH_MSC_BOTXferParam.CmdStateMachine)
207 /*Prepare the CBW and relevent field*/
208 USBH_MSC_CBWData.field.CBWTransferLength = XFER_LEN_READ_CAPACITY10;
209 USBH_MSC_CBWData.field.CBWFlags = USB_EP_DIR_IN;
210 USBH_MSC_CBWData.field.CBWLength = CBW_LENGTH;
212 USBH_MSC_BOTXferParam.pRxTxBuff = USBH_DataInBuffer;
213 USBH_MSC_BOTXferParam.MSCStateCurrent = USBH_MSC_READ_CAPACITY10;
215 for(index = CBW_CB_LENGTH; index != 0; index--)
217 USBH_MSC_CBWData.field.CBWCB[index] = 0x00;
220 USBH_MSC_CBWData.field.CBWCB[0] = OPCODE_READ_CAPACITY10;
221 USBH_MSC_BOTXferParam.BOTState = USBH_MSC_SEND_CBW;
223 /* Start the transfer, then let the state machine manage the other
225 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_USB_TRANSFERS;
226 USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_BUSY;
227 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_WAIT_STATUS;
229 status = USBH_MSC_BUSY;
232 case CMD_WAIT_STATUS:
233 if(USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_OK)
235 /*assign the capacity*/
236 (((uint8_t*)&USBH_MSC_Param.MSCapacity )[3]) = USBH_DataInBuffer[0];
237 (((uint8_t*)&USBH_MSC_Param.MSCapacity )[2]) = USBH_DataInBuffer[1];
238 (((uint8_t*)&USBH_MSC_Param.MSCapacity )[1]) = USBH_DataInBuffer[2];
239 (((uint8_t*)&USBH_MSC_Param.MSCapacity )[0]) = USBH_DataInBuffer[3];
241 /*assign the page length*/
242 (((uint8_t*)&USBH_MSC_Param.MSPageLength )[1]) = USBH_DataInBuffer[6];
243 (((uint8_t*)&USBH_MSC_Param.MSPageLength )[0]) = USBH_DataInBuffer[7];
245 /* Commands successfully sent and Response Received */
246 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
247 status = USBH_MSC_OK;
249 else if ( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_FAIL )
252 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
253 status = USBH_MSC_FAIL;
255 else if ( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_PHASE_ERROR )
258 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
259 status = USBH_MSC_PHASE_ERROR;
263 /* Wait for the Commands to get Completed */
264 /* NO Change in state Machine */
277 * @brief USBH_MSC_ModeSense6
278 * Issue the Mode Sense6 Command to the device. This function is used
279 * for reading the WriteProtect Status of the Mass-Storage device.
283 uint8_t USBH_MSC_ModeSense6(USB_OTG_CORE_HANDLE *pdev)
286 USBH_MSC_Status_TypeDef status = USBH_MSC_BUSY;
288 if(HCD_IsDeviceConnected(pdev))
290 switch(USBH_MSC_BOTXferParam.CmdStateMachine)
293 /*Prepare the CBW and relevent field*/
294 USBH_MSC_CBWData.field.CBWTransferLength = XFER_LEN_MODE_SENSE6;
295 USBH_MSC_CBWData.field.CBWFlags = USB_EP_DIR_IN;
296 USBH_MSC_CBWData.field.CBWLength = CBW_LENGTH;
298 USBH_MSC_BOTXferParam.pRxTxBuff = USBH_DataInBuffer;
299 USBH_MSC_BOTXferParam.MSCStateCurrent = USBH_MSC_MODE_SENSE6;
301 for(index = CBW_CB_LENGTH; index != 0; index--)
303 USBH_MSC_CBWData.field.CBWCB[index] = 0x00;
306 USBH_MSC_CBWData.field.CBWCB[0] = OPCODE_MODE_SENSE6;
307 USBH_MSC_CBWData.field.CBWCB[2] = MODE_SENSE_PAGE_CONTROL_FIELD | \
308 MODE_SENSE_PAGE_CODE;
310 USBH_MSC_CBWData.field.CBWCB[4] = XFER_LEN_MODE_SENSE6;
312 USBH_MSC_BOTXferParam.BOTState = USBH_MSC_SEND_CBW;
314 /* Start the transfer, then let the state machine manage the other
316 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_USB_TRANSFERS;
317 USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_BUSY;
318 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_WAIT_STATUS;
320 status = USBH_MSC_BUSY;
323 case CMD_WAIT_STATUS:
324 if(USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_OK)
326 /* Assign the Write Protect status */
327 /* If WriteProtect = 0, Writing is allowed
328 If WriteProtect != 0, Disk is Write Protected */
329 if ( USBH_DataInBuffer[2] & MASK_MODE_SENSE_WRITE_PROTECT)
331 USBH_MSC_Param.MSWriteProtect = DISK_WRITE_PROTECTED;
335 USBH_MSC_Param.MSWriteProtect = 0;
338 /* Commands successfully sent and Response Received */
339 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
340 status = USBH_MSC_OK;
342 else if ( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_FAIL )
345 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
346 status = USBH_MSC_FAIL;
348 else if ( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_PHASE_ERROR )
351 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
352 status = USBH_MSC_PHASE_ERROR;
356 /* Wait for the Commands to get Completed */
357 /* NO Change in state Machine */
369 * @brief USBH_MSC_RequestSense
370 * Issues the Request Sense command to the device. Once the response
371 * received, it updates the status to upper layer
375 uint8_t USBH_MSC_RequestSense(USB_OTG_CORE_HANDLE *pdev)
377 USBH_MSC_Status_TypeDef status = USBH_MSC_BUSY;
382 if(HCD_IsDeviceConnected(pdev))
384 switch(USBH_MSC_BOTXferParam.CmdStateMachine)
388 /*Prepare the CBW and relevent field*/
389 USBH_MSC_CBWData.field.CBWTransferLength = \
390 ALLOCATION_LENGTH_REQUEST_SENSE;
391 USBH_MSC_CBWData.field.CBWFlags = USB_EP_DIR_IN;
392 USBH_MSC_CBWData.field.CBWLength = CBW_LENGTH;
394 USBH_MSC_BOTXferParam.pRxTxBuff = USBH_DataInBuffer;
395 USBH_MSC_BOTXferParam.MSCStateBkp = USBH_MSC_BOTXferParam.MSCStateCurrent;
396 USBH_MSC_BOTXferParam.MSCStateCurrent = USBH_MSC_REQUEST_SENSE;
399 for(index = CBW_CB_LENGTH; index != 0; index--)
401 USBH_MSC_CBWData.field.CBWCB[index] = 0x00;
404 USBH_MSC_CBWData.field.CBWCB[0] = OPCODE_REQUEST_SENSE;
405 USBH_MSC_CBWData.field.CBWCB[1] = DESC_REQUEST_SENSE;
406 USBH_MSC_CBWData.field.CBWCB[4] = ALLOCATION_LENGTH_REQUEST_SENSE;
408 USBH_MSC_BOTXferParam.BOTState = USBH_MSC_SEND_CBW;
409 /* Start the transfer, then let the state machine magage
410 the other transactions */
411 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_USB_TRANSFERS;
412 USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_BUSY;
413 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_WAIT_STATUS;
415 status = USBH_MSC_BUSY;
419 case CMD_WAIT_STATUS:
421 if(USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_OK)
424 (((uint8_t*)&USBH_MSC_Param.MSSenseKey )[3]) = USBH_DataInBuffer[0];
425 (((uint8_t*)&USBH_MSC_Param.MSSenseKey )[2]) = USBH_DataInBuffer[1];
426 (((uint8_t*)&USBH_MSC_Param.MSSenseKey )[1]) = USBH_DataInBuffer[2];
427 (((uint8_t*)&USBH_MSC_Param.MSSenseKey )[0]) = USBH_DataInBuffer[3];
429 /* Commands successfully sent and Response Received */
430 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
431 status = USBH_MSC_OK;
433 else if ( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_FAIL )
436 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
437 status = USBH_MSC_FAIL;
440 else if ( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_PHASE_ERROR )
443 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
444 status = USBH_MSC_PHASE_ERROR;
449 /* Wait for the Commands to get Completed */
450 /* NO Change in state Machine */
463 * @brief USBH_MSC_Write10
464 * Issue the write command to the device. Once the response received,
465 * it updates the status to upper layer
466 * @param dataBuffer : DataBuffer contains the data to write
467 * @param address : Address to which the data will be written
468 * @param nbOfbytes : NbOfbytes to be written
471 uint8_t USBH_MSC_Write10(USB_OTG_CORE_HANDLE *pdev,
477 USBH_MSC_Status_TypeDef status = USBH_MSC_BUSY;
480 if(HCD_IsDeviceConnected(pdev))
482 switch(USBH_MSC_BOTXferParam.CmdStateMachine)
485 USBH_MSC_CBWData.field.CBWTransferLength = nbOfbytes;
486 USBH_MSC_CBWData.field.CBWFlags = USB_EP_DIR_OUT;
487 USBH_MSC_CBWData.field.CBWLength = CBW_LENGTH;
488 USBH_MSC_BOTXferParam.pRxTxBuff = dataBuffer;
491 for(index = CBW_CB_LENGTH; index != 0; index--)
493 USBH_MSC_CBWData.field.CBWCB[index] = 0x00;
496 USBH_MSC_CBWData.field.CBWCB[0] = OPCODE_WRITE10;
498 /*logical block address*/
499 USBH_MSC_CBWData.field.CBWCB[2] = (((uint8_t*)&address)[3]) ;
500 USBH_MSC_CBWData.field.CBWCB[3] = (((uint8_t*)&address)[2]);
501 USBH_MSC_CBWData.field.CBWCB[4] = (((uint8_t*)&address)[1]);
502 USBH_MSC_CBWData.field.CBWCB[5] = (((uint8_t*)&address)[0]);
504 /*USBH_MSC_PAGE_LENGTH = 512*/
505 nbOfPages = nbOfbytes/ USBH_MSC_PAGE_LENGTH;
508 USBH_MSC_CBWData.field.CBWCB[7] = (((uint8_t *)&nbOfPages)[1]) ;
509 USBH_MSC_CBWData.field.CBWCB[8] = (((uint8_t *)&nbOfPages)[0]) ;
511 USBH_MSC_BOTXferParam.BOTState = USBH_MSC_SEND_CBW;
512 /* Start the transfer, then let the state machine
513 magage the other transactions */
514 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_USB_TRANSFERS;
515 USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_BUSY;
516 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_WAIT_STATUS;
518 status = USBH_MSC_BUSY;
522 case CMD_WAIT_STATUS:
523 if(USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_OK)
525 /* Commands successfully sent and Response Received */
526 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
527 status = USBH_MSC_OK;
529 else if ( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_FAIL )
532 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
535 else if ( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_PHASE_ERROR )
538 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
539 status = USBH_MSC_PHASE_ERROR;
551 * @brief USBH_MSC_Read10
552 * Issue the read command to the device. Once the response received,
553 * it updates the status to upper layer
554 * @param dataBuffer : DataBuffer will contain the data to be read
555 * @param address : Address from which the data will be read
556 * @param nbOfbytes : NbOfbytes to be read
559 uint8_t USBH_MSC_Read10(USB_OTG_CORE_HANDLE *pdev,
565 static USBH_MSC_Status_TypeDef status = USBH_MSC_BUSY;
567 status = USBH_MSC_BUSY;
569 if(HCD_IsDeviceConnected(pdev))
571 switch(USBH_MSC_BOTXferParam.CmdStateMachine)
574 /*Prepare the CBW and relevent field*/
575 USBH_MSC_CBWData.field.CBWTransferLength = nbOfbytes;
576 USBH_MSC_CBWData.field.CBWFlags = USB_EP_DIR_IN;
577 USBH_MSC_CBWData.field.CBWLength = CBW_LENGTH;
579 USBH_MSC_BOTXferParam.pRxTxBuff = dataBuffer;
581 for(index = CBW_CB_LENGTH; index != 0; index--)
583 USBH_MSC_CBWData.field.CBWCB[index] = 0x00;
586 USBH_MSC_CBWData.field.CBWCB[0] = OPCODE_READ10;
588 /*logical block address*/
590 USBH_MSC_CBWData.field.CBWCB[2] = (((uint8_t*)&address)[3]);
591 USBH_MSC_CBWData.field.CBWCB[3] = (((uint8_t*)&address)[2]);
592 USBH_MSC_CBWData.field.CBWCB[4] = (((uint8_t*)&address)[1]);
593 USBH_MSC_CBWData.field.CBWCB[5] = (((uint8_t*)&address)[0]);
595 /*USBH_MSC_PAGE_LENGTH = 512*/
596 nbOfPages = nbOfbytes/ USBH_MSC_PAGE_LENGTH;
599 USBH_MSC_CBWData.field.CBWCB[7] = (((uint8_t *)&nbOfPages)[1]) ;
600 USBH_MSC_CBWData.field.CBWCB[8] = (((uint8_t *)&nbOfPages)[0]) ;
603 USBH_MSC_BOTXferParam.BOTState = USBH_MSC_SEND_CBW;
604 /* Start the transfer, then let the state machine
605 magage the other transactions */
606 USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOT_USB_TRANSFERS;
607 USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_BUSY;
608 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_WAIT_STATUS;
610 status = USBH_MSC_BUSY;
614 case CMD_WAIT_STATUS:
616 if((USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_OK) && \
617 (HCD_IsDeviceConnected(pdev)))
619 /* Commands successfully sent and Response Received */
620 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
621 status = USBH_MSC_OK;
623 else if (( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_FAIL ) && \
624 (HCD_IsDeviceConnected(pdev)))
627 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
630 else if ( USBH_MSC_BOTXferParam.BOTXferStatus == USBH_MSC_PHASE_ERROR )
633 USBH_MSC_BOTXferParam.CmdStateMachine = CMD_SEND_STATE;
634 status = USBH_MSC_PHASE_ERROR;
638 /* Wait for the Commands to get Completed */
639 /* NO Change in state Machine */
671 /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/