1
0
Fork 0
forked from len0rd/rockbox

- 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
This commit is contained in:
Frank Gevaerts 2008-02-28 22:35:23 +00:00
parent 4e1f2d3da3
commit 2662f1b3ce

View file

@ -67,9 +67,8 @@
#define SCSI_START_STOP_UNIT 0x1b #define SCSI_START_STOP_UNIT 0x1b
#define SCSI_REPORT_LUNS 0xa0 #define SCSI_REPORT_LUNS 0xa0
#define SCSI_STATUS_GOOD 0x00 #define UMS_STATUS_GOOD 0x00
#define SCSI_STATUS_FAIL 0x01 #define UMS_STATUS_FAIL 0x01
#define SCSI_STATUS_CHECK_CONDITION 0x02
#define SENSE_NOT_READY 0x02 #define SENSE_NOT_READY 0x02
#define SENSE_MEDIUM_ERROR 0x03 #define SENSE_MEDIUM_ERROR 0x03
@ -214,7 +213,7 @@ void usb_storage_init(void)
size_t bufsize; size_t bufsize;
unsigned char * audio_buffer = audio_get_buffer(false,&bufsize); unsigned char * audio_buffer = audio_get_buffer(false,&bufsize);
/* TODO : check if bufsize is at least 32K ? */ /* 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; inquiry = (void*)transfer_buffer;
capacity_data = (void*)transfer_buffer; capacity_data = (void*)transfer_buffer;
format_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.sector, MIN(BUFFER_SIZE/SECTOR_SIZE,current_cmd.count),
current_cmd.data[current_cmd.data_select]); current_cmd.data[current_cmd.data_select]);
if(result != 0) { 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.sense_key=SENSE_MEDIUM_ERROR;
cur_sense_data.asc=ASC_WRITE_ERROR; cur_sense_data.asc=ASC_WRITE_ERROR;
break; break;
} }
if(next_count==0) { if(next_count==0) {
send_csw(SCSI_STATUS_GOOD); send_csw(UMS_STATUS_GOOD);
} }
/* Switch buffers for the next one */ /* Switch buffers for the next one */
@ -278,7 +277,7 @@ void usb_storage_transfer_complete(bool in,int status,int length)
} }
else { else {
logf("Transfer failed %X",status); logf("Transfer failed %X",status);
send_csw(SCSI_STATUS_CHECK_CONDITION); send_csw(UMS_STATUS_FAIL);
/* TODO fill in cur_sense_data */ /* TODO fill in cur_sense_data */
cur_sense_data.sense_key=0; cur_sense_data.sense_key=0;
cur_sense_data.information=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("IN received in WAITING_FOR_COMMAND");
} }
//logf("command received"); //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; break;
case SENDING_CSW: case SENDING_CSW:
if(in==false) { if(in==false) {
@ -306,11 +311,11 @@ void usb_storage_transfer_complete(bool in,int status,int length)
} }
if(status==0) { if(status==0) {
//logf("data sent, now send csw"); //logf("data sent, now send csw");
send_csw(SCSI_STATUS_GOOD); send_csw(UMS_STATUS_GOOD);
} }
else { else {
logf("Transfer failed %X",status); logf("Transfer failed %X",status);
send_csw(SCSI_STATUS_CHECK_CONDITION); send_csw(UMS_STATUS_FAIL);
/* TODO fill in cur_sense_data */ /* TODO fill in cur_sense_data */
cur_sense_data.sense_key=0; cur_sense_data.sense_key=0;
cur_sense_data.information=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(status==0) {
if(current_cmd.count==0) { if(current_cmd.count==0) {
//logf("data sent, now send csw"); //logf("data sent, now send csw");
send_csw(SCSI_STATUS_GOOD); send_csw(UMS_STATUS_GOOD);
} }
else { else {
send_and_read_next(); send_and_read_next();
@ -332,7 +337,7 @@ void usb_storage_transfer_complete(bool in,int status,int length)
} }
else { else {
logf("Transfer failed %X",status); logf("Transfer failed %X",status);
send_csw(SCSI_STATUS_CHECK_CONDITION); send_csw(UMS_STATUS_FAIL);
/* TODO fill in cur_sense_data */ /* TODO fill in cur_sense_data */
cur_sense_data.sense_key=0; cur_sense_data.sense_key=0;
cur_sense_data.information=0; cur_sense_data.information=0;
@ -353,13 +358,6 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req)
*max_lun = 0; *max_lun = 0;
#else #else
*max_lun = NUM_VOLUMES - 1; *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 #endif
logf("ums: getmaxlun"); logf("ums: getmaxlun");
usb_drv_send(EP_CONTROL, UNCACHED_ADDR(max_lun), 1); usb_drv_send(EP_CONTROL, UNCACHED_ADDR(max_lun), 1);
@ -370,8 +368,15 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req)
case USB_BULK_RESET_REQUEST: case USB_BULK_RESET_REQUEST:
logf("ums: bulk reset"); 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, false);
usb_drv_reset_endpoint(EP_MASS_STORAGE, true); usb_drv_reset_endpoint(EP_MASS_STORAGE, true);
#endif
usb_drv_send(EP_CONTROL, NULL, 0); /* ack */ usb_drv_send(EP_CONTROL, NULL, 0); /* ack */
handled = true; handled = true;
break; break;
@ -392,7 +397,7 @@ static void send_and_read_next(void)
{ {
if(current_cmd.last_result!=0) { if(current_cmd.last_result!=0) {
/* The last read failed. */ /* 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.sense_key=SENSE_MEDIUM_ERROR;
cur_sense_data.asc=ASC_READ_ERROR; cur_sense_data.asc=ASC_READ_ERROR;
return; return;
@ -433,7 +438,7 @@ static void handle_scsi(struct command_block_wrapper* cbw)
unsigned int block_size_mult = 1; unsigned int block_size_mult = 1;
#ifdef HAVE_HOTSWAP #ifdef HAVE_HOTSWAP
tCardInfo* cinfo = card_get_info(lun); tCardInfo* cinfo = card_get_info(lun);
if(cinfo->initialized==1) { if(cinfo->initialized==1 && cinfo->numblocks > 0) {
block_size = cinfo->blocksize; block_size = cinfo->blocksize;
block_count = cinfo->numblocks; block_count = cinfo->numblocks;
} }
@ -458,17 +463,14 @@ static void handle_scsi(struct command_block_wrapper* cbw)
switch (cbw->command_block[0]) { switch (cbw->command_block[0]) {
case SCSI_TEST_UNIT_READY: case SCSI_TEST_UNIT_READY:
logf("scsi test_unit_ready %d",lun); logf("scsi test_unit_ready %d",lun);
#ifdef HAVE_HOTSWAP if(lun_present) {
if(cinfo->initialized==1) send_csw(UMS_STATUS_GOOD);
send_csw(SCSI_STATUS_GOOD); }
else { else {
send_csw(SCSI_STATUS_FAIL); send_csw(UMS_STATUS_FAIL);
cur_sense_data.sense_key=SENSE_NOT_READY; cur_sense_data.sense_key=SENSE_NOT_READY;
cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT;
} }
#else
send_csw(SCSI_STATUS_GOOD);
#endif
break; break;
case SCSI_REPORT_LUNS: { case SCSI_REPORT_LUNS: {
@ -515,12 +517,18 @@ static void handle_scsi(struct command_block_wrapper* cbw)
} }
case SCSI_MODE_SENSE_10: { 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 pc = (cbw->command_block[2] & 0xc0) >>6;*/
unsigned char page_code = cbw->command_block[2] & 0x3f; unsigned char page_code = cbw->command_block[2] & 0x3f;
logf("scsi mode_sense_10 %d %X",lun,page_code); logf("scsi mode_sense_10 %d %X",lun,page_code);
switch(page_code) { switch(page_code) {
case 0x3f: case 0x3f:
default:
mode_sense_data_10->mode_data_length=0; mode_sense_data_10->mode_data_length=0;
mode_sense_data_10->medium_type=0; mode_sense_data_10->medium_type=0;
mode_sense_data_10->device_specific=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, send_command_result(mode_sense_data_10,
MIN(sizeof(struct mode_sense_header_10), length)); MIN(sizeof(struct mode_sense_header_10), length));
break; break;
#if 0
default: 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.sense_key=SENSE_ILLEGAL_REQUEST;
cur_sense_data.asc=ASC_INVALID_FIELD_IN_CBD; cur_sense_data.asc=ASC_INVALID_FIELD_IN_CBD;
break; break;
#endif
} }
break; break;
} }
case SCSI_MODE_SENSE_6: { 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 pc = (cbw->command_block[2] & 0xc0) >>6;*/
unsigned char page_code = cbw->command_block[2] & 0x3f; unsigned char page_code = cbw->command_block[2] & 0x3f;
logf("scsi mode_sense_6 %d %X",lun,page_code); logf("scsi mode_sense_6 %d %X",lun,page_code);
switch(page_code) { switch(page_code) {
case 0x3f: case 0x3f:
default:
/* All supported pages Since we support only one this is easy*/ /* All supported pages Since we support only one this is easy*/
mode_sense_data_6->mode_data_length=0; mode_sense_data_6->mode_data_length=0;
mode_sense_data_6->medium_type=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, send_command_result(mode_sense_data_6,
MIN(sizeof(struct mode_sense_header_6), length)); MIN(sizeof(struct mode_sense_header_6), length));
break; break;
#if 0 /* TODO : windows does 1A, Power Condition. Do we need that ? */
default: 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.sense_key=SENSE_ILLEGAL_REQUEST;
cur_sense_data.asc=ASC_INVALID_FIELD_IN_CBD; cur_sense_data.asc=ASC_INVALID_FIELD_IN_CBD;
break; break;
#endif
} }
break; break;
} }
case SCSI_START_STOP_UNIT: case SCSI_START_STOP_UNIT:
logf("scsi start_stop unit %d",lun); logf("scsi start_stop unit %d",lun);
send_csw(SCSI_STATUS_GOOD); send_csw(UMS_STATUS_GOOD);
break; break;
case SCSI_ALLOW_MEDIUM_REMOVAL: case SCSI_ALLOW_MEDIUM_REMOVAL:
logf("scsi allow_medium_removal %d",lun); logf("scsi allow_medium_removal %d",lun);
/* TODO: use this to show the connect screen ? */ /* TODO: use this to show the connect screen ? */
send_csw(SCSI_STATUS_GOOD); send_csw(UMS_STATUS_GOOD);
break; break;
case SCSI_READ_FORMAT_CAPACITY: { case SCSI_READ_FORMAT_CAPACITY: {
logf("scsi read_format_capacity %d",lun); logf("scsi read_format_capacity %d",lun);
format_capacity_data->following_length=htobe32(8); if(lun_present) {
/* Careful: "block count" actually means "number of last block" */ format_capacity_data->following_length=htobe32(8);
format_capacity_data->block_count = htobe32(block_count/block_size_mult - 1); /* Careful: "block count" actually means "number of last block" */
format_capacity_data->block_size = htobe32(block_size*block_size_mult); format_capacity_data->block_count = htobe32(block_count/block_size_mult - 1);
format_capacity_data->block_size |= SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA; 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));
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; break;
} }
case SCSI_READ_CAPACITY: { case SCSI_READ_CAPACITY: {
logf("scsi read_capacity %d",lun); 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; break;
} }
case SCSI_READ_10: case SCSI_READ_10:
logf("scsi read10 %d",lun); logf("scsi read10 %d",lun);
if(! lun_present) { 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.sense_key=SENSE_NOT_READY;
cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT;
break; break;
} }
trigger_cpu_boost();
current_cmd.data[0] = transfer_buffer; current_cmd.data[0] = transfer_buffer;
current_cmd.data[1] = &transfer_buffer[BUFFER_SIZE]; current_cmd.data[1] = &transfer_buffer[BUFFER_SIZE];
current_cmd.data_select=0; 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[7] << 16 |
cbw->command_block[8]); 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) { 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.sense_key=SENSE_ILLEGAL_REQUEST;
cur_sense_data.asc=ASC_LBA_OUT_OF_RANGE; cur_sense_data.asc=ASC_LBA_OUT_OF_RANGE;
} }
else { else {
/* TODO: any way to do this nonblocking ? */
current_cmd.last_result = ata_read_sectors(IF_MV2(current_cmd.lun,) current_cmd.sector, current_cmd.last_result = ata_read_sectors(IF_MV2(current_cmd.lun,) current_cmd.sector,
MIN(BUFFER_SIZE/SECTOR_SIZE,current_cmd.count), MIN(BUFFER_SIZE/SECTOR_SIZE,current_cmd.count),
current_cmd.data[current_cmd.data_select]); current_cmd.data[current_cmd.data_select]);
@ -639,12 +668,12 @@ static void handle_scsi(struct command_block_wrapper* cbw)
case SCSI_WRITE_10: case SCSI_WRITE_10:
logf("scsi write10 %d",lun); logf("scsi write10 %d",lun);
if(! lun_present) { 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.sense_key=SENSE_NOT_READY;
cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT;
break; break;
} }
trigger_cpu_boost();
current_cmd.data[0] = transfer_buffer; current_cmd.data[0] = transfer_buffer;
current_cmd.data[1] = &transfer_buffer[BUFFER_SIZE]; current_cmd.data[1] = &transfer_buffer[BUFFER_SIZE];
current_cmd.data_select=0; current_cmd.data_select=0;
@ -658,7 +687,8 @@ static void handle_scsi(struct command_block_wrapper* cbw)
cbw->command_block[8]); cbw->command_block[8]);
/* expect data */ /* expect data */
if((current_cmd.sector + current_cmd.count) > block_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.sense_key=SENSE_ILLEGAL_REQUEST;
cur_sense_data.asc=ASC_LBA_OUT_OF_RANGE; cur_sense_data.asc=ASC_LBA_OUT_OF_RANGE;
} }
@ -672,7 +702,7 @@ static void handle_scsi(struct command_block_wrapper* cbw)
default: default:
logf("scsi unknown cmd %x",cbw->command_block[0x0]); logf("scsi unknown cmd %x",cbw->command_block[0x0]);
usb_drv_stall(EP_MASS_STORAGE, true,true); usb_drv_stall(EP_MASS_STORAGE, true,true);
send_csw(SCSI_STATUS_GOOD); send_csw(UMS_STATUS_FAIL);
break; break;
} }
} }
@ -697,17 +727,16 @@ static void receive_block_data(void *data,int size)
static void send_csw(int status) static void send_csw(int status)
{ {
cancel_cpu_boost(); csw->signature = htole32(CSW_SIGNATURE);
csw->signature = CSW_SIGNATURE;
csw->tag = current_cmd.tag; csw->tag = current_cmd.tag;
csw->data_residue = 0; csw->data_residue = 0;
csw->status = status; csw->status = status;
usb_drv_send_nonblocking(EP_MASS_STORAGE, csw, sizeof(struct command_status_wrapper)); usb_drv_send_nonblocking(EP_MASS_STORAGE, csw, sizeof(struct command_status_wrapper));
state = SENDING_CSW; 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.sense_key=0;
cur_sense_data.information=0; cur_sense_data.information=0;
cur_sense_data.asc=0; cur_sense_data.asc=0;
@ -759,7 +788,8 @@ static void identify2inquiry(int lun)
inquiry->Format = 2; /* SPC-2/3 inquiry format */ inquiry->Format = 2; /* SPC-2/3 inquiry format */
#ifdef HAVE_HOTSWAP #ifdef HAVE_HOTSWAP
inquiry->DeviceTypeModifier = DEVICE_REMOVABLE; if(lun>0)
inquiry->DeviceTypeModifier = DEVICE_REMOVABLE;
#endif #endif
} }