#include "MassStoreCommands.h"\r
\r
/* Globals: */\r
-/** Current CBW to send to the device. This is automatically filled by the routines\r
- * in this file and is not externally accessible.\r
- */\r
-static CommandBlockWrapper_t SCSICommandBlock;\r
-\r
-/** Current CSW received from the device. This is automatically filled by the routines\r
- * in this file and is externally accessible so that the return codes may be checked.\r
- */\r
-CommandStatusWrapper_t SCSICommandStatus;\r
-\r
/** Current Tag value used in issued CBWs to the device. This is automatically incremented\r
- * by the routines in this file, and is not externally accessible.\r
+ * each time a command is sent, and is not externally accessible.\r
*/\r
-static uint32_t MassStore_Tag = 1;\r
+static uint32_t MassStore_Tag = 1;\r
\r
\r
/** Routine to send the current CBW to the device, and increment the Tag value as needed.\r
*\r
+ * \param[in] SCSICommandBlock Pointer to a SCSI command block structure to send to the attached device\r
+ * \param[in,out] BufferPtr Pointer to a buffer for the data to send or receive to/from the device, or NULL if no data\r
+ *\r
* \return A value from the Pipe_Stream_RW_ErrorCodes_t enum\r
*/\r
-static uint8_t MassStore_SendCommand(void)\r
+static uint8_t MassStore_SendCommand(CommandBlockWrapper_t* SCSICommandBlock, void* BufferPtr)\r
{\r
uint8_t ErrorCode = PIPE_RWSTREAM_NoError;\r
\r
- /* Each transmission should have a unique tag value, excluding values 0 and 0xFFFFFFFF */\r
- if (++MassStore_Tag == 0xFFFFFFFF)\r
+ /* Each transmission should have a unique tag value, increment before use */\r
+ SCSICommandBlock->Tag = ++MassStore_Tag;\r
+\r
+ /* Wrap Tag value when invalid - MS class defines tag values of 0 and 0xFFFFFFFF to be invalid */\r
+ if (MassStore_Tag == 0xFFFFFFFF)\r
MassStore_Tag = 1;\r
\r
/* Select the OUT data pipe for CBW transmission */\r
Pipe_Unfreeze();\r
\r
/* Write the CBW command to the OUT pipe */\r
- if ((ErrorCode = Pipe_Write_Stream_LE(&SCSICommandBlock, sizeof(CommandBlockWrapper_t))) != PIPE_RWSTREAM_NoError)\r
+ if ((ErrorCode = Pipe_Write_Stream_LE(SCSICommandBlock, sizeof(CommandBlockWrapper_t))) != PIPE_RWSTREAM_NoError)\r
return ErrorCode;\r
\r
/* Send the data in the OUT pipe to the attached device */\r
Pipe_ClearOUT();\r
\r
/* Wait until command has been sent */\r
- while(!(Pipe_IsOUTReady()));\r
+ Pipe_WaitUntilReady();\r
\r
/* Freeze pipe after use */\r
Pipe_Freeze();\r
\r
- return PIPE_RWSTREAM_NoError;\r
+ /* Send data if any */\r
+ if ((BufferPtr != NULL) &&\r
+ ((ErrorCode = MassStore_SendReceiveData(SCSICommandBlock, BufferPtr)) != PIPE_READYWAIT_NoError))\r
+ {\r
+ Pipe_Freeze();\r
+ return ErrorCode;\r
+ }\r
+ \r
+ return ErrorCode;\r
}\r
\r
/** Waits until the attached device is ready to accept data following a CBW, checking\r
/** Sends or receives the transaction's data stage to or from the attached device, reading or\r
* writing to the nominated buffer.\r
*\r
- * \param[in,out] BufferPtr Pointer to the data buffer to read from or write to\r
+ * \param[in] SCSICommandBlock Pointer to a SCSI command block structure being sent to the attached device\r
+ * \param[in,out] BufferPtr Pointer to the data buffer to read from or write to\r
*\r
* \return A value from the Pipe_Stream_RW_ErrorCodes_t enum\r
*/\r
-static uint8_t MassStore_SendReceiveData(void* BufferPtr)\r
+static uint8_t MassStore_SendReceiveData(CommandBlockWrapper_t* SCSICommandBlock, void* BufferPtr)\r
{\r
uint8_t ErrorCode = PIPE_RWSTREAM_NoError;\r
- uint16_t BytesRem = SCSICommandBlock.Header.DataTransferLength;\r
+ uint16_t BytesRem = SCSICommandBlock->DataTransferLength;\r
\r
/* Check the direction of the SCSI command data stage */\r
- if (SCSICommandBlock.Header.Flags & COMMAND_DIRECTION_DATA_IN)\r
+ if (SCSICommandBlock->Flags & COMMAND_DIRECTION_DATA_IN)\r
{\r
+ /* Wait until the device has replied with some data */\r
+ if ((ErrorCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError)\r
+ return ErrorCode;\r
+ \r
/* Select the IN data pipe for data reception */\r
Pipe_SelectPipe(MASS_STORE_DATA_IN_PIPE);\r
Pipe_Unfreeze();\r
\r
/** Routine to receive the current CSW from the device.\r
*\r
- * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum\r
+ * \param[out] SCSICommandStatus Pointer to a destination where the returned status data should be stored\r
+ *\r
+ * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum, or MASS_STORE_SCSI_COMMAND_FAILED if the SCSI command fails\r
*/\r
-static uint8_t MassStore_GetReturnedStatus(void)\r
+static uint8_t MassStore_GetReturnedStatus(CommandStatusWrapper_t* SCSICommandStatus)\r
{\r
uint8_t ErrorCode = PIPE_RWSTREAM_NoError;\r
\r
Pipe_Unfreeze();\r
\r
/* Load in the CSW from the attached device */\r
- if ((ErrorCode = Pipe_Read_Stream_LE(&SCSICommandStatus, sizeof(CommandStatusWrapper_t))) != PIPE_RWSTREAM_NoError)\r
+ if ((ErrorCode = Pipe_Read_Stream_LE(SCSICommandStatus, sizeof(CommandStatusWrapper_t))) != PIPE_RWSTREAM_NoError)\r
return ErrorCode;\r
\r
/* Clear the data ready for next reception */\r
/* Freeze the IN pipe after use */\r
Pipe_Freeze();\r
\r
- return PIPE_RWSTREAM_NoError;\r
+ /* Check to see if command failed */\r
+ if (SCSICommandStatus->Status != Command_Pass)\r
+ ErrorCode = MASS_STORE_SCSI_COMMAND_FAILED;\r
+ \r
+ return ErrorCode;\r
}\r
\r
/** Issues a Mass Storage class specific request to reset the attached device's Mass Storage interface,\r
* readying the device for the next CBW.\r
*\r
- * \return A value from the USB_Host_SendControlErrorCodes_t enum\r
+ * \return A value from the USB_Host_SendControlErrorCodes_t enum, or MASS_STORE_SCSI_COMMAND_FAILED if the SCSI command fails\r
*/\r
uint8_t MassStore_MassStorageReset(void)\r
{\r
*\r
* \param[out] MaxLUNIndex Pointer to the location that the maximum LUN index value should be stored\r
*\r
- * \return A value from the USB_Host_SendControlErrorCodes_t enum\r
+ * \return A value from the USB_Host_SendControlErrorCodes_t enum, or MASS_STORE_SCSI_COMMAND_FAILED if the SCSI command fails\r
*/\r
uint8_t MassStore_GetMaxLUN(uint8_t* const MaxLUNIndex)\r
{\r
* \param[in] LUNIndex Index of the LUN inside the device the command is being addressed to\r
* \param[out] InquiryPtr Pointer to the inquiry data structure where the inquiry data from the device is to be stored\r
*\r
- * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum\r
+ * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum, or MASS_STORE_SCSI_COMMAND_FAILED if the SCSI command fails\r
*/\r
-uint8_t MassStore_Inquiry(const uint8_t LUNIndex, const SCSI_Inquiry_Response_t* const InquiryPtr)\r
+uint8_t MassStore_Inquiry(const uint8_t LUNIndex, SCSI_Inquiry_Response_t* const InquiryPtr)\r
{\r
- uint8_t ReturnCode = PIPE_RWSTREAM_NoError;\r
+ uint8_t ErrorCode = PIPE_RWSTREAM_NoError;\r
\r
/* Create a CBW with a SCSI command to issue INQUIRY command */\r
- SCSICommandBlock = (CommandBlockWrapper_t)\r
+ CommandBlockWrapper_t SCSICommandBlock = (CommandBlockWrapper_t)\r
{\r
- .Header =\r
- {\r
- .Signature = CBW_SIGNATURE,\r
- .Tag = MassStore_Tag,\r
- .DataTransferLength = sizeof(SCSI_Inquiry_Response_t),\r
- .Flags = COMMAND_DIRECTION_DATA_IN,\r
- .LUN = LUNIndex,\r
- .SCSICommandLength = 6\r
- },\r
- \r
- .SCSICommandData =\r
+ .Signature = CBW_SIGNATURE,\r
+ .DataTransferLength = sizeof(SCSI_Inquiry_Response_t),\r
+ .Flags = COMMAND_DIRECTION_DATA_IN,\r
+ .LUN = LUNIndex,\r
+ .SCSICommandLength = 6,\r
+ .SCSICommandData =\r
{\r
SCSI_CMD_INQUIRY,\r
0x00, // Reserved\r
}\r
};\r
\r
- /* Send SCSI command to the attached device */\r
- MassStore_SendCommand();\r
+ CommandStatusWrapper_t SCSICommandStatus;\r
\r
- /* Wait until data received from the device */\r
- if ((ReturnCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError)\r
+ /* Send the command and any data to the attached device */\r
+ if ((ErrorCode = MassStore_SendCommand(&SCSICommandBlock, InquiryPtr)) != PIPE_RWSTREAM_NoError)\r
{\r
Pipe_Freeze();\r
- return ReturnCode;\r
+ return ErrorCode;\r
}\r
-\r
- /* Read the returned sense data into the buffer */\r
- if ((ReturnCode = MassStore_SendReceiveData((uint8_t*)InquiryPtr)) != PIPE_RWSTREAM_NoError)\r
- {\r
- Pipe_Freeze();\r
- return ReturnCode;\r
- } \r
\r
- /* Read in the returned CSW from the device */\r
- if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError)\r
+ /* Retrieve status information from the attached device */\r
+ if ((ErrorCode = MassStore_GetReturnedStatus(&SCSICommandStatus)) != PIPE_RWSTREAM_NoError)\r
{\r
Pipe_Freeze();\r
- return ReturnCode;\r
+ return ErrorCode;\r
}\r
- \r
- return PIPE_RWSTREAM_NoError;\r
+\r
+ return ErrorCode;\r
}\r
\r
/** Issues a SCSI Request Sense command to the attached device, to determine the current SCSI sense information. This\r
* \param[in] LUNIndex Index of the LUN inside the device the command is being addressed to\r
* \param[out] SensePtr Pointer to the sense data structure where the sense data from the device is to be stored\r
*\r
- * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum\r
+ * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum, or MASS_STORE_SCSI_COMMAND_FAILED if the SCSI command fails\r
*/\r
-uint8_t MassStore_RequestSense(const uint8_t LUNIndex, const SCSI_Request_Sense_Response_t* const SensePtr)\r
+uint8_t MassStore_RequestSense(const uint8_t LUNIndex, SCSI_Request_Sense_Response_t* const SensePtr)\r
{\r
- uint8_t ReturnCode = PIPE_RWSTREAM_NoError;\r
+ uint8_t ErrorCode = PIPE_RWSTREAM_NoError;\r
\r
/* Create a CBW with a SCSI command to issue REQUEST SENSE command */\r
- SCSICommandBlock = (CommandBlockWrapper_t)\r
+ CommandBlockWrapper_t SCSICommandBlock = (CommandBlockWrapper_t)\r
{\r
- .Header =\r
- {\r
- .Signature = CBW_SIGNATURE,\r
- .Tag = MassStore_Tag,\r
- .DataTransferLength = sizeof(SCSI_Request_Sense_Response_t),\r
- .Flags = COMMAND_DIRECTION_DATA_IN,\r
- .LUN = LUNIndex,\r
- .SCSICommandLength = 6\r
- },\r
- \r
+ .Signature = CBW_SIGNATURE,\r
+ .DataTransferLength = sizeof(SCSI_Request_Sense_Response_t),\r
+ .Flags = COMMAND_DIRECTION_DATA_IN,\r
+ .LUN = LUNIndex,\r
+ .SCSICommandLength = 6,\r
.SCSICommandData =\r
{\r
SCSI_CMD_REQUEST_SENSE,\r
}\r
};\r
\r
- /* Send SCSI command to the attached device */\r
- MassStore_SendCommand();\r
+ CommandStatusWrapper_t SCSICommandStatus;\r
\r
- /* Wait until data received from the device */\r
- if ((ReturnCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError)\r
+ /* Send the command and any data to the attached device */\r
+ if ((ErrorCode = MassStore_SendCommand(&SCSICommandBlock, SensePtr)) != PIPE_RWSTREAM_NoError)\r
{\r
Pipe_Freeze();\r
- return ReturnCode;\r
+ return ErrorCode;\r
}\r
-\r
- /* Read the returned sense data into the buffer */\r
- if ((ReturnCode = MassStore_SendReceiveData((uint8_t*)SensePtr)) != PIPE_RWSTREAM_NoError)\r
- {\r
- Pipe_Freeze();\r
- return ReturnCode;\r
- } \r
\r
- /* Read in the returned CSW from the device */\r
- if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError)\r
+ /* Retrieve status information from the attached device */\r
+ if ((ErrorCode = MassStore_GetReturnedStatus(&SCSICommandStatus)) != PIPE_RWSTREAM_NoError)\r
{\r
Pipe_Freeze();\r
- return ReturnCode;\r
+ return ErrorCode;\r
}\r
- \r
- return PIPE_RWSTREAM_NoError;\r
+\r
+ return ErrorCode;\r
}\r
\r
/** Issues a SCSI Device Block Read command to the attached device, to read in one or more data blocks from the\r
* \param[in] BlockSize Size in bytes of each block to read\r
* \param[out] BufferPtr Pointer to the buffer where the read data is to be written to\r
*\r
- * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum\r
+ * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum, or MASS_STORE_SCSI_COMMAND_FAILED if the SCSI command fails\r
*/\r
uint8_t MassStore_ReadDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockAddress,\r
const uint8_t Blocks, const uint16_t BlockSize, void* BufferPtr)\r
{\r
- uint8_t ReturnCode = PIPE_RWSTREAM_NoError;\r
+ uint8_t ErrorCode = PIPE_RWSTREAM_NoError;\r
\r
/* Create a CBW with a SCSI command to read in the given blocks from the device */\r
- SCSICommandBlock = (CommandBlockWrapper_t)\r
+ CommandBlockWrapper_t SCSICommandBlock = (CommandBlockWrapper_t)\r
{\r
- .Header =\r
- {\r
- .Signature = CBW_SIGNATURE,\r
- .Tag = MassStore_Tag,\r
- .DataTransferLength = ((uint32_t)Blocks * BlockSize),\r
- .Flags = COMMAND_DIRECTION_DATA_IN,\r
- .LUN = LUNIndex,\r
- .SCSICommandLength = 10\r
- },\r
- \r
- .SCSICommandData =\r
+ .Signature = CBW_SIGNATURE,\r
+ .DataTransferLength = ((uint32_t)Blocks * BlockSize),\r
+ .Flags = COMMAND_DIRECTION_DATA_IN,\r
+ .LUN = LUNIndex,\r
+ .SCSICommandLength = 10,\r
+ .SCSICommandData =\r
{\r
SCSI_CMD_READ_10,\r
0x00, // Unused (control bits, all off)\r
}\r
};\r
\r
- /* Send SCSI command to the attached device */\r
- MassStore_SendCommand();\r
+ CommandStatusWrapper_t SCSICommandStatus;\r
\r
- /* Wait until data received from the device */\r
- if ((ReturnCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError)\r
+ /* Send the command and any data to the attached device */\r
+ if ((ErrorCode = MassStore_SendCommand(&SCSICommandBlock, BufferPtr)) != PIPE_RWSTREAM_NoError)\r
{\r
Pipe_Freeze();\r
- return ReturnCode;\r
+ return ErrorCode;\r
}\r
-\r
- /* Read the returned block data into the buffer */\r
- if ((ReturnCode = MassStore_SendReceiveData(BufferPtr)) != PIPE_RWSTREAM_NoError)\r
- {\r
- Pipe_Freeze();\r
- return ReturnCode;\r
- } \r
\r
- /* Read in the returned CSW from the device */\r
- if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError)\r
+ /* Retrieve status information from the attached device */\r
+ if ((ErrorCode = MassStore_GetReturnedStatus(&SCSICommandStatus)) != PIPE_RWSTREAM_NoError)\r
{\r
Pipe_Freeze();\r
- return ReturnCode;\r
+ return ErrorCode;\r
}\r
- \r
- return PIPE_RWSTREAM_NoError;\r
+\r
+ return ErrorCode;\r
}\r
\r
/** Issues a SCSI Device Block Write command to the attached device, to write one or more data blocks to the\r
* \param[in] BlockSize Size in bytes of each block to write\r
* \param[in] BufferPtr Pointer to the buffer where the write data is to be sourced from\r
*\r
- * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum\r
+ * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum, or MASS_STORE_SCSI_COMMAND_FAILED if the SCSI command fails\r
*/\r
uint8_t MassStore_WriteDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockAddress,\r
const uint8_t Blocks, const uint16_t BlockSize, void* BufferPtr)\r
{\r
- uint8_t ReturnCode = PIPE_RWSTREAM_NoError;\r
+ uint8_t ErrorCode = PIPE_RWSTREAM_NoError;\r
\r
/* Create a CBW with a SCSI command to write the given blocks to the device */\r
- SCSICommandBlock = (CommandBlockWrapper_t)\r
+ CommandBlockWrapper_t SCSICommandBlock = (CommandBlockWrapper_t)\r
{\r
- .Header =\r
- {\r
- .Signature = CBW_SIGNATURE,\r
- .Tag = MassStore_Tag,\r
- .DataTransferLength = ((uint32_t)Blocks * BlockSize),\r
- .Flags = COMMAND_DIRECTION_DATA_OUT,\r
- .LUN = LUNIndex,\r
- .SCSICommandLength = 10\r
- },\r
- \r
- .SCSICommandData =\r
+ .Signature = CBW_SIGNATURE,\r
+ .DataTransferLength = ((uint32_t)Blocks * BlockSize),\r
+ .Flags = COMMAND_DIRECTION_DATA_OUT,\r
+ .LUN = LUNIndex,\r
+ .SCSICommandLength = 10,\r
+ .SCSICommandData =\r
{\r
SCSI_CMD_WRITE_10,\r
0x00, // Unused (control bits, all off)\r
}\r
};\r
\r
- /* Send SCSI command to the attached device */\r
- MassStore_SendCommand();\r
+ CommandStatusWrapper_t SCSICommandStatus;\r
\r
- /* Write the data to the device from the buffer */\r
- if ((ReturnCode = MassStore_SendReceiveData(BufferPtr)) != PIPE_RWSTREAM_NoError)\r
+ /* Send the command and any data to the attached device */\r
+ if ((ErrorCode = MassStore_SendCommand(&SCSICommandBlock, BufferPtr)) != PIPE_RWSTREAM_NoError)\r
{\r
Pipe_Freeze();\r
- return ReturnCode;\r
- } \r
+ return ErrorCode;\r
+ }\r
\r
- /* Read in the returned CSW from the device */\r
- if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError)\r
+ /* Retrieve status information from the attached device */\r
+ if ((ErrorCode = MassStore_GetReturnedStatus(&SCSICommandStatus)) != PIPE_RWSTREAM_NoError)\r
{\r
Pipe_Freeze();\r
- return ReturnCode;\r
+ return ErrorCode;\r
}\r
- \r
- return PIPE_RWSTREAM_NoError;\r
+\r
+ return ErrorCode;\r
}\r
\r
/** Issues a SCSI Device Test Unit Ready command to the attached device, to determine if the device is ready to accept\r
*\r
* \param[in] LUNIndex Index of the LUN inside the device the command is being addressed to\r
*\r
- * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum\r
+ * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum, or MASS_STORE_SCSI_COMMAND_FAILED if the SCSI command fails\r
*/\r
uint8_t MassStore_TestUnitReady(const uint8_t LUNIndex)\r
{\r
- uint8_t ReturnCode = PIPE_RWSTREAM_NoError; \r
+ uint8_t ErrorCode = PIPE_RWSTREAM_NoError; \r
\r
/* Create a CBW with a SCSI command to issue TEST UNIT READY command */\r
- SCSICommandBlock = (CommandBlockWrapper_t)\r
+ CommandBlockWrapper_t SCSICommandBlock = (CommandBlockWrapper_t)\r
{\r
- .Header =\r
- {\r
- .Signature = CBW_SIGNATURE,\r
- .Tag = MassStore_Tag,\r
- .DataTransferLength = 0,\r
- .Flags = COMMAND_DIRECTION_DATA_IN,\r
- .LUN = LUNIndex,\r
- .SCSICommandLength = 6\r
- },\r
- \r
- .SCSICommandData =\r
+ .Signature = CBW_SIGNATURE,\r
+ .DataTransferLength = 0,\r
+ .Flags = COMMAND_DIRECTION_DATA_IN,\r
+ .LUN = LUNIndex,\r
+ .SCSICommandLength = 6,\r
+ .SCSICommandData =\r
{\r
SCSI_CMD_TEST_UNIT_READY,\r
0x00, // Reserved\r
}\r
};\r
\r
- /* Send SCSI command to the attached device */\r
- MassStore_SendCommand();\r
+ CommandStatusWrapper_t SCSICommandStatus;\r
\r
- /* Read in the returned CSW from the device */\r
- if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError)\r
+ /* Send the command and any data to the attached device */\r
+ if ((ErrorCode = MassStore_SendCommand(&SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)\r
{\r
Pipe_Freeze();\r
- return ReturnCode;\r
+ return ErrorCode;\r
}\r
\r
- return PIPE_RWSTREAM_NoError;\r
+ /* Retrieve status information from the attached device */\r
+ if ((ErrorCode = MassStore_GetReturnedStatus(&SCSICommandStatus)) != PIPE_RWSTREAM_NoError)\r
+ {\r
+ Pipe_Freeze();\r
+ return ErrorCode;\r
+ }\r
+\r
+ return ErrorCode;\r
}\r
\r
/** Issues a SCSI Device Read Capacity command to the attached device, to determine the capacity of the\r
* \param[in] LUNIndex Index of the LUN inside the device the command is being addressed to\r
* \param[out] CapacityPtr Device capacity structure where the capacity data is to be stored\r
*\r
- * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum\r
+ * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum, or MASS_STORE_SCSI_COMMAND_FAILED if the SCSI command fails\r
*/\r
uint8_t MassStore_ReadCapacity(const uint8_t LUNIndex, SCSI_Capacity_t* const CapacityPtr)\r
{\r
- uint8_t ReturnCode = PIPE_RWSTREAM_NoError;\r
+ uint8_t ErrorCode = PIPE_RWSTREAM_NoError;\r
\r
/* Create a CBW with a SCSI command to issue READ CAPACITY command */\r
- SCSICommandBlock = (CommandBlockWrapper_t)\r
+ CommandBlockWrapper_t SCSICommandBlock = (CommandBlockWrapper_t)\r
{\r
- .Header =\r
- {\r
- .Signature = CBW_SIGNATURE,\r
- .Tag = MassStore_Tag,\r
- .DataTransferLength = sizeof(SCSI_Capacity_t),\r
- .Flags = COMMAND_DIRECTION_DATA_IN,\r
- .LUN = LUNIndex,\r
- .SCSICommandLength = 10\r
- },\r
- \r
- .SCSICommandData =\r
+ .Signature = CBW_SIGNATURE,\r
+ .DataTransferLength = sizeof(SCSI_Capacity_t),\r
+ .Flags = COMMAND_DIRECTION_DATA_IN,\r
+ .LUN = LUNIndex,\r
+ .SCSICommandLength = 10,\r
+ .SCSICommandData =\r
{\r
SCSI_CMD_READ_CAPACITY_10,\r
0x00, // Reserved\r
}\r
};\r
\r
- /* Send SCSI command to the attached device */\r
- MassStore_SendCommand();\r
+ CommandStatusWrapper_t SCSICommandStatus;\r
\r
- /* Wait until data received from the device */\r
- if ((ReturnCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError)\r
+ /* Send the command and any data to the attached device */\r
+ if ((ErrorCode = MassStore_SendCommand(&SCSICommandBlock, CapacityPtr)) != PIPE_RWSTREAM_NoError)\r
{\r
Pipe_Freeze();\r
- return ReturnCode;\r
- }\r
-\r
- /* Read the returned capacity data into the buffer */\r
- if ((ReturnCode = MassStore_SendReceiveData(CapacityPtr)) != PIPE_RWSTREAM_NoError)\r
- {\r
- Pipe_Freeze();\r
- return ReturnCode;\r
+ return ErrorCode;\r
}\r
\r
/* Endian-correct the read data */\r
CapacityPtr->Blocks = SwapEndian_32(CapacityPtr->Blocks);\r
CapacityPtr->BlockSize = SwapEndian_32(CapacityPtr->BlockSize);\r
\r
- /* Read in the returned CSW from the device */\r
- if ((ReturnCode = MassStore_GetReturnedStatus()) != PIPE_RWSTREAM_NoError)\r
+ /* Retrieve status information from the attached device */\r
+ if ((ErrorCode = MassStore_GetReturnedStatus(&SCSICommandStatus)) != PIPE_RWSTREAM_NoError)\r
{\r
Pipe_Freeze();\r
- return ReturnCode;\r
+ return ErrorCode;\r
}\r
- \r
- return PIPE_RWSTREAM_NoError;\r
+\r
+ return ErrorCode;\r
}\r
\r
/** Issues a SCSI Device Prevent/Allow Medium Removal command to the attached device, to lock the physical media from\r
* \param[in] LUNIndex Index of the LUN inside the device the command is being addressed to\r
* \param[in] PreventRemoval Whether or not the LUN media should be locked to prevent removal or not\r
*\r
- * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum\r
+ * \return A value from the Pipe_Stream_RW_ErrorCodes_t enum, or MASS_STORE_SCSI_COMMAND_FAILED if the SCSI command fails\r
*/\r
uint8_t MassStore_PreventAllowMediumRemoval(const uint8_t LUNIndex, const bool PreventRemoval)\r
{\r
- uint8_t ReturnCode = PIPE_RWSTREAM_NoError;\r
+ uint8_t ErrorCode = PIPE_RWSTREAM_NoError;\r
\r
/* Create a CBW with a SCSI command to issue PREVENT ALLOW MEDIUM REMOVAL command */\r
- SCSICommandBlock = (CommandBlockWrapper_t)\r
+ CommandBlockWrapper_t SCSICommandBlock = (CommandBlockWrapper_t)\r
{\r
- .Header =\r
- {\r
- .Signature = CBW_SIGNATURE,\r
- .Tag = MassStore_Tag,\r
- .DataTransferLength = 0,\r
- .Flags = COMMAND_DIRECTION_DATA_OUT,\r
- .LUN = LUNIndex,\r
- .SCSICommandLength = 6\r
- },\r
- \r
- .SCSICommandData =\r
+ .Signature = CBW_SIGNATURE,\r
+ .DataTransferLength = 0,\r
+ .Flags = COMMAND_DIRECTION_DATA_OUT,\r
+ .LUN = LUNIndex,\r
+ .SCSICommandLength = 6,\r
+ .SCSICommandData =\r
{\r
SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,\r
0x00, // Reserved\r
}\r
};\r
\r
- /* Send SCSI command to the attached device */\r
- MassStore_SendCommand();\r
+ CommandStatusWrapper_t SCSICommandStatus;\r
\r
- /* Read in the returned CSW from the device */\r
- if ((ReturnCode = MassStore_GetReturnedStatus()))\r
+ /* Send the command and any data to the attached device */\r
+ if ((ErrorCode = MassStore_SendCommand(&SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)\r
{\r
Pipe_Freeze();\r
- return ReturnCode;\r
+ return ErrorCode;\r
}\r
\r
- return PIPE_RWSTREAM_NoError;\r
+ /* Retrieve status information from the attached device */\r
+ if ((ErrorCode = MassStore_GetReturnedStatus(&SCSICommandStatus)) != PIPE_RWSTREAM_NoError)\r
+ {\r
+ Pipe_Freeze();\r
+ return ErrorCode;\r
+ }\r
+\r
+ return ErrorCode;\r
}\r
\r
/* Macros: */\r
/** Class specific request to reset the Mass Storage interface of the attached device */\r
- #define REQ_MassStorageReset 0xFF\r
+ #define REQ_MassStorageReset 0xFF\r
\r
/** Class specific request to retrieve the maximum Logical Unit Number (LUN) index of the attached device */\r
- #define REQ_GetMaxLUN 0xFE\r
+ #define REQ_GetMaxLUN 0xFE\r
\r
/** Command Block Wrapper signature byte, for verification of valid CBW blocks */\r
- #define CBW_SIGNATURE 0x43425355UL\r
+ #define CBW_SIGNATURE 0x43425355UL\r
\r
/** Command Static Wrapper signature byte, for verification of valid CSW blocks */\r
- #define CSW_SIGNATURE 0x53425355UL\r
+ #define CSW_SIGNATURE 0x53425355UL\r
\r
/** Data direction mask for the Flags field of a CBW, indicating Host-to-Device transfer direction */\r
- #define COMMAND_DIRECTION_DATA_OUT (0 << 7)\r
+ #define COMMAND_DIRECTION_DATA_OUT (0 << 7)\r
\r
/** Data direction mask for the Flags field of a CBW, indicating Device-to-Host transfer direction */\r
- #define COMMAND_DIRECTION_DATA_IN (1 << 7)\r
+ #define COMMAND_DIRECTION_DATA_IN (1 << 7)\r
\r
/** Timeout period between the issuing of a CBW to a device, and the reception of the first packet */\r
- #define COMMAND_DATA_TIMEOUT_MS 2000\r
+ #define COMMAND_DATA_TIMEOUT_MS 2000\r
\r
/** Pipe number of the Mass Storage data IN pipe */\r
- #define MASS_STORE_DATA_IN_PIPE 1\r
+ #define MASS_STORE_DATA_IN_PIPE 1\r
\r
/** Pipe number of the Mass Storage data OUT pipe */\r
- #define MASS_STORE_DATA_OUT_PIPE 2\r
+ #define MASS_STORE_DATA_OUT_PIPE 2\r
+ \r
+ /** Additional error code for Mass Storage functions when a device returns a logical command failure */\r
+ #define MASS_STORE_SCSI_COMMAND_FAILED 0xC0\r
\r
/* Type defines: */\r
/** Type define for a Mass Storage class Command Block Wrapper, used to wrap SCSI\r
*/\r
typedef struct\r
{\r
- struct\r
- {\r
- uint32_t Signature; /**< Command block signature, always equal to CBW_SIGNATURE */\r
- uint32_t Tag; /**< Current CBW tag, to positively associate a CBW with a CSW */\r
- uint32_t DataTransferLength; /**< Length of data to transfer, following the CBW */\r
- uint8_t Flags; /**< Block flags, equal to one of the COMMAND_DIRECTION_DATA_* macros */\r
- uint8_t LUN; /**< Logical Unit Number the CBW is addressed to in the device */\r
- uint8_t SCSICommandLength; /**< Length of the SCSI command in the CBW */\r
- } Header;\r
- \r
- uint8_t SCSICommandData[16]; /**< SCSI command to issue to the device */\r
+ uint32_t Signature; /**< Command block signature, always equal to CBW_SIGNATURE */\r
+ uint32_t Tag; /**< Current CBW tag, to positively associate a CBW with a CSW (filled automatically) */\r
+ uint32_t DataTransferLength; /**< Length of data to transfer, following the CBW */\r
+ uint8_t Flags; /**< Block flags, equal to one of the COMMAND_DIRECTION_DATA_* macros */\r
+ uint8_t LUN; /**< Logical Unit Number the CBW is addressed to in the device */\r
+ uint8_t SCSICommandLength; /**< Length of the SCSI command in the CBW */\r
+ uint8_t SCSICommandData[16]; /**< SCSI command to issue to the device */\r
} CommandBlockWrapper_t;\r
\r
/** Type define for a Mass Storage class Command Status Wrapper, used to wrap SCSI\r
Command_Fail = 1, /**< Command failed to complete successfully */\r
Phase_Error = 2 /**< Phase error while processing the issued command */\r
};\r
- \r
- /* External Variables: */\r
- extern CommandStatusWrapper_t SCSICommandStatus;\r
- \r
+ \r
/* Function Prototypes: */\r
#if defined(INCLUDE_FROM_MASSSTORE_COMMANDS_C)\r
- static uint8_t MassStore_SendCommand(void);\r
+ static uint8_t MassStore_SendCommand(CommandBlockWrapper_t* SCSICommandBlock, void* BufferPtr);\r
static uint8_t MassStore_WaitForDataReceived(void);\r
- static uint8_t MassStore_SendReceiveData(void* BufferPtr) ATTR_NON_NULL_PTR_ARG(1);\r
- static uint8_t MassStore_GetReturnedStatus(void);\r
+ static uint8_t MassStore_SendReceiveData(CommandBlockWrapper_t* SCSICommandBlock, void* BufferPtr) ATTR_NON_NULL_PTR_ARG(1);\r
+ static uint8_t MassStore_GetReturnedStatus(CommandStatusWrapper_t* SCSICommandStatus) ATTR_NON_NULL_PTR_ARG(1);\r
#endif\r
\r
uint8_t MassStore_MassStorageReset(void);\r
uint8_t MassStore_GetMaxLUN(uint8_t* const MaxLUNIndex);\r
- uint8_t MassStore_RequestSense(const uint8_t LUNIndex, const SCSI_Request_Sense_Response_t* const SensePtr)\r
+ uint8_t MassStore_RequestSense(const uint8_t LUNIndex, SCSI_Request_Sense_Response_t* const SensePtr)\r
ATTR_NON_NULL_PTR_ARG(2);\r
- uint8_t MassStore_Inquiry(const uint8_t LUNIndex, const SCSI_Inquiry_Response_t* const InquiryPtr)\r
+ uint8_t MassStore_Inquiry(const uint8_t LUNIndex, SCSI_Inquiry_Response_t* const InquiryPtr)\r
ATTR_NON_NULL_PTR_ARG(2);\r
uint8_t MassStore_ReadDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockAddress,\r
const uint8_t Blocks, const uint16_t BlockSize, void* BufferPtr) ATTR_NON_NULL_PTR_ARG(5);\r
/* Send the request, display error and wait for device detach if request fails */\r
if ((ErrorCode = MassStore_GetMaxLUN(&MassStore_MaxLUNIndex)) != HOST_SENDCONTROL_Successful)\r
{ \r
- ShowDiskReadError(PSTR("Get Max LUN"), false, ErrorCode);\r
+ ShowDiskReadError(PSTR("Get Max LUN"), ErrorCode);\r
\r
USB_HostState = HOST_STATE_WaitForDeviceRemoval;\r
break;\r
/* Reset the Mass Storage device interface, ready for use */\r
if ((ErrorCode = MassStore_MassStorageReset()) != HOST_SENDCONTROL_Successful)\r
{\r
- ShowDiskReadError(PSTR("Mass Storage Reset"), false, ErrorCode);\r
+ ShowDiskReadError(PSTR("Mass Storage Reset"), ErrorCode);\r
\r
USB_HostState = HOST_STATE_WaitForDeviceRemoval;\r
break;\r
/* Get sense data from the device - many devices will not accept any other commands until the sense data\r
* is read - both on start-up and after a failed command */\r
SCSI_Request_Sense_Response_t SenseData;\r
- if (((ErrorCode = MassStore_RequestSense(0, &SenseData)) != 0) || (SCSICommandStatus.Status != Command_Pass))\r
+ if ((ErrorCode = MassStore_RequestSense(0, &SenseData)) != 0)\r
{\r
- ShowDiskReadError(PSTR("Request Sense"), (SCSICommandStatus.Status != Command_Pass), ErrorCode);\r
+ ShowDiskReadError(PSTR("Request Sense"), ErrorCode);\r
+ USB_HostState = HOST_STATE_WaitForDeviceRemoval;\r
break;\r
}\r
\r
/* Set the prevent removal flag for the device, allowing it to be accessed */\r
- if (((ErrorCode = MassStore_PreventAllowMediumRemoval(0, true)) != 0) || (SCSICommandStatus.Status != Command_Pass))\r
+ if ((ErrorCode = MassStore_PreventAllowMediumRemoval(0, true)) != 0)\r
{\r
- ShowDiskReadError(PSTR("Prevent/Allow Medium Removal"), (SCSICommandStatus.Status != Command_Pass), ErrorCode);\r
+ ShowDiskReadError(PSTR("Prevent/Allow Medium Removal"), ErrorCode);\r
\r
USB_HostState = HOST_STATE_WaitForDeviceRemoval;\r
break;\r
\r
/* Get inquiry data from the device */\r
SCSI_Inquiry_Response_t InquiryData;\r
- if (((ErrorCode = MassStore_Inquiry(0, &InquiryData)) != 0) || (SCSICommandStatus.Status != Command_Pass))\r
+ if ((ErrorCode = MassStore_Inquiry(0, &InquiryData)) != 0)\r
{\r
- ShowDiskReadError(PSTR("Inquiry"), (SCSICommandStatus.Status != Command_Pass), ErrorCode);\r
+ ShowDiskReadError(PSTR("Inquiry"), ErrorCode);\r
\r
USB_HostState = HOST_STATE_WaitForDeviceRemoval;\r
break;\r
/* Wait until disk ready */\r
puts_P(PSTR("Waiting until ready.."));\r
\r
- do\r
+ for (;;)\r
{\r
Serial_TxByte('.');\r
- \r
+\r
/* Abort if device removed */\r
if (USB_HostState == HOST_STATE_Unattached)\r
break;\r
\r
- if ((ErrorCode = MassStore_TestUnitReady(0)) != PIPE_RWSTREAM_NoError)\r
+ /* Check to see if the attached device is ready for new commands */\r
+ ErrorCode = MassStore_TestUnitReady(0);\r
+ \r
+ /* If attached device is ready, abort the loop */\r
+ if (!(ErrorCode))\r
+ break;\r
+\r
+ /* If an error othe than a logical command failure (indicating device busy) returned, abort */\r
+ if (ErrorCode != MASS_STORE_SCSI_COMMAND_FAILED)\r
{\r
- ShowDiskReadError(PSTR("Test Unit Ready"), false, ErrorCode);\r
+ ShowDiskReadError(PSTR("Test Unit Ready"), ErrorCode);\r
\r
USB_HostState = HOST_STATE_WaitForDeviceRemoval;\r
break;\r
}\r
}\r
- while (SCSICommandStatus.Status != Command_Pass);\r
\r
puts_P(PSTR("\r\nRetrieving Capacity... "));\r
\r
SCSI_Capacity_t DiskCapacity;\r
\r
/* Retrieve disk capacity */\r
- if (((ErrorCode = MassStore_ReadCapacity(0, &DiskCapacity)) != 0) || (SCSICommandStatus.Status != Command_Pass))\r
+ if ((ErrorCode = MassStore_ReadCapacity(0, &DiskCapacity)) != 0)\r
{\r
- ShowDiskReadError(PSTR("Read Capacity"), (SCSICommandStatus.Status != Command_Pass), ErrorCode);\r
+ ShowDiskReadError(PSTR("Read Capacity"), ErrorCode);\r
\r
USB_HostState = HOST_STATE_WaitForDeviceRemoval;\r
break;\r
uint8_t BlockBuffer[DiskCapacity.BlockSize];\r
\r
/* Read in the first 512 byte block from the device */\r
- if (((ErrorCode = MassStore_ReadDeviceBlock(0, 0x00000000, 1, DiskCapacity.BlockSize, BlockBuffer)) != 0) ||\r
- (SCSICommandStatus.Status != Command_Pass))\r
+ if ((ErrorCode = MassStore_ReadDeviceBlock(0, 0x00000000, 1, DiskCapacity.BlockSize, BlockBuffer)) != 0)\r
{\r
- ShowDiskReadError(PSTR("Read Device Block"), (SCSICommandStatus.Status != Command_Pass), ErrorCode);\r
+ ShowDiskReadError(PSTR("Read Device Block"), ErrorCode);\r
\r
USB_HostState = HOST_STATE_WaitForDeviceRemoval;\r
break;\r
if (USB_HostState == HOST_STATE_Unattached)\r
break;\r
}\r
+\r
+ /* Abort if device removed */\r
+ if (USB_HostState == HOST_STATE_Unattached)\r
+ break;\r
\r
/* Print out the entire disk contents in ASCII format */\r
- for (uint32_t CurrBlock = 0; CurrBlock < DiskCapacity.Blocks; CurrBlock++)\r
+ for (uint32_t CurrBlockAddress = 0; CurrBlockAddress < DiskCapacity.Blocks; CurrBlockAddress++)\r
{\r
/* Read in the next block of data from the device */\r
- if (((ErrorCode = MassStore_ReadDeviceBlock(0, CurrBlock, 1, DiskCapacity.BlockSize, BlockBuffer)) != 0) ||\r
- (SCSICommandStatus.Status != Command_Pass))\r
+ if ((ErrorCode = MassStore_ReadDeviceBlock(0, CurrBlockAddress, 1, DiskCapacity.BlockSize, BlockBuffer)) != 0)\r
{\r
- ShowDiskReadError(PSTR("Read Device Block"), (SCSICommandStatus.Status != Command_Pass), ErrorCode);\r
+ ShowDiskReadError(PSTR("Read Device Block"), ErrorCode);\r
\r
USB_HostState = HOST_STATE_WaitForDeviceRemoval;\r
break;\r
* printing error codes to the serial port and waiting until the device is removed before\r
* continuing.\r
*\r
- * \param[in] CommandString ASCII string located in PROGMEM space indicating what operation failed\r
- * \param[in] FailedAtSCSILayer Indicates if the command failed at the (logical) SCSI layer or at the physical USB layer\r
- * \param[in] ErrorCode Error code of the function which failed to complete successfully\r
+ * \param[in] CommandString ASCII string located in PROGMEM space indicating what operation failed\r
+ * \param[in] ErrorCode Error code of the function which failed to complete successfully\r
*/\r
-void ShowDiskReadError(char* CommandString, bool FailedAtSCSILayer, uint8_t ErrorCode)\r
+void ShowDiskReadError(char* CommandString, uint8_t ErrorCode)\r
{\r
- if (FailedAtSCSILayer)\r
+ if (ErrorCode == MASS_STORE_SCSI_COMMAND_FAILED)\r
{\r
/* Display the error code */\r
printf_P(PSTR(ESC_FG_RED "SCSI command error (%S).\r\n"), CommandString);\r
- printf_P(PSTR(" -- Status Code: %d" ESC_FG_WHITE), ErrorCode);\r
}\r
else\r
{\r