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:
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]);
/* 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);
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;
+}
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
/** 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);
/** 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,
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:
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]);
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;
+}
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
/** 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);
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:
*/
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)
{
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;
+}
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
/** 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;
* - 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:
/* 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,
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:
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]);
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);
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
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
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:
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]);
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);
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;
+}
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
/** 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
{
*/
#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,
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:
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]);
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);
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;
+}
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