Device mode class driver callbacks are now fired before the control request status...
[pub/USBasp.git] / Demos / Host / LowLevel / MassStorageHost / Lib / MassStoreCommands.c
index 7ee7de1..be92d69 100644 (file)
@@ -1,21 +1,21 @@
 /*\r
              LUFA Library\r
-     Copyright (C) Dean Camera, 2009.\r
+     Copyright (C) Dean Camera, 2010.\r
               \r
   dean [at] fourwalledcubicle [dot] com\r
       www.fourwalledcubicle.com\r
 */\r
 \r
 /*\r
-  Copyright 2009  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
-\r
-  Permission to use, copy, modify, and distribute this software\r
-  and its documentation for any purpose and without fee is hereby\r
-  granted, provided that the above copyright notice appear in all\r
-  copies and that both that the copyright notice and this\r
-  permission notice and warranty disclaimer appear in supporting\r
-  documentation, and that the name of the author not be used in\r
-  advertising or publicity pertaining to distribution of the\r
+  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
+\r
+  Permission to use, copy, modify, distribute, and sell this \r
+  software and its documentation for any purpose is hereby granted\r
+  without fee, provided that the above copyright notice appear in \r
+  all copies and that both that the copyright notice and this\r
+  permission notice and warranty disclaimer appear in supporting \r
+  documentation, and that the name of the author not be used in \r
+  advertising or publicity pertaining to distribution of the \r
   software without specific, written prior permission.\r
 \r
   The author disclaim all warranties with regard to this\r
 #define  INCLUDE_FROM_MASSSTORE_COMMANDS_C\r
 #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
@@ -84,19 +79,27 @@ static uint8_t MassStore_SendCommand(void)
        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
@@ -154,7 +157,7 @@ static uint8_t MassStore_WaitForDataReceived(void)
                }\r
                  \r
                /* Check to see if the device was disconnected, if so exit function */\r
-               if (!(USB_IsConnected))\r
+               if (USB_HostState == HOST_STATE_Unattached)\r
                  return PIPE_RWSTREAM_DeviceDisconnected;\r
        };\r
        \r
@@ -170,18 +173,23 @@ static uint8_t MassStore_WaitForDataReceived(void)
 /** 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
@@ -206,7 +214,11 @@ static uint8_t MassStore_SendReceiveData(void* BufferPtr)
                /* Acknowledge the packet */\r
                Pipe_ClearOUT();\r
                \r
-               while (!(Pipe_IsOUTReady()));\r
+               while (!(Pipe_IsOUTReady()))\r
+               {\r
+                       if (USB_HostState == HOST_STATE_Unattached)\r
+                         return PIPE_RWSTREAM_DeviceDisconnected;\r
+               }\r
        }\r
        \r
        /* Freeze used pipe after use */\r
@@ -217,13 +229,15 @@ static uint8_t MassStore_SendReceiveData(void* BufferPtr)
 \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
-       /* If an error in the command ocurred, abort */\r
+       /* If an error in the command occurred, abort */\r
        if ((ErrorCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError)\r
          return ErrorCode;\r
 \r
@@ -232,7 +246,7 @@ static uint8_t MassStore_GetReturnedStatus(void)
        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
@@ -241,13 +255,17 @@ static uint8_t MassStore_GetReturnedStatus(void)
        /* 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
@@ -269,13 +287,17 @@ uint8_t MassStore_MassStorageReset(void)
 /** Issues a Mass Storage class specific request to determine the index of the highest numbered Logical\r
  *  Unit in the attached device.\r
  *\r
+ *  \note Some devices do not support this request, and will STALL it when issued. To get around this,\r
+ *        on unsupported devices the max LUN index will be reported as zero and no error will be returned\r
+ *        if the device STALLs the request.\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
-       uint8_t ErrorCode;\r
+       uint8_t ErrorCode = HOST_SENDCONTROL_Successful;\r
 \r
        USB_ControlRequest = (USB_Request_Header_t)\r
                {\r
@@ -295,7 +317,10 @@ uint8_t MassStore_GetMaxLUN(uint8_t* const MaxLUNIndex)
                Pipe_ClearStall();\r
        \r
                /* Some faulty Mass Storage devices don't implement the GET_MAX_LUN request, so assume a single LUN */\r
-               *MaxLUNIndex = 0;       \r
+               *MaxLUNIndex = 0;\r
+               \r
+               /* Clear the error, and pretend the request executed correctly if the device STALLed it */\r
+               ErrorCode = HOST_SENDCONTROL_Successful;\r
        }\r
        \r
        return ErrorCode;\r
@@ -307,26 +332,21 @@ uint8_t MassStore_GetMaxLUN(uint8_t* const MaxLUNIndex)
  *  \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
@@ -337,31 +357,23 @@ uint8_t MassStore_Inquiry(const uint8_t LUNIndex, const SCSI_Inquiry_Response_t*
                                }\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
@@ -370,25 +382,20 @@ uint8_t MassStore_Inquiry(const uint8_t LUNIndex, const SCSI_Inquiry_Response_t*
  *  \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
@@ -400,31 +407,23 @@ uint8_t MassStore_RequestSense(const uint8_t LUNIndex, const SCSI_Request_Sense_
                                }\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
@@ -436,27 +435,22 @@ uint8_t MassStore_RequestSense(const uint8_t LUNIndex, const SCSI_Request_Sense_
  *  \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
@@ -471,31 +465,23 @@ uint8_t MassStore_ReadDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockAd
                                }\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
@@ -507,27 +493,22 @@ uint8_t MassStore_ReadDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockAd
  *  \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
@@ -542,24 +523,23 @@ uint8_t MassStore_WriteDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockA
                                }\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
@@ -567,26 +547,21 @@ uint8_t MassStore_WriteDeviceBlock(const uint8_t LUNIndex, const uint32_t BlockA
  *\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
@@ -597,17 +572,23 @@ uint8_t MassStore_TestUnitReady(const uint8_t LUNIndex)
                                }\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
@@ -616,26 +597,21 @@ uint8_t MassStore_TestUnitReady(const uint8_t LUNIndex)
  *  \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
@@ -650,35 +626,27 @@ uint8_t MassStore_ReadCapacity(const uint8_t LUNIndex, SCSI_Capacity_t* const Ca
                                }\r
                };\r
        \r
-       /* Send SCSI command to the attached device */\r
-       MassStore_SendCommand();\r
-\r
-       /* Wait until data received from the device */\r
-       if ((ReturnCode = MassStore_WaitForDataReceived()) != PIPE_RWSTREAM_NoError)\r
-       {\r
-               Pipe_Freeze();\r
-               return ReturnCode;\r
-       }\r
+       CommandStatusWrapper_t SCSICommandStatus;\r
 \r
-       /* Read the returned capacity data into the buffer */\r
-       if ((ReturnCode = MassStore_SendReceiveData(CapacityPtr)) != 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
+               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
@@ -688,26 +656,21 @@ uint8_t MassStore_ReadCapacity(const uint8_t LUNIndex, SCSI_Capacity_t* const Ca
  *  \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
@@ -718,15 +681,21 @@ uint8_t MassStore_PreventAllowMediumRemoval(const uint8_t LUNIndex, const bool P
                                }\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