From f2e4500f883e8c2ac7d698f15c22b6c77fde6faf Mon Sep 17 00:00:00 2001 From: ksb Date: Sat, 11 Jul 2009 14:50:08 +0000 Subject: [PATCH] SCSI RBC --- cpu/arm/common/usb/msc/msc-descriptors.c | 72 ++++ .../common/usb/msc/msc-string-descriptors.xml | 17 + cpu/arm/common/usb/msc/usb-rbc.c | 365 ++++++++++++++++++ 3 files changed, 454 insertions(+) create mode 100644 cpu/arm/common/usb/msc/msc-descriptors.c create mode 100644 cpu/arm/common/usb/msc/msc-string-descriptors.xml create mode 100644 cpu/arm/common/usb/msc/usb-rbc.c diff --git a/cpu/arm/common/usb/msc/msc-descriptors.c b/cpu/arm/common/usb/msc/msc-descriptors.c new file mode 100644 index 000000000..3ee0e613e --- /dev/null +++ b/cpu/arm/common/usb/msc/msc-descriptors.c @@ -0,0 +1,72 @@ +#include "descriptors.h" +#include "usbmassbulk.h" +#include + +const struct usb_st_device_descriptor device_descriptor = + { + sizeof(struct usb_st_device_descriptor), + DEVICE, + 0x0210, + 0, + 0, + 0, + CTRL_EP_SIZE, + 0xffff, + 0xffff, + 0x0030, + 2, + 1, + 3, + 1 + }; + +const struct configuration_st { + struct usb_st_configuration_descriptor configuration; + struct usb_st_interface_descriptor massbulk; + struct usb_st_endpoint_descriptor ep_in; + struct usb_st_endpoint_descriptor ep_out; +} BYTE_ALIGNED configuration_block = + { + /* Configuration */ + { + sizeof(configuration_block.configuration), + CONFIGURATION, + sizeof(configuration_block), + 1, + 1, + 0, + 0x80, + 50 + }, + { + sizeof(configuration_block.massbulk), + INTERFACE, + 0, + 0, + 2, + MASS_STORAGE, + MASS_RBC, + MASS_BULK_ONLY, + 0 + }, + { + sizeof(configuration_block.ep_in), + ENDPOINT, + 0x81, + 0x02, + 64, + 0 + }, + { + sizeof(configuration_block.ep_out), + ENDPOINT, + 0x02, + 0x02, + 64, + 0 + } + + }; + +const struct usb_st_configuration_descriptor const *configuration_head = +(struct usb_st_configuration_descriptor const*)&configuration_block; diff --git a/cpu/arm/common/usb/msc/msc-string-descriptors.xml b/cpu/arm/common/usb/msc/msc-string-descriptors.xml new file mode 100644 index 000000000..6fda8d23c --- /dev/null +++ b/cpu/arm/common/usb/msc/msc-string-descriptors.xml @@ -0,0 +1,17 @@ + + + + 0x0409 + + + + USB mass storage test + + + Fluffware + + + F00000000001 + + + diff --git a/cpu/arm/common/usb/msc/usb-rbc.c b/cpu/arm/common/usb/msc/usb-rbc.c new file mode 100644 index 000000000..ca79a1fa1 --- /dev/null +++ b/cpu/arm/common/usb/msc/usb-rbc.c @@ -0,0 +1,365 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +#ifndef USB_RBC_NUM_BLOCKS +#define USB_RBC_NUM_BLOCKS 32 +#endif + +static struct spc2_sense_data sense_data = + { + SCSI_SENSE_CURRENT_ERROR, + 0, + 0, + {0}, + (sizeof(struct spc2_sense_data) + - offsetof(struct spc2_sense_data, command_specific)) + }; + +static void +scsi_error(unsigned int sense_key, unsigned int asc, int32_t info) +{ + sense_data.response_code = SCSI_SENSE_INFORMATION_VALID | SCSI_SENSE_CURRENT_ERROR; + sense_data.information[0] = (info >> 24) & 0xff; + sense_data.information[1] = (info >> 16) & 0xff; + sense_data.information[2] = (info >> 8) & 0xff; + sense_data.information[3] = info & 0xff; + sense_data.sense_key = sense_key; + sense_data.asc = (asc >> 8) & 0xff; + sense_data.ascq = asc & 0xff; +} + +static void +scsi_ok() +{ + sense_data.response_code = SCSI_SENSE_CURRENT_ERROR; + sense_data.sense_key = SCSI_SENSE_KEY_NO_SENSE; + sense_data.asc = 0x00; + sense_data.ascq = 0x00; +}; + +static const struct spc2_std_inquiry_data std_inquiry_data = + { + SCSI_STD_INQUIRY_CONNECTED | SCSI_STD_INQUIRY_TYPE_RBC, + 0, + SCSI_STD_INQUIRY_VERSION_SPC2, + 0, + (sizeof(struct spc2_std_inquiry_data) + - offsetof(struct spc2_std_inquiry_data, flags3)), + 0, + 0, + 0, + {'F','l','u','f','w','a','r','e'}, + {'T','e','s','t',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}, + {'0','.','1',' '} + }; + +#define UNIT_NAME {'F','l','u','f','f','w','a','r','e',' ', \ + 'P','s','e','u','d','o',' ','D','i','s','k'} +#define UNIT_NAME_LENGTH 21 + +static const struct +{ + struct spc2_vital_product_data_head head; + struct { + struct spc2_vital_product_data_head head; + char unit_name[UNIT_NAME_LENGTH]; + } descriptor; +} CC_BYTE_ALIGNED device_identification_data = + { + { + SCSI_STD_INQUIRY_CONNECTED | SCSI_STD_INQUIRY_TYPE_RBC, + SCSI_PAGE_DEVICE_IDENTIFICATION, + 0, + sizeof(device_identification_data.descriptor), + }, + { + { + SCSI_CODE_SET_ACSII, + SCSI_IDENTIFIER_TYPE_NON_UNIQUE, + 0, + sizeof(device_identification_data.descriptor.unit_name) + }, + UNIT_NAME + } + }; + + +static const struct +{ + struct spc2_vital_product_data_head head; + uint8_t supported[3]; +} CC_BYTE_ALIGNED supported_pages_data = + { + { + SCSI_STD_INQUIRY_CONNECTED | SCSI_STD_INQUIRY_TYPE_RBC, + SCSI_PAGE_SUPPORTED_PAGES, + 0, + sizeof(supported_pages_data.supported), + }, + {SCSI_PAGE_SUPPORTED_PAGES, SCSI_PAGE_UNIT_SERIAL_NUMBER, + SCSI_PAGE_DEVICE_IDENTIFICATION} + }; + +static const struct +{ + struct spc2_vital_product_data_head head; + uint8_t serial_number[8]; +} CC_BYTE_ALIGNED unit_serial_number_data = { + { + SCSI_STD_INQUIRY_CONNECTED | SCSI_STD_INQUIRY_TYPE_RBC, + SCSI_PAGE_SUPPORTED_PAGES, + 0, + sizeof(unit_serial_number_data.serial_number) + }, + {'1','2','3','4','5','6','7','8'} +}; + +static usb_msc_handler_status +handle_inquiry_cmd(struct usb_msc_command_state *state) +{ + struct spc2_inquiry_cmd *cmd = (struct spc2_inquiry_cmd*)state->command; + if (cmd->flags & SCSI_INQUIRY_FLAG_CMDDT) { + scsi_error(SCSI_SENSE_KEY_ILLEGAL_REQUEST,SCSI_ASC_INVALID_FIELD_IN_CDB, + cmd->allocation_length); + return USB_MSC_HANDLER_FAILED; + } + if (cmd->flags & SCSI_INQUIRY_FLAG_EVPD) { + PRINTF("Requested page %02x\n", cmd->page); + switch (cmd->page) { + case SCSI_PAGE_SUPPORTED_PAGES: + usb_msc_send_data((uint8_t *)&supported_pages_data, + sizeof(supported_pages_data), + USB_MSC_DATA_SEND | USB_MSC_DATA_LAST); + break; + case SCSI_PAGE_DEVICE_IDENTIFICATION: + usb_msc_send_data((uint8_t *)&device_identification_data, + sizeof(device_identification_data), + USB_MSC_DATA_SEND | USB_MSC_DATA_LAST); + break; + case SCSI_PAGE_UNIT_SERIAL_NUMBER: + usb_msc_send_data((uint8_t *)&unit_serial_number_data, + sizeof(unit_serial_number_data), + USB_MSC_DATA_SEND | USB_MSC_DATA_LAST); + break; + default: + scsi_error(SCSI_SENSE_KEY_ILLEGAL_REQUEST,SCSI_ASC_INVALID_FIELD_IN_CDB, + cmd->allocation_length); + return USB_MSC_HANDLER_FAILED; + } + return USB_MSC_HANDLER_OK; + } else { + if (cmd->page != 0) { + scsi_error(SCSI_SENSE_KEY_ILLEGAL_REQUEST,SCSI_ASC_INVALID_FIELD_IN_CDB, + cmd->allocation_length); + return USB_MSC_HANDLER_FAILED; + } + usb_msc_send_data((uint8_t *)&std_inquiry_data, + sizeof(std_inquiry_data), + USB_MSC_DATA_SEND | USB_MSC_DATA_LAST); + } + return USB_MSC_HANDLER_OK; +} + +static usb_msc_handler_status +handle_request_sense_cmd(struct usb_msc_command_state *state) +{ + usb_msc_send_data((uint8_t *)&sense_data, + sizeof(sense_data), + USB_MSC_DATA_SEND | USB_MSC_DATA_LAST); + return USB_MSC_HANDLER_OK; +} + +static usb_msc_handler_status +handle_test_unit_ready_cmd(struct usb_msc_command_state *state) +{ + scsi_ok(); + return USB_MSC_HANDLER_OK; +} + +static const struct rbc_read_capacity_data read_capacity_data = + { + HOST32_TO_BE_BYTES(USB_RBC_NUM_BLOCKS-1), + HOST32_TO_BE_BYTES(512) + }; + +static usb_msc_handler_status +handle_read_capacity(struct usb_msc_command_state *state) +{ + usb_msc_send_data((uint8_t *)&read_capacity_data, + sizeof(read_capacity_data), + USB_MSC_DATA_SEND | USB_MSC_DATA_LAST); + return USB_MSC_HANDLER_OK; +} + +static const struct mode_sense_data { + struct spc2_mode_parameter_header_6 header; + struct rbc_device_parameters_page page; +} CC_BYTE_ALIGNED mode_sense_data = + { + { + (sizeof(mode_sense_data) + - offsetof(struct mode_sense_data, header.medium_type)), + 0,0,0 + }, + { + {SCSI_MODE_RBC_DEVICE_PAGE | SCSI_MODE_PAGE_SP, + sizeof(mode_sense_data) - offsetof(struct mode_sense_data, page.flags1)}, + SCSI_MODE_WCD, + HOST16_TO_BE_BYTES(512), + HOST40_TO_BE_BYTES((long long)USB_RBC_NUM_BLOCKS), + 0x80, + (SCSI_MODE_FORMATD | SCSI_MODE_LOCKD), + 0 + } + }; + +static usb_msc_handler_status +handle_mode_sense(struct usb_msc_command_state *state) +{ + struct spc2_mode_sence_6_cmd *cmd = + (struct spc2_mode_sence_6_cmd*)state->command; + PRINTF("%ld - %ld - %ld\n", sizeof(struct mode_sense_data), offsetof(struct mode_sense_data, page.flags1),offsetof(struct mode_sense_data, page.reserved)); + switch(cmd->page_code) { + case SCSI_MODE_RBC_DEVICE_PAGE: + case SCSI_MODE_SENSE_ALL_PAGES: + usb_msc_send_data((uint8_t *)&mode_sense_data, + sizeof(mode_sense_data), + USB_MSC_DATA_SEND | USB_MSC_DATA_LAST); + break; + default: + scsi_error(SCSI_SENSE_KEY_ILLEGAL_REQUEST,SCSI_ASC_INVALID_FIELD_IN_CDB, + cmd->allocation_length); + return USB_MSC_HANDLER_FAILED; + } + return USB_MSC_HANDLER_OK; +} + +static usb_msc_handler_status +handle_mode_select(struct usb_msc_command_state *state) +{ + /* Can't change anything */ + return USB_MSC_HANDLER_OK; +} +static uint8_t disk_blocks[USB_RBC_NUM_BLOCKS][512]; + +static usb_msc_handler_status +handle_read(struct usb_msc_command_state *state) +{ + struct rbc_read_cmd *cmd = (struct rbc_read_cmd*)state->command; + unsigned long lba = be32_to_host(cmd->logical_block_address); + unsigned long blocks = be16_to_host(cmd->transfer_length); + PRINTF("Requested %ld blocks at %ld\n", blocks, lba); + if (lba >= USB_RBC_NUM_BLOCKS || lba + blocks > USB_RBC_NUM_BLOCKS) { + scsi_error(SCSI_SENSE_KEY_ILLEGAL_REQUEST,SCSI_ASC_INVALID_FIELD_IN_CDB, + blocks); + return USB_MSC_HANDLER_FAILED; + } + usb_msc_send_data((uint8_t *)&disk_blocks[lba], blocks * 512, + USB_MSC_DATA_SEND | USB_MSC_DATA_LAST); + scsi_ok(); + return USB_MSC_HANDLER_OK; +} + +static void +handle_write_done(struct usb_msc_command_state *state) +{ + PRINTF("Wrote data\n"); + state->status = MASS_BULK_CSW_STATUS_PASSED; + scsi_ok(); +} + +static usb_msc_handler_status +handle_write(struct usb_msc_command_state *state) +{ + struct rbc_write_cmd *cmd = (struct rbc_write_cmd*)state->command; + unsigned long lba = be32_to_host(cmd->logical_block_address); + unsigned long blocks = be16_to_host(cmd->transfer_length); + if (lba >= USB_RBC_NUM_BLOCKS || lba + blocks > USB_RBC_NUM_BLOCKS) { + scsi_error(SCSI_SENSE_KEY_ILLEGAL_REQUEST,SCSI_ASC_INVALID_FIELD_IN_CDB, + blocks); + return USB_MSC_HANDLER_FAILED; + } + PRINTF("Writing %ld blocks at %ld\n", blocks, lba); + usb_msc_receive_data(disk_blocks[lba], blocks * 512, + USB_MSC_DATA_RECEIVE | USB_MSC_DATA_LAST + | USB_MSC_DATA_DO_CALLBACK); + state->data_cb = handle_write_done; + return USB_MSC_HANDLER_DELAYED; +} + +static usb_msc_handler_status +handle_start_stop_unit(struct usb_msc_command_state *state) +{ + scsi_ok(); + return USB_MSC_HANDLER_OK; +} + +static usb_msc_handler_status +handle_verify(struct usb_msc_command_state *state) +{ + scsi_ok(); + return USB_MSC_HANDLER_OK; +} + +usb_msc_handler_status +usb_msc_handle_command(struct usb_msc_command_state *state) +{ + + usb_msc_handler_status ret; + PRINTF("Got CBW %02x\n", state->command[0]); + switch(state->command[0]) { + case SCSI_CMD_INQUIRY: + ret = handle_inquiry_cmd(state); + break; + case SCSI_CMD_REQUEST_SENSE: + ret = handle_request_sense_cmd(state); + break; + case SCSI_CMD_TEST_UNIT_READY: + ret = handle_test_unit_ready_cmd(state); + break; + case SCSI_CMD_READ_CAPACITY: + ret = handle_read_capacity(state); + break; + case SCSI_CMD_MODE_SENSE_6: + ret = handle_mode_sense(state); + break; + case SCSI_CMD_MODE_SELECT_6: + ret = handle_mode_select(state); + break; + case SCSI_CMD_READ_10: + ret = handle_read(state); + break; + case SCSI_CMD_WRITE_10: + ret = handle_write(state); + break; + case SCSI_CMD_VERIFY_10: + ret = handle_verify(state); + break; + case SCSI_CMD_START_STOP_UNIT: + ret = handle_start_stop_unit(state); + break; + default: + printf("Unhandled request: %02x\n", state->command[0]); + scsi_error(SCSI_SENSE_KEY_ILLEGAL_REQUEST, + SCSI_ASC_INVALID_COMMAND_OPERATION,0); + return USB_MSC_HANDLER_FAILED; + } + return ret; +} + +void +usb_msc_command_handler_init() +{ +}