Added ability to write protect Mass Storage disk write operations from the host OS.
authorDean Camera <dean@fourwalledcubicle.com>
Fri, 26 Nov 2010 04:16:47 +0000 (04:16 +0000)
committerDean Camera <dean@fourwalledcubicle.com>
Fri, 26 Nov 2010 04:16:47 +0000 (04:16 +0000)
20 files changed:
Demos/Device/ClassDriver/MassStorage/Lib/SCSI.c
Demos/Device/ClassDriver/MassStorage/Lib/SCSI.h
Demos/Device/ClassDriver/MassStorage/MassStorage.h
Demos/Device/ClassDriver/MassStorageKeyboard/Lib/DataflashManager.h
Demos/Device/ClassDriver/MassStorageKeyboard/Lib/SCSI.c
Demos/Device/ClassDriver/MassStorageKeyboard/Lib/SCSI.h
Demos/Device/ClassDriver/MassStorageKeyboard/MassStorageKeyboard.h
Demos/Device/LowLevel/MassStorage/Lib/SCSI.c
Demos/Device/LowLevel/MassStorage/Lib/SCSI.h
Demos/Device/LowLevel/MassStorage/MassStorage.h
LUFA/ManPages/ChangeLog.txt
Projects/Incomplete/StandaloneProgrammer/Lib/DataflashManager.h
Projects/Incomplete/StandaloneProgrammer/Lib/SCSI.c
Projects/Incomplete/StandaloneProgrammer/Lib/SCSI.h
Projects/TempDataLogger/Lib/SCSI.c
Projects/TempDataLogger/Lib/SCSI.h
Projects/TempDataLogger/TempDataLogger.h
Projects/Webserver/Lib/DataflashManager.h
Projects/Webserver/Lib/SCSI.c
Projects/Webserver/Lib/SCSI.h

index 5e0a82b..ac6c9e7 100644 (file)
@@ -113,6 +113,9 @@ bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
                case SCSI_CMD_READ_10:
                        CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ);
                        break;
+               case SCSI_CMD_MODE_SENSE_6:
+                       CommandSuccess = SCSI_Command_ModeSense_6(MSInterfaceInfo);
+                       break;
                case SCSI_CMD_TEST_UNIT_READY:
                case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
                case SCSI_CMD_VERIFY_10:
@@ -281,6 +284,17 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
        uint32_t BlockAddress;
        uint16_t TotalBlocks;
 
+       /* Check if the disk is write protected or not */
+       if ((IsDataRead == DATA_WRITE) && DISK_READ_ONLY)
+       {
+               /* Block address is invalid, update SENSE key and return command fail */
+               SCSI_SET_SENSE(SCSI_SENSE_KEY_DATA_PROTECT,
+                              SCSI_ASENSE_WRITE_PROTECTED,
+                              SCSI_ASENSEQ_NO_QUALIFIER);
+
+               return false;           
+       }
+
        /* Load in the 32-bit block address (SCSI uses big-endian, so have to reverse the byte order) */
        BlockAddress = SwapEndian_32(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]);
 
@@ -302,7 +316,7 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
        /* Adjust the given block address to the real media address based on the selected LUN */
        BlockAddress += ((uint32_t)MSInterfaceInfo->State.CommandBlock.LUN * LUN_MEDIA_BLOCKS);
        #endif
-
+       
        /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */
        if (IsDataRead == DATA_READ)
          DataflashManager_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks);
@@ -315,3 +329,24 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
        return true;
 }
 
+/** Command processing for an issued SCSI MODE SENSE (6) command. This command returns various informational pages about
+ *  the SCSI device, as well as the device's Write Protect status.
+ *
+ *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface structure that the command is associated with
+ *
+ *  \return Boolean true if the command completed successfully, false otherwise.
+ */
+static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+       /* Send an empty header response with the Write Protect flag status */
+       Endpoint_Write_Byte(0x00);
+       Endpoint_Write_Byte(0x00);
+       Endpoint_Write_Byte(DISK_READ_ONLY ? 0x80 : 0x00);
+       Endpoint_Write_Byte(0x00);
+       Endpoint_ClearIN();
+
+       /* Update the bytes transferred counter and succeed the command */
+       MSInterfaceInfo->State.CommandBlock.DataTransferLength -= 4;
+
+       return true;
+}
index e8f5eb6..6f2e19d 100644 (file)
@@ -81,6 +81,7 @@
                        static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
                        static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
                                                              const bool IsDataRead);
+                       static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
                #endif
 
 #endif
index f7ac363..63a8642 100644 (file)
@@ -73,6 +73,9 @@
 
                /** Blocks in each LUN, calculated from the total capacity divided by the total number of Logical Units in the device. */
                #define LUN_MEDIA_BLOCKS         (VIRTUAL_MEMORY_BLOCKS / TOTAL_LUNS)
+               
+               /** Indicates if the disk is write protected or not. */
+               #define DISK_READ_ONLY            false
 
        /* Function Prototypes: */
                void SetupHardware(void);
index 3db19da..d7f8605 100644 (file)
                /** Total number of blocks of the virtual memory for reporting to the host as the device's total capacity. */
                #define VIRTUAL_MEMORY_BLOCKS              (VIRTUAL_MEMORY_BYTES / VIRTUAL_MEMORY_BLOCK_SIZE)
 
-               /** Total number of logical drives within the device - must be non-zero. */
-               #define TOTAL_LUNS                          1
-
-               /** Blocks in each LUN, calculated from the total capacity divided by the total number of Logical Units in the device. */
-               #define LUN_MEDIA_BLOCKS                   (VIRTUAL_MEMORY_BLOCKS / TOTAL_LUNS)
-
        /* Function Prototypes: */
                void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
                                                  const uint32_t BlockAddress,
index 5e0a82b..5d0adf9 100644 (file)
@@ -113,6 +113,9 @@ bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
                case SCSI_CMD_READ_10:
                        CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ);
                        break;
+               case SCSI_CMD_MODE_SENSE_6:
+                       CommandSuccess = SCSI_Command_ModeSense_6(MSInterfaceInfo);
+                       break;
                case SCSI_CMD_TEST_UNIT_READY:
                case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
                case SCSI_CMD_VERIFY_10:
@@ -281,6 +284,17 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
        uint32_t BlockAddress;
        uint16_t TotalBlocks;
 
+       /* Check if the disk is write protected or not */
+       if ((IsDataRead == DATA_WRITE) && DISK_READ_ONLY)
+       {
+               /* Block address is invalid, update SENSE key and return command fail */
+               SCSI_SET_SENSE(SCSI_SENSE_KEY_DATA_PROTECT,
+                              SCSI_ASENSE_WRITE_PROTECTED,
+                              SCSI_ASENSEQ_NO_QUALIFIER);
+
+               return false;           
+       }
+
        /* Load in the 32-bit block address (SCSI uses big-endian, so have to reverse the byte order) */
        BlockAddress = SwapEndian_32(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]);
 
@@ -315,3 +329,24 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
        return true;
 }
 
+/** Command processing for an issued SCSI MODE SENSE (6) command. This command returns various informational pages about
+ *  the SCSI device, as well as the device's Write Protect status.
+ *
+ *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface structure that the command is associated with
+ *
+ *  \return Boolean true if the command completed successfully, false otherwise.
+ */
+static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+       /* Send an empty header response with the Write Protect flag status */
+       Endpoint_Write_Byte(0x00);
+       Endpoint_Write_Byte(0x00);
+       Endpoint_Write_Byte(DISK_READ_ONLY ? 0x80 : 0x00);
+       Endpoint_Write_Byte(0x00);
+       Endpoint_ClearIN();
+
+       /* Update the bytes transferred counter and succeed the command */
+       MSInterfaceInfo->State.CommandBlock.DataTransferLength -= 4;
+
+       return true;
+}
index bab018c..9a5bd80 100644 (file)
@@ -81,6 +81,7 @@
                        static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
                        static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
                                                              const bool IsDataRead);
+                       static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
                #endif
 
 #endif
index e07157a..110953c 100644 (file)
                /** LED mask for the library LED driver, to indicate that the USB interface is busy. */
                #define LEDMASK_USB_BUSY         LEDS_LED2
 
+               /** Total number of logical drives within the device - must be non-zero. */
+               #define TOTAL_LUNS               1
+
+               /** Blocks in each LUN, calculated from the total capacity divided by the total number of Logical Units in the device. */
+               #define LUN_MEDIA_BLOCKS         (VIRTUAL_MEMORY_BLOCKS / TOTAL_LUNS)
+
+               /** Indicates if the disk is write protected or not. */
+               #define DISK_READ_ONLY           false
+               
        /* Function Prototypes: */
                void SetupHardware(void);
 
index 598c689..63f1ec3 100644 (file)
@@ -111,6 +111,9 @@ bool SCSI_DecodeSCSICommand(void)
                case SCSI_CMD_READ_10:
                        CommandSuccess = SCSI_Command_ReadWrite_10(DATA_READ);
                        break;
+               case SCSI_CMD_MODE_SENSE_6:
+                       CommandSuccess = SCSI_Command_ModeSense_6();
+                       break;
                case SCSI_CMD_TEST_UNIT_READY:
                case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
                case SCSI_CMD_VERIFY_10:
@@ -278,9 +281,23 @@ static bool SCSI_Command_Send_Diagnostic(void)
  */
 static bool SCSI_Command_ReadWrite_10(const bool IsDataRead)
 {
-       uint32_t BlockAddress = SwapEndian_32(*(uint32_t*)&CommandBlock.SCSICommandData[2]);
-       uint16_t TotalBlocks  = SwapEndian_16(*(uint16_t*)&CommandBlock.SCSICommandData[7]);
+       uint32_t BlockAddress;
+       uint16_t TotalBlocks;
+
+       /* Check if the disk is write protected or not */
+       if ((IsDataRead == DATA_WRITE) && DISK_READ_ONLY)
+       {
+               /* Block address is invalid, update SENSE key and return command fail */
+               SCSI_SET_SENSE(SCSI_SENSE_KEY_DATA_PROTECT,
+                              SCSI_ASENSE_WRITE_PROTECTED,
+                              SCSI_ASENSEQ_NO_QUALIFIER);
 
+               return false;           
+       }
+
+       BlockAddress = SwapEndian_32(*(uint32_t*)&CommandBlock.SCSICommandData[2]);
+       TotalBlocks  = SwapEndian_16(*(uint16_t*)&CommandBlock.SCSICommandData[7]);
+       
        /* Check if the block address is outside the maximum allowable value for the LUN */
        if (BlockAddress >= LUN_MEDIA_BLOCKS)
        {
@@ -309,3 +326,22 @@ static bool SCSI_Command_ReadWrite_10(const bool IsDataRead)
        return true;
 }
 
+/** Command processing for an issued SCSI MODE SENSE (6) command. This command returns various informational pages about
+ *  the SCSI device, as well as the device's Write Protect status.
+ *
+ *  \return Boolean true if the command completed successfully, false otherwise.
+ */
+static bool SCSI_Command_ModeSense_6(void)
+{
+       /* Send an empty header response with the Write Protect flag status */
+       Endpoint_Write_Byte(0x00);
+       Endpoint_Write_Byte(0x00);
+       Endpoint_Write_Byte(DISK_READ_ONLY ? 0x80 : 0x00);
+       Endpoint_Write_Byte(0x00);
+       Endpoint_ClearIN();
+
+       /* Update the bytes transferred counter and succeed the command */
+       CommandBlock.DataTransferLength -= 4;
+
+       return true;
+}
index 962a2ac..8710db8 100644 (file)
                        static bool SCSI_Command_Read_Capacity_10(void);
                        static bool SCSI_Command_Send_Diagnostic(void);
                        static bool SCSI_Command_ReadWrite_10(const bool IsDataRead);
+                       static bool SCSI_Command_ModeSense_6(void);
                #endif
 
 #endif
index 0baa369..d817075 100644 (file)
@@ -68,6 +68,9 @@
                /** LED mask for the library LED driver, to indicate that the USB interface is busy. */
                #define LEDMASK_USB_BUSY           LEDS_LED2
 
+               /** Indicates if the disk is write protected or not. */
+               #define DISK_READ_ONLY            false
+
        /* Global Variables: */
                extern MS_CommandBlockWrapper_t  CommandBlock;
                extern MS_CommandStatusWrapper_t CommandStatus;
index 402865f..57f8677 100644 (file)
@@ -12,6 +12,7 @@
   *   - None
   *  - Library Applications:
   *   - Added new incomplete MIDIToneGenerator project
+  *   - Added ability to write protect Mass Storage disk write operations from the host OS
   *
   *  <b>Changed:</b>
   *  - Core:
index 9bd59d7..b963fa2 100644 (file)
 
        /* Defines: */
                /** Total number of bytes of the storage medium, comprised of one or more dataflash ICs. */
-               #define VIRTUAL_MEMORY_BYTES                ((uint32_t)DATAFLASH_PAGES * DATAFLASH_PAGE_SIZE * DATAFLASH_TOTALCHIPS)
+               #define VIRTUAL_MEMORY_BYTES        ((uint32_t)DATAFLASH_PAGES * DATAFLASH_PAGE_SIZE * DATAFLASH_TOTALCHIPS)
 
                /** Block size of the device. This is kept at 512 to remain compatible with the OS despite the underlying
                 *  storage media (Dataflash) using a different native block size. Do not change this value.
                 */
-               #define VIRTUAL_MEMORY_BLOCK_SIZE           512
+               #define VIRTUAL_MEMORY_BLOCK_SIZE   512
 
                /** Total number of blocks of the virtual memory for reporting to the host as the device's total capacity. Do not
                 *  change this value; change VIRTUAL_MEMORY_BYTES instead to alter the media size.
                 */
-               #define VIRTUAL_MEMORY_BLOCKS               (VIRTUAL_MEMORY_BYTES / VIRTUAL_MEMORY_BLOCK_SIZE)
+               #define VIRTUAL_MEMORY_BLOCKS       (VIRTUAL_MEMORY_BYTES / VIRTUAL_MEMORY_BLOCK_SIZE)
 
+               /** Indicates if the disk is write protected or not. */
+               #define DISK_READ_ONLY              false
+               
        /* Function Prototypes: */
                #if defined(USB_CAN_BE_DEVICE)
                        void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
index 7b2a8fa..a23e211 100644 (file)
@@ -114,6 +114,9 @@ bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
                case SCSI_CMD_READ_10:
                        CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ);
                        break;
+               case SCSI_CMD_MODE_SENSE_6:
+                       CommandSuccess = SCSI_Command_ModeSense_6(MSInterfaceInfo);
+                       break;
                case SCSI_CMD_TEST_UNIT_READY:
                case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
                case SCSI_CMD_VERIFY_10:
@@ -282,6 +285,17 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
        uint32_t BlockAddress;
        uint16_t TotalBlocks;
 
+       /* Check if the disk is write protected or not */
+       if ((IsDataRead == DATA_WRITE) && DISK_READ_ONLY)
+       {
+               /* Block address is invalid, update SENSE key and return command fail */
+               SCSI_SET_SENSE(SCSI_SENSE_KEY_DATA_PROTECT,
+                              SCSI_ASENSE_WRITE_PROTECTED,
+                              SCSI_ASENSEQ_NO_QUALIFIER);
+
+               return false;           
+       }
+
        /* Load in the 32-bit block address (SCSI uses big-endian, so have to reverse the byte order) */
        BlockAddress = SwapEndian_32(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]);
 
@@ -298,7 +312,7 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
 
                return false;
        }
-
+       
        /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */
        if (IsDataRead == DATA_READ)
          DataflashManager_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks);
@@ -310,5 +324,26 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
 
        return true;
 }
-#endif
 
+/** Command processing for an issued SCSI MODE SENSE (6) command. This command returns various informational pages about
+ *  the SCSI device, as well as the device's Write Protect status.
+ *
+ *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface structure that the command is associated with
+ *
+ *  \return Boolean true if the command completed successfully, false otherwise.
+ */
+static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+       /* Send an empty header response with the Write Protect flag status */
+       Endpoint_Write_Byte(0x00);
+       Endpoint_Write_Byte(0x00);
+       Endpoint_Write_Byte(DISK_READ_ONLY ? 0x80 : 0x00);
+       Endpoint_Write_Byte(0x00);
+       Endpoint_ClearIN();
+
+       /* Update the bytes transferred counter and succeed the command */
+       MSInterfaceInfo->State.CommandBlock.DataTransferLength -= 4;
+
+       return true;
+}
+#endif
\ No newline at end of file
index 36ad66d..34ed852 100644 (file)
@@ -82,6 +82,7 @@
                                static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
                                static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
                                                                                                          const bool IsDataRead);
+                               static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
                        #endif
                #endif
 
index b1e88dc..6a51c74 100644 (file)
@@ -113,6 +113,9 @@ bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
                case SCSI_CMD_READ_10:
                        CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ);
                        break;
+               case SCSI_CMD_MODE_SENSE_6:
+                       CommandSuccess = SCSI_Command_ModeSense_6(MSInterfaceInfo);
+                       break;
                case SCSI_CMD_TEST_UNIT_READY:
                case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
                case SCSI_CMD_VERIFY_10:
@@ -281,6 +284,17 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
        uint32_t BlockAddress;
        uint16_t TotalBlocks;
 
+       /* Check if the disk is write protected or not */
+       if ((IsDataRead == DATA_WRITE) && DISK_READ_ONLY)
+       {
+               /* Block address is invalid, update SENSE key and return command fail */
+               SCSI_SET_SENSE(SCSI_SENSE_KEY_DATA_PROTECT,
+                              SCSI_ASENSE_WRITE_PROTECTED,
+                              SCSI_ASENSEQ_NO_QUALIFIER);
+
+               return false;           
+       }
+
        /* Load in the 32-bit block address (SCSI uses big-endian, so have to reverse the byte order) */
        BlockAddress = SwapEndian_32(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]);
 
@@ -297,7 +311,7 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
 
                return false;
        }
-
+       
        /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */
        if (IsDataRead == DATA_READ)
          DataflashManager_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks);
@@ -310,3 +324,24 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
        return true;
 }
 
+/** Command processing for an issued SCSI MODE SENSE (6) command. This command returns various informational pages about
+ *  the SCSI device, as well as the device's Write Protect status.
+ *
+ *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface structure that the command is associated with
+ *
+ *  \return Boolean true if the command completed successfully, false otherwise.
+ */
+static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+       /* Send an empty header response with the Write Protect flag status */
+       Endpoint_Write_Byte(0x00);
+       Endpoint_Write_Byte(0x00);
+       Endpoint_Write_Byte(DISK_READ_ONLY ? 0x80 : 0x00);
+       Endpoint_Write_Byte(0x00);
+       Endpoint_ClearIN();
+
+       /* Update the bytes transferred counter and succeed the command */
+       MSInterfaceInfo->State.CommandBlock.DataTransferLength -= 4;
+
+       return true;
+}
index 27eab5e..e9aa4f0 100644 (file)
@@ -81,6 +81,7 @@
                        static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
                        static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
                                                              const bool IsDataRead);
+                       static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
                #endif
 
 #endif
index f81a574..39aa43c 100644 (file)
@@ -78,6 +78,9 @@
                /** Default log interval when the EEPROM is blank, in 500ms ticks. */
                #define DEFAULT_LOG_INTERVAL     20
 
+               /** Indicates if the disk is write protected or not. */
+               #define DISK_READ_ONLY           false
+
        /* Type Defines: */
                typedef struct
                {
index acbeba5..a53c887 100644 (file)
@@ -64,6 +64,9 @@
                 */
                #define VIRTUAL_MEMORY_BLOCKS               (VIRTUAL_MEMORY_BYTES / VIRTUAL_MEMORY_BLOCK_SIZE)
 
+               /** Indicates if the disk is write protected or not. */
+               #define DISK_READ_ONLY                      false
+
        /* Function Prototypes: */
                void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
                                                  const uint32_t BlockAddress,
index b1e88dc..6a51c74 100644 (file)
@@ -113,6 +113,9 @@ bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
                case SCSI_CMD_READ_10:
                        CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ);
                        break;
+               case SCSI_CMD_MODE_SENSE_6:
+                       CommandSuccess = SCSI_Command_ModeSense_6(MSInterfaceInfo);
+                       break;
                case SCSI_CMD_TEST_UNIT_READY:
                case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
                case SCSI_CMD_VERIFY_10:
@@ -281,6 +284,17 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
        uint32_t BlockAddress;
        uint16_t TotalBlocks;
 
+       /* Check if the disk is write protected or not */
+       if ((IsDataRead == DATA_WRITE) && DISK_READ_ONLY)
+       {
+               /* Block address is invalid, update SENSE key and return command fail */
+               SCSI_SET_SENSE(SCSI_SENSE_KEY_DATA_PROTECT,
+                              SCSI_ASENSE_WRITE_PROTECTED,
+                              SCSI_ASENSEQ_NO_QUALIFIER);
+
+               return false;           
+       }
+
        /* Load in the 32-bit block address (SCSI uses big-endian, so have to reverse the byte order) */
        BlockAddress = SwapEndian_32(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]);
 
@@ -297,7 +311,7 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
 
                return false;
        }
-
+       
        /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */
        if (IsDataRead == DATA_READ)
          DataflashManager_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks);
@@ -310,3 +324,24 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
        return true;
 }
 
+/** Command processing for an issued SCSI MODE SENSE (6) command. This command returns various informational pages about
+ *  the SCSI device, as well as the device's Write Protect status.
+ *
+ *  \param[in] MSInterfaceInfo  Pointer to the Mass Storage class interface structure that the command is associated with
+ *
+ *  \return Boolean true if the command completed successfully, false otherwise.
+ */
+static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
+{
+       /* Send an empty header response with the Write Protect flag status */
+       Endpoint_Write_Byte(0x00);
+       Endpoint_Write_Byte(0x00);
+       Endpoint_Write_Byte(DISK_READ_ONLY ? 0x80 : 0x00);
+       Endpoint_Write_Byte(0x00);
+       Endpoint_ClearIN();
+
+       /* Update the bytes transferred counter and succeed the command */
+       MSInterfaceInfo->State.CommandBlock.DataTransferLength -= 4;
+
+       return true;
+}
index 8eae210..8360234 100644 (file)
@@ -80,6 +80,7 @@
                        static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
                        static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
                                                              const bool IsDataRead);
+                       static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
                #endif
 
 #endif