summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrank Gevaerts <frank@gevaerts.be>2008-02-28 22:35:23 +0000
committerFrank Gevaerts <frank@gevaerts.be>2008-02-28 22:35:23 +0000
commit2662f1b3ce4b262e1364630a6202b3147af3a0b7 (patch)
tree15b78c9ce886fe9714ee6a2411d24e6711392d8e
parent4e1f2d3da388a8d77849cbb8192c0d43b4fda6d0 (diff)
- some SCSI/UMS fixes
- don't boost the CPU any more. The USB driver does that - only mark the SD-card slot on sansas removable (decision on what is the right thing to do is still pending) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16448 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/usbstack/usb_storage.c164
1 files changed, 97 insertions, 67 deletions
diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c
index f9051d1b68..9d65f3b908 100644
--- a/firmware/usbstack/usb_storage.c
+++ b/firmware/usbstack/usb_storage.c
@@ -67,9 +67,8 @@
#define SCSI_START_STOP_UNIT 0x1b
#define SCSI_REPORT_LUNS 0xa0
-#define SCSI_STATUS_GOOD 0x00
-#define SCSI_STATUS_FAIL 0x01
-#define SCSI_STATUS_CHECK_CONDITION 0x02
+#define UMS_STATUS_GOOD 0x00
+#define UMS_STATUS_FAIL 0x01
#define SENSE_NOT_READY 0x02
#define SENSE_MEDIUM_ERROR 0x03
@@ -214,7 +213,7 @@ void usb_storage_init(void)
size_t bufsize;
unsigned char * audio_buffer = audio_get_buffer(false,&bufsize);
/* TODO : check if bufsize is at least 32K ? */
- transfer_buffer = (void *)UNCACHED_ADDR((unsigned int)(audio_buffer + 32) & 0xffffffe0);
+ transfer_buffer = (void *)UNCACHED_ADDR((unsigned int)(audio_buffer + 31) & 0xffffffe0);
inquiry = (void*)transfer_buffer;
capacity_data = (void*)transfer_buffer;
format_capacity_data = (void*)transfer_buffer;
@@ -259,14 +258,14 @@ void usb_storage_transfer_complete(bool in,int status,int length)
current_cmd.sector, MIN(BUFFER_SIZE/SECTOR_SIZE,current_cmd.count),
current_cmd.data[current_cmd.data_select]);
if(result != 0) {
- send_csw(SCSI_STATUS_CHECK_CONDITION);
+ send_csw(UMS_STATUS_FAIL);
cur_sense_data.sense_key=SENSE_MEDIUM_ERROR;
cur_sense_data.asc=ASC_WRITE_ERROR;
break;
}
if(next_count==0) {
- send_csw(SCSI_STATUS_GOOD);
+ send_csw(UMS_STATUS_GOOD);
}
/* Switch buffers for the next one */
@@ -278,7 +277,7 @@ void usb_storage_transfer_complete(bool in,int status,int length)
}
else {
logf("Transfer failed %X",status);
- send_csw(SCSI_STATUS_CHECK_CONDITION);
+ send_csw(UMS_STATUS_FAIL);
/* TODO fill in cur_sense_data */
cur_sense_data.sense_key=0;
cur_sense_data.information=0;
@@ -290,7 +289,13 @@ void usb_storage_transfer_complete(bool in,int status,int length)
logf("IN received in WAITING_FOR_COMMAND");
}
//logf("command received");
- handle_scsi(cbw);
+ if(letoh32(cbw->signature) == CBW_SIGNATURE){
+ handle_scsi(cbw);
+ }
+ else {
+ usb_drv_stall(EP_MASS_STORAGE, true,true);
+ usb_drv_stall(EP_MASS_STORAGE, true,false);
+ }
break;
case SENDING_CSW:
if(in==false) {
@@ -306,11 +311,11 @@ void usb_storage_transfer_complete(bool in,int status,int length)
}
if(status==0) {
//logf("data sent, now send csw");
- send_csw(SCSI_STATUS_GOOD);
+ send_csw(UMS_STATUS_GOOD);
}
else {
logf("Transfer failed %X",status);
- send_csw(SCSI_STATUS_CHECK_CONDITION);
+ send_csw(UMS_STATUS_FAIL);
/* TODO fill in cur_sense_data */
cur_sense_data.sense_key=0;
cur_sense_data.information=0;
@@ -324,7 +329,7 @@ void usb_storage_transfer_complete(bool in,int status,int length)
if(status==0) {
if(current_cmd.count==0) {
//logf("data sent, now send csw");
- send_csw(SCSI_STATUS_GOOD);
+ send_csw(UMS_STATUS_GOOD);
}
else {
send_and_read_next();
@@ -332,7 +337,7 @@ void usb_storage_transfer_complete(bool in,int status,int length)
}
else {
logf("Transfer failed %X",status);
- send_csw(SCSI_STATUS_CHECK_CONDITION);
+ send_csw(UMS_STATUS_FAIL);
/* TODO fill in cur_sense_data */
cur_sense_data.sense_key=0;
cur_sense_data.information=0;
@@ -354,13 +359,6 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req)
#else
*max_lun = NUM_VOLUMES - 1;
#endif
-#ifdef HAVE_HOTSWAP
- /* Workaround until we find out how to do removable devices properly */
- tCardInfo* cinfo = card_get_info(1);
- if(cinfo->initialized==0) {
- *max_lun=0;
- }
-#endif
logf("ums: getmaxlun");
usb_drv_send(EP_CONTROL, UNCACHED_ADDR(max_lun), 1);
usb_drv_recv(EP_CONTROL, NULL, 0); /* ack */
@@ -370,8 +368,15 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req)
case USB_BULK_RESET_REQUEST:
logf("ums: bulk reset");
+ state = WAITING_FOR_COMMAND;
+ /* UMS BOT 3.1 says The device shall preserve the value of its bulk
+ * data toggle bits and endpoint STALL conditions despite the Bulk-Only
+ * Mass Storage Reset. */
+#if 0
usb_drv_reset_endpoint(EP_MASS_STORAGE, false);
usb_drv_reset_endpoint(EP_MASS_STORAGE, true);
+#endif
+
usb_drv_send(EP_CONTROL, NULL, 0); /* ack */
handled = true;
break;
@@ -392,7 +397,7 @@ static void send_and_read_next(void)
{
if(current_cmd.last_result!=0) {
/* The last read failed. */
- send_csw(SCSI_STATUS_CHECK_CONDITION);
+ send_csw(UMS_STATUS_FAIL);
cur_sense_data.sense_key=SENSE_MEDIUM_ERROR;
cur_sense_data.asc=ASC_READ_ERROR;
return;
@@ -433,7 +438,7 @@ static void handle_scsi(struct command_block_wrapper* cbw)
unsigned int block_size_mult = 1;
#ifdef HAVE_HOTSWAP
tCardInfo* cinfo = card_get_info(lun);
- if(cinfo->initialized==1) {
+ if(cinfo->initialized==1 && cinfo->numblocks > 0) {
block_size = cinfo->blocksize;
block_count = cinfo->numblocks;
}
@@ -458,17 +463,14 @@ static void handle_scsi(struct command_block_wrapper* cbw)
switch (cbw->command_block[0]) {
case SCSI_TEST_UNIT_READY:
logf("scsi test_unit_ready %d",lun);
-#ifdef HAVE_HOTSWAP
- if(cinfo->initialized==1)
- send_csw(SCSI_STATUS_GOOD);
+ if(lun_present) {
+ send_csw(UMS_STATUS_GOOD);
+ }
else {
- send_csw(SCSI_STATUS_FAIL);
+ send_csw(UMS_STATUS_FAIL);
cur_sense_data.sense_key=SENSE_NOT_READY;
cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT;
}
-#else
- send_csw(SCSI_STATUS_GOOD);
-#endif
break;
case SCSI_REPORT_LUNS: {
@@ -515,12 +517,18 @@ static void handle_scsi(struct command_block_wrapper* cbw)
}
case SCSI_MODE_SENSE_10: {
+ if(! lun_present) {
+ usb_drv_stall(EP_MASS_STORAGE, true,true);
+ send_csw(UMS_STATUS_FAIL);
+ cur_sense_data.sense_key=SENSE_NOT_READY;
+ cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT;
+ break;
+ }
/*unsigned char pc = (cbw->command_block[2] & 0xc0) >>6;*/
unsigned char page_code = cbw->command_block[2] & 0x3f;
logf("scsi mode_sense_10 %d %X",lun,page_code);
switch(page_code) {
case 0x3f:
- default:
mode_sense_data_10->mode_data_length=0;
mode_sense_data_10->medium_type=0;
mode_sense_data_10->device_specific=0;
@@ -528,23 +536,28 @@ static void handle_scsi(struct command_block_wrapper* cbw)
send_command_result(mode_sense_data_10,
MIN(sizeof(struct mode_sense_header_10), length));
break;
-#if 0
default:
- send_csw(SCSI_STATUS_CHECK_CONDITION);
+ usb_drv_stall(EP_MASS_STORAGE, true,true);
+ send_csw(UMS_STATUS_FAIL);
cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST;
cur_sense_data.asc=ASC_INVALID_FIELD_IN_CBD;
break;
-#endif
}
break;
}
case SCSI_MODE_SENSE_6: {
+ if(! lun_present) {
+ usb_drv_stall(EP_MASS_STORAGE, true,true);
+ send_csw(UMS_STATUS_FAIL);
+ cur_sense_data.sense_key=SENSE_NOT_READY;
+ cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT;
+ break;
+ }
/*unsigned char pc = (cbw->command_block[2] & 0xc0) >>6;*/
unsigned char page_code = cbw->command_block[2] & 0x3f;
logf("scsi mode_sense_6 %d %X",lun,page_code);
switch(page_code) {
case 0x3f:
- default:
/* All supported pages Since we support only one this is easy*/
mode_sense_data_6->mode_data_length=0;
mode_sense_data_6->medium_type=0;
@@ -553,61 +566,77 @@ static void handle_scsi(struct command_block_wrapper* cbw)
send_command_result(mode_sense_data_6,
MIN(sizeof(struct mode_sense_header_6), length));
break;
-#if 0
+ /* TODO : windows does 1A, Power Condition. Do we need that ? */
default:
- send_csw(SCSI_STATUS_CHECK_CONDITION);
+ usb_drv_stall(EP_MASS_STORAGE, true,true);
+ send_csw(UMS_STATUS_FAIL);
cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST;
cur_sense_data.asc=ASC_INVALID_FIELD_IN_CBD;
break;
-#endif
}
break;
}
case SCSI_START_STOP_UNIT:
logf("scsi start_stop unit %d",lun);
- send_csw(SCSI_STATUS_GOOD);
+ send_csw(UMS_STATUS_GOOD);
break;
case SCSI_ALLOW_MEDIUM_REMOVAL:
logf("scsi allow_medium_removal %d",lun);
/* TODO: use this to show the connect screen ? */
- send_csw(SCSI_STATUS_GOOD);
+ send_csw(UMS_STATUS_GOOD);
break;
-
case SCSI_READ_FORMAT_CAPACITY: {
logf("scsi read_format_capacity %d",lun);
- format_capacity_data->following_length=htobe32(8);
- /* Careful: "block count" actually means "number of last block" */
- format_capacity_data->block_count = htobe32(block_count/block_size_mult - 1);
- format_capacity_data->block_size = htobe32(block_size*block_size_mult);
- format_capacity_data->block_size |= SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA;
-
- send_command_result(format_capacity_data,
- MIN(sizeof(struct format_capacity), length));
-
+ if(lun_present) {
+ format_capacity_data->following_length=htobe32(8);
+ /* Careful: "block count" actually means "number of last block" */
+ format_capacity_data->block_count = htobe32(block_count/block_size_mult - 1);
+ format_capacity_data->block_size = htobe32(block_size*block_size_mult);
+ format_capacity_data->block_size |= SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA;
+
+ send_command_result(format_capacity_data,
+ MIN(sizeof(struct format_capacity), length));
+ }
+ else
+ {
+ usb_drv_stall(EP_MASS_STORAGE, true,true);
+ send_csw(UMS_STATUS_FAIL);
+ cur_sense_data.sense_key=SENSE_NOT_READY;
+ cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT;
+ }
break;
}
-
case SCSI_READ_CAPACITY: {
logf("scsi read_capacity %d",lun);
- /* Careful: "block count" actually means "number of last block" */
- capacity_data->block_count = htobe32(block_count/block_size_mult - 1);
- capacity_data->block_size = htobe32(block_size*block_size_mult);
- send_command_result(capacity_data, MIN(sizeof(struct capacity), length));
+ if(lun_present) {
+ /* Careful: "block count" actually means "number of last block" */
+ capacity_data->block_count = htobe32(block_count/block_size_mult - 1);
+ capacity_data->block_size = htobe32(block_size*block_size_mult);
+
+ send_command_result(capacity_data, MIN(sizeof(struct capacity), length));
+ }
+ else
+ {
+ usb_drv_stall(EP_MASS_STORAGE, true,true);
+ send_csw(UMS_STATUS_FAIL);
+ cur_sense_data.sense_key=SENSE_NOT_READY;
+ cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT;
+ }
break;
}
case SCSI_READ_10:
logf("scsi read10 %d",lun);
if(! lun_present) {
- send_csw(SCSI_STATUS_CHECK_CONDITION);
+ usb_drv_stall(EP_MASS_STORAGE, true,true);
+ send_csw(UMS_STATUS_FAIL);
cur_sense_data.sense_key=SENSE_NOT_READY;
cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT;
break;
}
- trigger_cpu_boost();
current_cmd.data[0] = transfer_buffer;
current_cmd.data[1] = &transfer_buffer[BUFFER_SIZE];
current_cmd.data_select=0;
@@ -620,15 +649,15 @@ static void handle_scsi(struct command_block_wrapper* cbw)
(cbw->command_block[7] << 16 |
cbw->command_block[8]);
- logf("scsi read %d %d", current_cmd.sector, current_cmd.count);
+ //logf("scsi read %d %d", current_cmd.sector, current_cmd.count);
if((current_cmd.sector + current_cmd.count) > block_count) {
- send_csw(SCSI_STATUS_CHECK_CONDITION);
+ usb_drv_stall(EP_MASS_STORAGE, true,true);
+ send_csw(UMS_STATUS_FAIL);
cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST;
cur_sense_data.asc=ASC_LBA_OUT_OF_RANGE;
}
else {
- /* TODO: any way to do this nonblocking ? */
current_cmd.last_result = ata_read_sectors(IF_MV2(current_cmd.lun,) current_cmd.sector,
MIN(BUFFER_SIZE/SECTOR_SIZE,current_cmd.count),
current_cmd.data[current_cmd.data_select]);
@@ -639,12 +668,12 @@ static void handle_scsi(struct command_block_wrapper* cbw)
case SCSI_WRITE_10:
logf("scsi write10 %d",lun);
if(! lun_present) {
- send_csw(SCSI_STATUS_CHECK_CONDITION);
+ usb_drv_stall(EP_MASS_STORAGE, true,true);
+ send_csw(UMS_STATUS_FAIL);
cur_sense_data.sense_key=SENSE_NOT_READY;
cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT;
break;
}
- trigger_cpu_boost();
current_cmd.data[0] = transfer_buffer;
current_cmd.data[1] = &transfer_buffer[BUFFER_SIZE];
current_cmd.data_select=0;
@@ -658,7 +687,8 @@ static void handle_scsi(struct command_block_wrapper* cbw)
cbw->command_block[8]);
/* expect data */
if((current_cmd.sector + current_cmd.count) > block_count) {
- send_csw(SCSI_STATUS_CHECK_CONDITION);
+ usb_drv_stall(EP_MASS_STORAGE, true,true);
+ send_csw(UMS_STATUS_FAIL);
cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST;
cur_sense_data.asc=ASC_LBA_OUT_OF_RANGE;
}
@@ -672,7 +702,7 @@ static void handle_scsi(struct command_block_wrapper* cbw)
default:
logf("scsi unknown cmd %x",cbw->command_block[0x0]);
usb_drv_stall(EP_MASS_STORAGE, true,true);
- send_csw(SCSI_STATUS_GOOD);
+ send_csw(UMS_STATUS_FAIL);
break;
}
}
@@ -697,17 +727,16 @@ static void receive_block_data(void *data,int size)
static void send_csw(int status)
{
- cancel_cpu_boost();
- csw->signature = CSW_SIGNATURE;
+ csw->signature = htole32(CSW_SIGNATURE);
csw->tag = current_cmd.tag;
csw->data_residue = 0;
csw->status = status;
usb_drv_send_nonblocking(EP_MASS_STORAGE, csw, sizeof(struct command_status_wrapper));
state = SENDING_CSW;
- logf("CSW: %X",status);
+ //logf("CSW: %X",status);
- if(status == SCSI_STATUS_GOOD) {
+ if(status == UMS_STATUS_GOOD) {
cur_sense_data.sense_key=0;
cur_sense_data.information=0;
cur_sense_data.asc=0;
@@ -759,7 +788,8 @@ static void identify2inquiry(int lun)
inquiry->Format = 2; /* SPC-2/3 inquiry format */
#ifdef HAVE_HOTSWAP
- inquiry->DeviceTypeModifier = DEVICE_REMOVABLE;
+ if(lun>0)
+ inquiry->DeviceTypeModifier = DEVICE_REMOVABLE;
#endif
}