/*
LUFA Library
- Copyright (C) Dean Camera, 2010.
+ Copyright (C) Dean Camera, 2011.
dean [at] fourwalledcubicle [dot] com
www.lufa-lib.org
*/
/*
- Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
+ Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
/** Structure to hold the SCSI response data to a SCSI INQUIRY command. This gives information about the device's
* features and capabilities.
*/
-SCSI_Inquiry_Response_t InquiryData =
+static const SCSI_Inquiry_Response_t InquiryData =
{
.DeviceType = DEVICE_TYPE_BLOCK,
.PeripheralQualifier = 0,
/** Structure to hold the sense data for the last issued SCSI command, which is returned to the host after a SCSI REQUEST SENSE
* command is issued. This gives information on exactly why the last command failed to complete.
*/
-SCSI_Request_Sense_Response_t SenseData =
+static SCSI_Request_Sense_Response_t SenseData =
{
.ResponseCode = 0x70,
.AdditionalLength = 0x0A,
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:
static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
{
uint16_t AllocationLength = SwapEndian_16(*(uint16_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[3]);
- uint16_t BytesTransferred = (AllocationLength < sizeof(InquiryData))? AllocationLength :
- sizeof(InquiryData);
+ uint16_t BytesTransferred = MIN(AllocationLength, sizeof(InquiryData));
/* Only the standard INQUIRY data is supported, check if any optional INQUIRY bits set */
if ((MSInterfaceInfo->State.CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) ||
return false;
}
- Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, NO_STREAM_CALLBACK);
-
- uint8_t PadBytes[AllocationLength - BytesTransferred];
+ Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, NULL);
/* Pad out remaining bytes with 0x00 */
- Endpoint_Write_Stream_LE(&PadBytes, sizeof(PadBytes), NO_STREAM_CALLBACK);
+ Endpoint_Null_Stream((AllocationLength - BytesTransferred), NULL);
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN();
static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
{
uint8_t AllocationLength = MSInterfaceInfo->State.CommandBlock.SCSICommandData[4];
- uint8_t BytesTransferred = (AllocationLength < sizeof(SenseData))? AllocationLength : sizeof(SenseData);
-
- uint8_t PadBytes[AllocationLength - BytesTransferred];
+ uint8_t BytesTransferred = MIN(AllocationLength, sizeof(SenseData));
- Endpoint_Write_Stream_LE(&SenseData, BytesTransferred, NO_STREAM_CALLBACK);
- Endpoint_Write_Stream_LE(&PadBytes, sizeof(PadBytes), NO_STREAM_CALLBACK);
+ Endpoint_Write_Stream_LE(&SenseData, BytesTransferred, NULL);
+ Endpoint_Null_Stream((AllocationLength - BytesTransferred), NULL);
Endpoint_ClearIN();
/* Succeed the command and update the bytes transferred counter */
uint32_t LastBlockAddressInLUN = (VIRTUAL_MEMORY_BLOCKS - 1);
uint32_t MediaBlockSize = VIRTUAL_MEMORY_BLOCK_SIZE;
- Endpoint_Write_Stream_BE(&LastBlockAddressInLUN, sizeof(LastBlockAddressInLUN), NO_STREAM_CALLBACK);
- Endpoint_Write_Stream_BE(&MediaBlockSize, sizeof(MediaBlockSize), NO_STREAM_CALLBACK);
+ Endpoint_Write_Stream_BE(&LastBlockAddressInLUN, sizeof(LastBlockAddressInLUN), NULL);
+ Endpoint_Write_Stream_BE(&MediaBlockSize, sizeof(MediaBlockSize), NULL);
Endpoint_ClearIN();
/* Succeed the command and update the bytes transferred counter */
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_8(0x00);
+ Endpoint_Write_8(0x00);
+ Endpoint_Write_8(DISK_READ_ONLY ? 0x80 : 0x00);
+ Endpoint_Write_8(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