diff --git a/firmware/baseband/sd_over_usb/scsi.c b/firmware/baseband/sd_over_usb/scsi.c index b4b03536..18397ecd 100644 --- a/firmware/baseband/sd_over_usb/scsi.c +++ b/firmware/baseband/sd_over_usb/scsi.c @@ -62,23 +62,9 @@ volatile bool inquiry_stage_one_send = false; void inquiry_cb(void* user_data, unsigned int bytes_transferred) { inquiry_stage_one_send = true; - - //HALT_UNTIL_DEBUGGING(); - - //faulty - // usb_transfer_schedule_block( - // &usb_endpoint_bulk_out, - // &usb_bulk_buffer[0], - // USB_TRANSFER_SIZE, - // handle_inquiry_3, - // msd_cbw_data); - - -//does not send - } -void handle_inquiry(msd_cbw_t *msd_cbw_data){ +void handle_inquiry(msd_cbw_t *msd_cbw_data) { inquiry_stage_one_send = false; memcpy(&usb_bulk_buffer[0], &default_scsi_inquiry_response, sizeof(scsi_inquiry_response_t)); usb_transfer_schedule_block( @@ -98,16 +84,290 @@ void handle_inquiry(msd_cbw_t *msd_cbw_data){ }; memcpy(&usb_bulk_buffer[0x4000], &csw, sizeof(msd_csw_t)); - // does not gets send usb_transfer_schedule_block( &usb_endpoint_bulk_in, &usb_bulk_buffer[0x4000], sizeof(msd_csw_t), - NULL, //handle_inquiry_3, - NULL); //msd_cbw_data); + NULL, + NULL); } +typedef struct { + uint8_t header[4]; + uint8_t blocknum[4]; + uint8_t blocklen[4]; +} scsi_read_format_capacities_response_t; + +volatile bool capacities_stage_one_send = false; +void capacities_cb(void* user_data, unsigned int bytes_transferred) +{ + capacities_stage_one_send = true; +} + +void read_format_capacities(msd_cbw_t *msd_cbw_data) { + uint16_t len = msd_cbw_data->cmd_data[7] << 8 | msd_cbw_data->cmd_data[8]; + + if (len != 0) { + scsi_read_format_capacities_response_t ret = { + .header = {0, 0, 0, 1 * 8 /* num_entries * 8 */}, + .blocknum = {0, 0, (1024 * 8) >> 8, 0}, // 32GB + .blocklen = {0b10 /* formated */, 0, (512) >> 8, 0} + }; + + capacities_stage_one_send = false; + memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_read_format_capacities_response_t)); + usb_transfer_schedule_block( + &usb_endpoint_bulk_in, + &usb_bulk_buffer[0], + sizeof(scsi_inquiry_response_t), + capacities_cb, + msd_cbw_data); + + while (!capacities_stage_one_send); + } + + + msd_csw_t csw = { + .signature = MSD_CSW_SIGNATURE, + .tag = msd_cbw_data->tag, + .data_residue = 0, + .status = 0 + }; + + memcpy(&usb_bulk_buffer[0x4000], &csw, sizeof(msd_csw_t)); + usb_transfer_schedule_block( + &usb_endpoint_bulk_in, + &usb_bulk_buffer[0x4000], + sizeof(msd_csw_t), + NULL, + NULL); + +} + +typedef struct { + uint32_t last_block_addr; + uint32_t block_size; +} scsi_read_capacity10_response_t; + +volatile bool capacity10_stage_one_send = false; +void capacity10_cb(void* user_data, unsigned int bytes_transferred) +{ + capacity10_stage_one_send = true; +} + +void read_capacity10(msd_cbw_t *msd_cbw_data) { + capacity10_stage_one_send = false; + + scsi_read_capacity10_response_t ret = { + .last_block_addr = cpu_to_be32(8 * 1024 * 1024 - 1), + .block_size = cpu_to_be32(512) + }; + + memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_read_capacity10_response_t)); + usb_transfer_schedule_block( + &usb_endpoint_bulk_in, + &usb_bulk_buffer[0], + sizeof(scsi_read_capacity10_response_t), + capacity10_cb, + msd_cbw_data); + + while (!capacity10_stage_one_send); + + msd_csw_t csw = { + .signature = MSD_CSW_SIGNATURE, + .tag = msd_cbw_data->tag, + .data_residue = 0, + .status = 0 + }; + + memcpy(&usb_bulk_buffer[0x4000], &csw, sizeof(msd_csw_t)); + usb_transfer_schedule_block( + &usb_endpoint_bulk_in, + &usb_bulk_buffer[0x4000], + sizeof(msd_csw_t), + NULL, + NULL); + +} + + +typedef struct { + uint8_t byte[18]; +} scsi_sense_response_t; + +volatile bool sense_stage_one_send = false; +void sense_cb(void* user_data, unsigned int bytes_transferred) +{ + sense_stage_one_send = true; +} + + +void request_sense(msd_cbw_t *msd_cbw_data) { + sense_stage_one_send = false; + + scsi_sense_response_t ret = { + .byte = { 0x70, 0, SCSI_SENSE_KEY_GOOD, 0, + 0, 0, 0, 8, + 0, 0 ,0 ,0, + SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, SCSI_ASENSEQ_NO_QUALIFIER, 0, 0, + 0, 0 } + }; + + memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_sense_response_t)); + usb_transfer_schedule_block( + &usb_endpoint_bulk_in, + &usb_bulk_buffer[0], + sizeof(scsi_sense_response_t), + sense_cb, + msd_cbw_data); + + while (!sense_stage_one_send); + + msd_csw_t csw = { + .signature = MSD_CSW_SIGNATURE, + .tag = msd_cbw_data->tag, + .data_residue = 0, + .status = 0 + }; + + memcpy(&usb_bulk_buffer[0x4000], &csw, sizeof(msd_csw_t)); + usb_transfer_schedule_block( + &usb_endpoint_bulk_in, + &usb_bulk_buffer[0x4000], + sizeof(msd_csw_t), + NULL, + NULL); +} + +typedef struct { + uint8_t byte[4]; +} scsi_mode_sense6_response_t; + +volatile bool sense6_stage_one_send = false; +void sense6_cb(void* user_data, unsigned int bytes_transferred) +{ + sense6_stage_one_send = true; +} + +void mode_sense6 (msd_cbw_t *msd_cbw_data) { + sense6_stage_one_send = false; + + scsi_mode_sense6_response_t ret = { + .byte = { + sizeof(scsi_mode_sense6_response_t) - 1, + 0, + 0x01 << 7, // 0 for not write protected + 0 } + }; + + memcpy(&usb_bulk_buffer[0], &ret, sizeof(scsi_mode_sense6_response_t)); + usb_transfer_schedule_block( + &usb_endpoint_bulk_in, + &usb_bulk_buffer[0], + sizeof(scsi_mode_sense6_response_t), + sense6_cb, + msd_cbw_data); + + while (!sense6_stage_one_send); + + msd_csw_t csw = { + .signature = MSD_CSW_SIGNATURE, + .tag = msd_cbw_data->tag, + .data_residue = 0, + .status = 0 + }; + + memcpy(&usb_bulk_buffer[0x4000], &csw, sizeof(msd_csw_t)); + usb_transfer_schedule_block( + &usb_endpoint_bulk_in, + &usb_bulk_buffer[0x4000], + sizeof(msd_csw_t), + NULL, + NULL); +} + +typedef struct { + uint32_t first_lba; + uint16_t blk_cnt; +} data_request_t; + +static data_request_t decode_data_request(const uint8_t *cmd) { + + data_request_t req; + uint32_t lba; + uint16_t blk; + + memcpy(&lba, &cmd[2], sizeof(lba)); + memcpy(&blk, &cmd[7], sizeof(blk)); + + req.first_lba = be32_to_cpu(lba); + req.blk_cnt = be16_to_cpu(blk); + + return req; +} + +volatile uint32_t read10_blocks_send = 0; +void read10_cb(void* user_data, unsigned int bytes_transferred) +{ + read10_blocks_send++; +} + + +void data_read10(msd_cbw_t *msd_cbw_data) { + read10_blocks_send = 0; + + data_request_t req = decode_data_request(msd_cbw_data->cmd_data); + + for (size_t block_index = 0; block_index < req.blk_cnt; block_index++) { + memset(&usb_bulk_buffer[0], 0, 512); + + usb_transfer_schedule_block( + &usb_endpoint_bulk_in, + &usb_bulk_buffer[0], + 512, + read10_cb, + msd_cbw_data); + + while (read10_blocks_send <= block_index); + } + + msd_csw_t csw = { + .signature = MSD_CSW_SIGNATURE, + .tag = msd_cbw_data->tag, + .data_residue = 0, + .status = 0 + }; + + memcpy(&usb_bulk_buffer[0x4000], &csw, sizeof(msd_csw_t)); + usb_transfer_schedule_block( + &usb_endpoint_bulk_in, + &usb_bulk_buffer[0x4000], + sizeof(msd_csw_t), + NULL, + NULL); +} + + + + +void test_unit_ready(msd_cbw_t *msd_cbw_data) { + msd_csw_t csw = { + .signature = MSD_CSW_SIGNATURE, + .tag = msd_cbw_data->tag, + .data_residue = 0, + .status = 0 + }; + + memcpy(&usb_bulk_buffer[0x4000], &csw, sizeof(msd_csw_t)); + usb_transfer_schedule_block( + &usb_endpoint_bulk_in, + &usb_bulk_buffer[0x4000], + sizeof(msd_csw_t), + NULL, + NULL); +} + void scsi_command(msd_cbw_t *msd_cbw_data) { switch (msd_cbw_data->cmd_data[0]) { @@ -117,50 +377,48 @@ void scsi_command(msd_cbw_t *msd_cbw_data) { break; - default: - HALT_UNTIL_DEBUGGING(); + case SCSI_CMD_REQUEST_SENSE: + request_sense(msd_cbw_data); + break; + + case SCSI_CMD_READ_CAPACITY_10: + read_capacity10(msd_cbw_data); + break; + + case SCSI_CMD_READ_10: + data_read10(msd_cbw_data); + break; + + /* + case SCSI_CMD_WRITE_10: + ret = data_read_write10(scsip, cmd); + break; +*/ + case SCSI_CMD_TEST_UNIT_READY: + test_unit_ready(msd_cbw_data); + break; + + case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + test_unit_ready(msd_cbw_data); + // ret = cmd_ignored(scsip, cmd); + break; + + case SCSI_CMD_MODE_SENSE_6: + mode_sense6(msd_cbw_data); + break; + + case SCSI_CMD_READ_FORMAT_CAPACITIES: + read_format_capacities(msd_cbw_data); + break; + + case SCSI_CMD_VERIFY_10: + test_unit_ready(msd_cbw_data); break; /* - case SCSI_CMD_REQUEST_SENSE: - ret = request_sense(scsip, cmd); - break; - - case SCSI_CMD_READ_CAPACITY_10: - ret = read_capacity10(scsip, cmd); - break; - - case SCSI_CMD_READ_10: - ret = data_read_write10(scsip, cmd); - break; - - case SCSI_CMD_WRITE_10: - ret = data_read_write10(scsip, cmd); - break; - - case SCSI_CMD_TEST_UNIT_READY: - ret = test_unit_ready(scsip, cmd); - break; - - case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - ret = cmd_ignored(scsip, cmd); - break; - - case SCSI_CMD_MODE_SENSE_6: - ret = mode_sense6(scsip, cmd); - break; - - case SCSI_CMD_READ_FORMAT_CAPACITIES: - ret = read_format_capacities(scsip, cmd); - break; - - case SCSI_CMD_VERIFY_10: - ret = cmd_ignored(scsip, cmd); - break; - - default: - ret = cmd_unhandled(scsip, cmd); - break; - */ + default: + ret = cmd_unhandled(scsip, cmd); + break; + */ } // if (ret == SCSI_SUCCESS) diff --git a/firmware/baseband/sd_over_usb/scsi.h b/firmware/baseband/sd_over_usb/scsi.h index 616c9aff..85dedd1a 100644 --- a/firmware/baseband/sd_over_usb/scsi.h +++ b/firmware/baseband/sd_over_usb/scsi.h @@ -26,6 +26,36 @@ #define SCSI_CMD_WRITE_10 0x2A #define SCSI_CMD_VERIFY_10 0x2F +#define SCSI_SENSE_KEY_GOOD 0x00 +#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01 +#define SCSI_SENSE_KEY_NOT_READY 0x02 +#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03 +#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04 +#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05 +#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06 +#define SCSI_SENSE_KEY_DATA_PROTECT 0x07 +#define SCSI_SENSE_KEY_BLANK_CHECK 0x08 +#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09 +#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A +#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B +#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D +#define SCSI_SENSE_KEY_MISCOMPARE 0x0E + +#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00 +#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04 +#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24 +#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28 +#define SCSI_ASENSE_WRITE_PROTECTED 0x27 +#define SCSI_ASENSE_FORMAT_ERROR 0x31 +#define SCSI_ASENSE_INVALID_COMMAND 0x20 +#define SCSI_ASENSE_LBA_OUT_OF_RANGE 0x21 +#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A + +#define SCSI_ASENSEQ_NO_QUALIFIER 0x00 +#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01 +#define SCSI_ASENSEQ_INIT_COMMAND_REQUIRED 0x02 +#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07 + #define MSD_CBW_SIGNATURE 0x43425355 #define MSD_CSW_SIGNATURE 0x53425355 @@ -41,6 +71,54 @@ typedef struct { uint8_t cmd_data[16]; } __attribute__((packed)) msd_cbw_t; +static inline uint16_t bswap_16(const uint16_t x) + __attribute__ ((warn_unused_result)) + __attribute__ ((const)) + __attribute__ ((always_inline)); + +static inline uint16_t bswap_16(const uint16_t x) { + + uint8_t tmp; + union { uint16_t x; uint8_t b[2]; } data; + + data.x = x; + tmp = data.b[0]; + data.b[0] = data.b[1]; + data.b[1] = tmp; + + return data.x; +} + +static inline uint32_t bswap_32(const uint32_t x) + __attribute__ ((warn_unused_result)) + __attribute__ ((const)) + __attribute__ ((always_inline)); + + +static inline uint32_t bswap_32(const uint32_t x) { + + uint8_t tmp; + union { uint32_t x; uint8_t b[4]; } data; + + data.x = x; + tmp = data.b[0]; + data.b[0] = data.b[3]; + data.b[3] = tmp; + tmp = data.b[1]; + data.b[1] = data.b[2]; + data.b[2] = tmp; + + return data.x; +} + +#define be16_to_cpu(x) bswap_16(x) +#define be32_to_cpu(x) bswap_32(x) + +#define cpu_to_be16(x) bswap_16(x) +#define cpu_to_be32(x) bswap_32(x) + + + void scsi_command(msd_cbw_t *msd_cbw_data); #endif /* __SCSI_H__ */ \ No newline at end of file