summaryrefslogtreecommitdiff
path: root/digital/zigbit/bitcloud/stack/Components/HAL/drivers/USBClasses/MSD/src/scsiProtocol.c
diff options
context:
space:
mode:
Diffstat (limited to 'digital/zigbit/bitcloud/stack/Components/HAL/drivers/USBClasses/MSD/src/scsiProtocol.c')
-rw-r--r--digital/zigbit/bitcloud/stack/Components/HAL/drivers/USBClasses/MSD/src/scsiProtocol.c398
1 files changed, 398 insertions, 0 deletions
diff --git a/digital/zigbit/bitcloud/stack/Components/HAL/drivers/USBClasses/MSD/src/scsiProtocol.c b/digital/zigbit/bitcloud/stack/Components/HAL/drivers/USBClasses/MSD/src/scsiProtocol.c
new file mode 100644
index 00000000..68c3cfb6
--- /dev/null
+++ b/digital/zigbit/bitcloud/stack/Components/HAL/drivers/USBClasses/MSD/src/scsiProtocol.c
@@ -0,0 +1,398 @@
+/****************************************************************************//**
+ \files scsiProtocol.h
+
+ \brief Implementation of communication device protocol command.
+
+ \author
+ Atmel Corporation: http://www.atmel.com \n
+ Support email: avr@atmel.com
+
+ Copyright (c) 2008-2011, Atmel Corporation. All rights reserved.
+ Licensed under Atmel's Limited License Agreement (BitCloudTM).
+
+ \internal
+ History:
+ 30/08/11 N. Fomin - Created
+*******************************************************************************/
+/******************************************************************************
+ Includes section
+******************************************************************************/
+#include <scsiProtocol.h>
+
+/******************************************************************************
+ Define(s) section
+******************************************************************************/
+// scsi commands
+#define INQUIRY 0x12
+#define READ_CAPACITY_10 0x25
+#define READ_10 0x28
+#define REQUEST_SENSE 0x03
+#define TEST_UNIT_READY 0x00
+#define WRITE_10 0x2A
+#define PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
+#define MODE_SENSE_6 0x1A
+#define READ_FORMAT_CAPACITIES 0x23
+#define VERIFY_10 0x2F
+
+// capacity definitions
+#define BLOCK_SIZE 512
+
+//inquiry definitions
+#define INQUIRY_PERIPHERAL 0x00
+#define INQUIRY_REMOVABLE 0x80
+#define INQUIRY_VERSION 0x04
+#define INQUIRY_RESPONSE_FORMAT 0x02
+#define INQUIRY_ADDITIONAL_LENGTH 0x20
+#define INQUIRY_FLAGS 0x00
+#define INQUIRY_VENDOR_ID "Atmel "
+#define INQUIRY_PRODUCT_ID "Mass Storage "
+#define INQUIRY_PRODUCT_REVISION "0001"
+
+// request sense definitions
+#define REQUEST_SENSE_CODE 0xF0
+#define REQUEST_SENSE_OBSOLETE 0x00
+#define REQUEST_SENSE_NORMAL_FLAGS 0x00
+#define REQUEST_SENSE_ERROR_FLAGS 0x05
+#define REQUEST_SENSE_INFO 0x00
+#define REQUEST_SENSE_ADDITIONAL_SENSE_LENGTH 0x0A
+#define REQUEST_SENSE_CMD_SPECIFIC_INFO 0x00
+#define REQUEST_SENSE_NORMAL_ADDITIONAL_SENSE_CODE 0x00
+#define REQUEST_SENSE_ERROR_ADDITIONAL_SENSE_CODE 0x20
+#define REQUEST_SENSE_ADDITIONAL_SENSE_CODE_QUALIFIER 0x00
+#define REQUEST_SENSE_FIELD_REPLACABLE_UNIT_CODE 0x00
+#define REQUEST_SENSE_SENSE_KEY_SPECIFIC_VALID 0x80
+#define REQUEST_SENSE_SENSE_KEY_SPECIFIC 0x00
+
+// mode sense definitions
+#define MODE_SENSE_LENGTH 0x03
+#define MODE_SENSE_MEDIA_TYPE 0x00
+#define MODE_SENSE_DEVICE_SPECIFIC 0x00
+#define MODE_SENSE_BLOCK_DESC_LENGTH 0x00
+
+// format capacities definitions
+#define FORMAT_CAPACITIES_RESERVED 0x00
+#define FORMAT_CAPACITIES_LENGTH 0x08
+#define FORMAT_CAPACITIES_DESC_TYPE 0x01
+
+/******************************************************************************
+ Types section
+******************************************************************************/
+BEGIN_PACK
+typedef struct PACK
+{
+ uint32_t lastLogicalBlock;
+ uint32_t logicalBlockLength;
+} ScsiReadCapacityResponse_t;
+
+typedef struct PACK
+{
+ uint8_t peripheral;
+ uint8_t removable;
+ uint8_t version;
+ uint8_t responseDataFormat;
+ uint8_t additionalLength;
+ uint8_t flags[3];
+ uint8_t vendorId[8];
+ uint8_t productId[16];
+ uint8_t productRevision[4];
+} ScsiInquiryResponse_t;
+
+typedef struct PACK
+{
+ uint8_t responseCodeAndValid;
+ uint8_t obsolete;
+ uint8_t flags;
+ uint32_t information;
+ uint8_t addSenseLen;
+ uint32_t cmdSpecificInfo;
+ uint8_t additionalSenseCode;
+ uint8_t additionalSenseCodeQualifier;
+ uint8_t fieldReplacableUnitCode;
+ uint8_t senseKeySpecific[3];
+} ScsiRequestSenseResponse_t;
+
+typedef struct PACK
+{
+ uint8_t modeDataLength;
+ uint8_t mediumType;
+ uint8_t deviceSpecific;
+ uint8_t blockDescriptorLength;
+} ScsiModeSense6Response_t;
+
+typedef struct PACK
+{
+ uint8_t reserved[3];
+ uint8_t length;
+ uint32_t blocksNumber;
+ uint8_t descType;
+ uint8_t blockLengthUp;
+ uint16_t blockLengthDown;
+} ScsiReadFormatCapacities_t;
+
+typedef struct PACK
+{
+ uint8_t flags;
+ uint32_t logicalBlockAddress;
+ uint8_t groupNumber;
+ uint16_t transferLength;
+ uint8_t control;
+} ScsiReadWriteCommand_t;
+
+typedef struct PACK
+{
+ uint8_t index;
+ union
+ {
+ ScsiReadWriteCommand_t rwCommand;
+ };
+} ScsiCommand_t;
+END_PACK
+
+/******************************************************************************
+ Global variables section
+******************************************************************************/
+static bool defaultRequestSenseResponse;
+static uint32_t lastLogicalBlockNum;
+
+/******************************************************************************
+ Constants section
+******************************************************************************/
+const ScsiInquiryResponse_t inquiryResponse = {
+ INQUIRY_PERIPHERAL,
+ INQUIRY_REMOVABLE,
+ INQUIRY_VERSION,
+ INQUIRY_RESPONSE_FORMAT,
+ INQUIRY_ADDITIONAL_LENGTH,
+ {INQUIRY_FLAGS, INQUIRY_FLAGS, INQUIRY_FLAGS},
+ INQUIRY_VENDOR_ID,
+ INQUIRY_PRODUCT_ID,
+ INQUIRY_PRODUCT_REVISION
+};
+
+const ScsiRequestSenseResponse_t normalRequestSenseResponse = {
+ REQUEST_SENSE_CODE,
+ REQUEST_SENSE_OBSOLETE,
+ REQUEST_SENSE_NORMAL_FLAGS,
+ SWAP32(REQUEST_SENSE_INFO),
+ REQUEST_SENSE_ADDITIONAL_SENSE_LENGTH,
+ SWAP32(REQUEST_SENSE_CMD_SPECIFIC_INFO),
+ REQUEST_SENSE_NORMAL_ADDITIONAL_SENSE_CODE,
+ REQUEST_SENSE_ADDITIONAL_SENSE_CODE_QUALIFIER,
+ REQUEST_SENSE_FIELD_REPLACABLE_UNIT_CODE,
+ {REQUEST_SENSE_SENSE_KEY_SPECIFIC_VALID, REQUEST_SENSE_SENSE_KEY_SPECIFIC, REQUEST_SENSE_SENSE_KEY_SPECIFIC}
+};
+
+const ScsiRequestSenseResponse_t errorRequestSenseResponse = {
+ REQUEST_SENSE_CODE,
+ REQUEST_SENSE_OBSOLETE,
+ REQUEST_SENSE_ERROR_FLAGS,
+ SWAP32(REQUEST_SENSE_INFO),
+ REQUEST_SENSE_ADDITIONAL_SENSE_LENGTH,
+ SWAP32(REQUEST_SENSE_CMD_SPECIFIC_INFO),
+ REQUEST_SENSE_ERROR_ADDITIONAL_SENSE_CODE,
+ REQUEST_SENSE_ADDITIONAL_SENSE_CODE_QUALIFIER,
+ REQUEST_SENSE_FIELD_REPLACABLE_UNIT_CODE,
+ {REQUEST_SENSE_SENSE_KEY_SPECIFIC_VALID, REQUEST_SENSE_SENSE_KEY_SPECIFIC, REQUEST_SENSE_SENSE_KEY_SPECIFIC}
+};
+
+const ScsiModeSense6Response_t modeSense6Response = {
+ MODE_SENSE_LENGTH,
+ MODE_SENSE_MEDIA_TYPE,
+ MODE_SENSE_DEVICE_SPECIFIC,
+ MODE_SENSE_BLOCK_DESC_LENGTH
+};
+
+/******************************************************************************
+ Implementations section
+******************************************************************************/
+
+/**************************************************************************//**
+\brief Checks if received scsi command is supported.
+\param[in]
+ data - pointer to received command with parameters.
+\return
+ false - command is not supported;
+ true - command is supported.
+******************************************************************************/
+bool scsiIsValidCommand(uint8_t *data)
+{
+ ScsiCommand_t *command = (ScsiCommand_t *)data;
+
+ command->rwCommand.transferLength = SWAP16(command->rwCommand.transferLength);
+ command->rwCommand.logicalBlockAddress = SWAP32(command->rwCommand.logicalBlockAddress);
+
+ switch (command->index)
+ {
+ case INQUIRY:
+ case READ_CAPACITY_10:
+ case TEST_UNIT_READY:
+ case PREVENT_ALLOW_MEDIUM_REMOVAL:
+ case READ_10:
+ case WRITE_10:
+ case MODE_SENSE_6:
+ case READ_FORMAT_CAPACITIES:
+ case VERIFY_10:
+ defaultRequestSenseResponse = true;
+ break;
+ case REQUEST_SENSE:
+ return true;
+ default:
+ defaultRequestSenseResponse = false;
+ break;
+ }
+
+ return defaultRequestSenseResponse;
+}
+
+/**************************************************************************//**
+\brief Checks if any response or data transfer needed for received
+ scsi command.
+\param[in]
+ command - received command.
+\return
+ false - response is not needed;
+ true - response is needed.
+******************************************************************************/
+bool scsiIsDataInOutPhaseNeeded(uint8_t *data)
+{
+ ScsiCommand_t *command = (ScsiCommand_t *)data;
+
+ if ((TEST_UNIT_READY == command->index) || (PREVENT_ALLOW_MEDIUM_REMOVAL == command->index)
+ || (VERIFY_10 == command->index))
+ return false;
+ if ((READ_10 == command->index) || (WRITE_10 == command->index))
+ if (0 == command->rwCommand.transferLength)
+ return false;
+ return true;
+}
+
+/**************************************************************************//**
+\brief Checks if command is read or write command.
+\param[in]
+ command - received command.
+\return
+ false - command is not read/write command;
+ true - command is read/write command.
+******************************************************************************/
+bool scsiIsReadWriteCommand(uint8_t *data)
+{
+ ScsiCommand_t *command = (ScsiCommand_t *)data;
+
+ return ((READ_10 == command->index) || (WRITE_10 == command->index));
+}
+
+/**************************************************************************//**
+\brief Checks if command is read command.
+\param[in]
+ command - received command.
+\return
+ false - command is not read command;
+ true - command is read command.
+******************************************************************************/
+bool scsiIsReadCommand(uint8_t *data)
+{
+ ScsiCommand_t *command = (ScsiCommand_t *)data;
+
+ return (READ_10 == command->index);
+}
+
+/**************************************************************************//**
+\brief Blocks for read/write command.
+\param[in]
+ data - pointer to received command with parameters.
+\return
+ number of blocks to read or write from memory.
+******************************************************************************/
+uint16_t scsiBlocksAmount(uint8_t *data)
+{
+ ScsiCommand_t *command = (ScsiCommand_t *)data;
+
+ if ((READ_10 == command->index) || (WRITE_10 == command->index))
+ return command->rwCommand.transferLength;
+
+ return 0;
+}
+
+/**************************************************************************//**
+\brief Response for scsi command.
+\param[in]
+ command - received command.
+\param[out]
+ buffer - buffer with scsi command response.
+\return
+ length of response
+******************************************************************************/
+uint8_t scsiGetCommandResponse(uint8_t *data, uint8_t *buffer)
+{
+ ScsiCommand_t *command = (ScsiCommand_t *)data;
+ ScsiReadCapacityResponse_t readCapacityResponse = {
+ .lastLogicalBlock = SWAP32(lastLogicalBlockNum),
+ .logicalBlockLength = SWAP32(BLOCK_SIZE)
+ };
+ ScsiReadFormatCapacities_t readFormatCapacitiesResponse = {
+ .reserved = {FORMAT_CAPACITIES_RESERVED, FORMAT_CAPACITIES_RESERVED, FORMAT_CAPACITIES_RESERVED},
+ .length = FORMAT_CAPACITIES_LENGTH,
+ .blocksNumber = SWAP32(lastLogicalBlockNum + 1),
+ .descType = FORMAT_CAPACITIES_DESC_TYPE,
+ .blockLengthUp = 0,
+ .blockLengthDown = SWAP16(BLOCK_SIZE)
+ };
+
+ if (INQUIRY == command->index)
+ {
+ memcpy(buffer, (uint8_t *)&inquiryResponse, sizeof(ScsiInquiryResponse_t));
+ return sizeof(ScsiInquiryResponse_t);
+ }
+ if (READ_CAPACITY_10 == command->index)
+ {
+ memcpy(buffer, (uint8_t *)&readCapacityResponse, sizeof(ScsiReadCapacityResponse_t));
+ return sizeof(ScsiReadCapacityResponse_t);
+ }
+ if (REQUEST_SENSE == command->index)
+ {
+ if (defaultRequestSenseResponse)
+ memcpy(buffer, (uint8_t *)&normalRequestSenseResponse, sizeof(ScsiRequestSenseResponse_t));
+ else
+ memcpy(buffer, (uint8_t *)&errorRequestSenseResponse, sizeof(ScsiRequestSenseResponse_t));
+ return sizeof(ScsiRequestSenseResponse_t);
+ }
+ if (MODE_SENSE_6 == command->index)
+ {
+ memcpy(buffer, (uint8_t *)&modeSense6Response, sizeof(ScsiModeSense6Response_t));
+ return sizeof(ScsiModeSense6Response_t);
+ }
+ if (READ_FORMAT_CAPACITIES == command->index)
+ {
+ memcpy(buffer, (uint8_t *)&readFormatCapacitiesResponse, sizeof(ScsiReadFormatCapacities_t));
+ return sizeof(ScsiReadFormatCapacities_t);
+ }
+ return 0;
+}
+
+/**************************************************************************//**
+\brief Sets number of last available memory block for scsi response.
+\param[in]
+ lastBlock - received command.
+\param[out]
+ buffer - number of last available memory block
+******************************************************************************/
+void scsiSetCapacity(uint32_t lastBlock)
+{
+ lastLogicalBlockNum = lastBlock;
+}
+
+/**************************************************************************//**
+\brief Block address for read/write command.
+\param[in]
+ data - pointer to received command with parameters.
+\return
+ block address for read or write from memory.
+******************************************************************************/
+uint32_t scsiGetBlockAddress(uint8_t *data)
+{
+ ScsiCommand_t *command = (ScsiCommand_t *)data;
+
+ return command->rwCommand.logicalBlockAddress;
+}
+
+//eof scsiProtocol.c