diff options
Diffstat (limited to 'firmware/usbstack/usb_storage.c')
-rw-r--r-- | firmware/usbstack/usb_storage.c | 116 |
1 files changed, 108 insertions, 8 deletions
diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c index 81d90d01db..e226c15f99 100644 --- a/firmware/usbstack/usb_storage.c +++ b/firmware/usbstack/usb_storage.c | |||
@@ -114,6 +114,9 @@ | |||
114 | #define SCSI_REPORT_LUNS 0xa0 | 114 | #define SCSI_REPORT_LUNS 0xa0 |
115 | #define SCSI_WRITE_BUFFER 0x3b | 115 | #define SCSI_WRITE_BUFFER 0x3b |
116 | 116 | ||
117 | #define SCSI_READ_16 0x88 | ||
118 | #define SCSI_WRITE_16 0x8a | ||
119 | |||
117 | #define UMS_STATUS_GOOD 0x00 | 120 | #define UMS_STATUS_GOOD 0x00 |
118 | #define UMS_STATUS_FAIL 0x01 | 121 | #define UMS_STATUS_FAIL 0x01 |
119 | 122 | ||
@@ -273,7 +276,7 @@ static union { | |||
273 | static char *cbw_buffer; | 276 | static char *cbw_buffer; |
274 | 277 | ||
275 | static struct { | 278 | static struct { |
276 | unsigned int sector; | 279 | sector_t sector; |
277 | unsigned int count; | 280 | unsigned int count; |
278 | unsigned int orig_count; | 281 | unsigned int orig_count; |
279 | unsigned int cur_cmd; | 282 | unsigned int cur_cmd; |
@@ -503,7 +506,7 @@ void usb_storage_transfer_complete(int ep,int dir,int status,int length) | |||
503 | if(dir==USB_DIR_IN) { | 506 | if(dir==USB_DIR_IN) { |
504 | logf("IN received in RECEIVING"); | 507 | logf("IN received in RECEIVING"); |
505 | } | 508 | } |
506 | logf("scsi write %d %d", cur_cmd.sector, cur_cmd.count); | 509 | logf("scsi write %llu %d", cur_cmd.sector, cur_cmd.count); |
507 | if(status==0) { | 510 | if(status==0) { |
508 | if((unsigned int)length!=(SECTOR_SIZE* cur_cmd.count) | 511 | if((unsigned int)length!=(SECTOR_SIZE* cur_cmd.count) |
509 | && (unsigned int)length!=WRITE_BUFFER_SIZE) { | 512 | && (unsigned int)length!=WRITE_BUFFER_SIZE) { |
@@ -511,7 +514,7 @@ void usb_storage_transfer_complete(int ep,int dir,int status,int length) | |||
511 | break; | 514 | break; |
512 | } | 515 | } |
513 | 516 | ||
514 | unsigned int next_sector = cur_cmd.sector + | 517 | sector_t next_sector = cur_cmd.sector + |
515 | (WRITE_BUFFER_SIZE/SECTOR_SIZE); | 518 | (WRITE_BUFFER_SIZE/SECTOR_SIZE); |
516 | unsigned int next_count = cur_cmd.count - | 519 | unsigned int next_count = cur_cmd.count - |
517 | MIN(cur_cmd.count,WRITE_BUFFER_SIZE/SECTOR_SIZE); | 520 | MIN(cur_cmd.count,WRITE_BUFFER_SIZE/SECTOR_SIZE); |
@@ -739,12 +742,10 @@ static void send_and_read_next(void) | |||
739 | 742 | ||
740 | static void handle_scsi(struct command_block_wrapper* cbw) | 743 | static void handle_scsi(struct command_block_wrapper* cbw) |
741 | { | 744 | { |
742 | /* USB Mass Storage assumes LBA capability. | ||
743 | TODO: support 48-bit LBA */ | ||
744 | |||
745 | struct storage_info info; | 745 | struct storage_info info; |
746 | unsigned int length = cbw->data_transfer_length; | 746 | unsigned int length = cbw->data_transfer_length; |
747 | unsigned int block_size, block_count; | 747 | sector_t block_count; |
748 | unsigned int block_size; | ||
748 | bool lun_present=true; | 749 | bool lun_present=true; |
749 | unsigned char lun = cbw->lun; | 750 | unsigned char lun = cbw->lun; |
750 | unsigned int block_size_mult = 1; | 751 | unsigned int block_size_mult = 1; |
@@ -888,6 +889,12 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
888 | memset(tb.ms_data_10->block_descriptor.reserved,0,4); | 889 | memset(tb.ms_data_10->block_descriptor.reserved,0,4); |
889 | memset(tb.ms_data_10->block_descriptor.num_blocks,0,8); | 890 | memset(tb.ms_data_10->block_descriptor.num_blocks,0,8); |
890 | 891 | ||
892 | #ifdef STORAGE_64BIT_SECTOR | ||
893 | tb.ms_data_10->block_descriptor.num_blocks[2] = | ||
894 | ((block_count/block_size_mult) & 0xff00000000ULL)>>40; | ||
895 | tb.ms_data_10->block_descriptor.num_blocks[3] = | ||
896 | ((block_count/block_size_mult) & 0x00ff000000ULL)>>32; | ||
897 | #endif | ||
891 | tb.ms_data_10->block_descriptor.num_blocks[4] = | 898 | tb.ms_data_10->block_descriptor.num_blocks[4] = |
892 | ((block_count/block_size_mult) & 0xff000000)>>24; | 899 | ((block_count/block_size_mult) & 0xff000000)>>24; |
893 | tb.ms_data_10->block_descriptor.num_blocks[5] = | 900 | tb.ms_data_10->block_descriptor.num_blocks[5] = |
@@ -1070,7 +1077,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
1070 | cbw->command_block[8]); | 1077 | cbw->command_block[8]); |
1071 | cur_cmd.orig_count = cur_cmd.count; | 1078 | cur_cmd.orig_count = cur_cmd.count; |
1072 | 1079 | ||
1073 | //logf("scsi read %d %d", cur_cmd.sector, cur_cmd.count); | 1080 | logf("scsi read %llu %d", cur_cmd.sector, cur_cmd.count); |
1074 | 1081 | ||
1075 | if((cur_cmd.sector + cur_cmd.count) > block_count) { | 1082 | if((cur_cmd.sector + cur_cmd.count) > block_count) { |
1076 | send_csw(UMS_STATUS_FAIL); | 1083 | send_csw(UMS_STATUS_FAIL); |
@@ -1092,7 +1099,58 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
1092 | send_and_read_next(); | 1099 | send_and_read_next(); |
1093 | } | 1100 | } |
1094 | break; | 1101 | break; |
1102 | #ifdef STORAGE_64BIT_SECTOR | ||
1103 | case SCSI_READ_16: | ||
1104 | logf("scsi read16 %d",lun); | ||
1105 | if(!lun_present) { | ||
1106 | send_command_failed_result(); | ||
1107 | cur_sense_data.sense_key=SENSE_NOT_READY; | ||
1108 | cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; | ||
1109 | cur_sense_data.ascq=0; | ||
1110 | break; | ||
1111 | } | ||
1112 | cur_cmd.data[0] = tb.transfer_buffer; | ||
1113 | cur_cmd.data[1] = &tb.transfer_buffer[READ_BUFFER_SIZE]; | ||
1114 | cur_cmd.data_select=0; | ||
1115 | cur_cmd.sector = block_size_mult * | ||
1116 | ((uint64_t)cbw->command_block[2] << 56 | | ||
1117 | (uint64_t)cbw->command_block[3] << 48 | | ||
1118 | (uint64_t)cbw->command_block[4] << 40 | | ||
1119 | (uint64_t)cbw->command_block[5] << 32 | | ||
1120 | cbw->command_block[6] << 24 | | ||
1121 | cbw->command_block[7] << 16 | | ||
1122 | cbw->command_block[8] << 8 | | ||
1123 | cbw->command_block[9]); | ||
1124 | cur_cmd.count = block_size_mult * | ||
1125 | (cbw->command_block[10] << 24 | | ||
1126 | cbw->command_block[11] << 16 | | ||
1127 | cbw->command_block[12] << 8 | | ||
1128 | cbw->command_block[13]); | ||
1129 | cur_cmd.orig_count = cur_cmd.count; | ||
1095 | 1130 | ||
1131 | logf("scsi read %llu %d", cur_cmd.sector, cur_cmd.count); | ||
1132 | |||
1133 | if((cur_cmd.sector + cur_cmd.count) > block_count) { | ||
1134 | send_csw(UMS_STATUS_FAIL); | ||
1135 | cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST; | ||
1136 | cur_sense_data.asc=ASC_LBA_OUT_OF_RANGE; | ||
1137 | cur_sense_data.ascq=0; | ||
1138 | } | ||
1139 | else { | ||
1140 | #ifdef USB_USE_RAMDISK | ||
1141 | memcpy(cur_cmd.data[cur_cmd.data_select], | ||
1142 | ramdisk_buffer + cur_cmd.sector*SECTOR_SIZE, | ||
1143 | MIN(READ_BUFFER_SIZE/SECTOR_SIZE,cur_cmd.count)*SECTOR_SIZE); | ||
1144 | #else | ||
1145 | cur_cmd.last_result = storage_read_sectors(IF_MD(cur_cmd.lun,) | ||
1146 | cur_cmd.sector, | ||
1147 | MIN(READ_BUFFER_SIZE/SECTOR_SIZE, cur_cmd.count), | ||
1148 | cur_cmd.data[cur_cmd.data_select]); | ||
1149 | #endif | ||
1150 | send_and_read_next(); | ||
1151 | } | ||
1152 | break; | ||
1153 | #endif | ||
1096 | case SCSI_WRITE_10: | 1154 | case SCSI_WRITE_10: |
1097 | logf("scsi write10 %d",lun); | 1155 | logf("scsi write10 %d",lun); |
1098 | if(!lun_present) { | 1156 | if(!lun_present) { |
@@ -1127,6 +1185,48 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
1127 | MIN(WRITE_BUFFER_SIZE, cur_cmd.count*SECTOR_SIZE)); | 1185 | MIN(WRITE_BUFFER_SIZE, cur_cmd.count*SECTOR_SIZE)); |
1128 | } | 1186 | } |
1129 | break; | 1187 | break; |
1188 | #ifdef STORAGE_64BIT_SECTOR | ||
1189 | case SCSI_WRITE_16: | ||
1190 | logf("scsi write16 %d",lun); | ||
1191 | if(!lun_present) { | ||
1192 | send_csw(UMS_STATUS_FAIL); | ||
1193 | cur_sense_data.sense_key=SENSE_NOT_READY; | ||
1194 | cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; | ||
1195 | cur_sense_data.ascq=0; | ||
1196 | break; | ||
1197 | } | ||
1198 | cur_cmd.data[0] = tb.transfer_buffer; | ||
1199 | cur_cmd.data[1] = &tb.transfer_buffer[WRITE_BUFFER_SIZE]; | ||
1200 | cur_cmd.data_select=0; | ||
1201 | cur_cmd.sector = block_size_mult * | ||
1202 | ((uint64_t)cbw->command_block[2] << 56 | | ||
1203 | (uint64_t)cbw->command_block[3] << 48 | | ||
1204 | (uint64_t)cbw->command_block[4] << 40 | | ||
1205 | (uint64_t)cbw->command_block[5] << 32 | | ||
1206 | cbw->command_block[6] << 24 | | ||
1207 | cbw->command_block[7] << 16 | | ||
1208 | cbw->command_block[8] << 8 | | ||
1209 | cbw->command_block[9]); | ||
1210 | cur_cmd.count = block_size_mult * | ||
1211 | (cbw->command_block[10] << 24 | | ||
1212 | cbw->command_block[11] << 16 | | ||
1213 | cbw->command_block[12] << 8 | | ||
1214 | cbw->command_block[13]); | ||
1215 | cur_cmd.orig_count = cur_cmd.count; | ||
1216 | |||
1217 | /* expect data */ | ||
1218 | if((cur_cmd.sector + cur_cmd.count) > block_count) { | ||
1219 | send_csw(UMS_STATUS_FAIL); | ||
1220 | cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST; | ||
1221 | cur_sense_data.asc=ASC_LBA_OUT_OF_RANGE; | ||
1222 | cur_sense_data.ascq=0; | ||
1223 | } | ||
1224 | else { | ||
1225 | receive_block_data(cur_cmd.data[0], | ||
1226 | MIN(WRITE_BUFFER_SIZE, cur_cmd.count*SECTOR_SIZE)); | ||
1227 | } | ||
1228 | break; | ||
1229 | #endif | ||
1130 | 1230 | ||
1131 | #if CONFIG_RTC | 1231 | #if CONFIG_RTC |
1132 | case SCSI_WRITE_BUFFER: | 1232 | case SCSI_WRITE_BUFFER: |