* Fix test unit ready command (the device still stall, no idea why).

* Move the interrupt stuff inside the device structure
 * Some cleanup, added some more tracing fordebug purposes.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38399 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Adrien Destugues
2010-08-27 12:40:05 +00:00
parent d26fafe96b
commit 156a187d0d
2 changed files with 39 additions and 31 deletions
@@ -147,9 +147,6 @@ status_t usb_disk_synchronize(device_lun *lun, bool force);
// //
// FIXME: should be part of the device struct.
static unsigned char interruptBuffer[2];
sem_id interruptLock;
void void
@@ -158,7 +155,7 @@ usb_disk_free_device_and_luns(disk_device *device)
mutex_lock(&device->lock); mutex_lock(&device->lock);
mutex_destroy(&device->lock); mutex_destroy(&device->lock);
delete_sem(device->notify); delete_sem(device->notify);
delete_sem(interruptLock); delete_sem(device->interruptLock);
for (uint8 i = 0; i < device->lun_count; i++) for (uint8 i = 0; i < device->lun_count; i++)
free(device->luns[i]); free(device->luns[i]);
free(device->luns); free(device->luns);
@@ -216,13 +213,14 @@ usb_disk_transfer_data(disk_device *device, bool directionIn, void *data,
void void
usb_disk_interrupt(void* cookie, int32 status, void* data, uint32 length) usb_disk_interrupt(void* cookie, int32 status, void* data, uint32 length)
{ {
char* stRep = (char*)data; if (length != 2)
TRACE("interrupt of length %ld! status: %d misc: %d\n", length, TRACE_ALWAYS("interrupt of length %ld! (expected 2)\n", length);
stRep[0], stRep[1]); disk_device* dev = (disk_device*)cookie;
release_sem(interruptLock); release_sem(dev->interruptLock);
gUSBModule->queue_interrupt(((disk_device*)cookie)->interrupt, // Reschedule the interrupt for next time
interruptBuffer, 2, usb_disk_interrupt, cookie); gUSBModule->queue_interrupt(dev->interrupt, dev->interruptBuffer, 2,
usb_disk_interrupt, cookie);
} }
@@ -231,12 +229,12 @@ usb_disk_receive_csw(disk_device *device, command_status_wrapper *status)
{ {
TRACE("Waiting for result...\n"); TRACE("Waiting for result...\n");
gUSBModule->queue_interrupt(device->interrupt, gUSBModule->queue_interrupt(device->interrupt,
interruptBuffer, 2, usb_disk_interrupt, device); device->interruptBuffer, 2, usb_disk_interrupt, device);
acquire_sem(interruptLock); acquire_sem(device->interruptLock);
status->status = interruptBuffer[0]; status->status = device->interruptBuffer[0];
status->misc = interruptBuffer[1]; status->misc = device->interruptBuffer[1];
return B_OK; return B_OK;
} }
@@ -247,10 +245,11 @@ usb_disk_operation(device_lun *lun, uint8* operation,
uint32 logicalBlockAddress, uint16 transferLength, void *data, uint32 logicalBlockAddress, uint16 transferLength, void *data,
uint32 *dataLength, bool directionIn) uint32 *dataLength, bool directionIn)
{ {
TRACE("operation: lun: %u; op: %u; lba: %lu; tlen: %u; data: %p; dlen: %p (%lu); in: %c\n", // TODO: remove transferLength
lun->logical_unit_number, operation[0], logicalBlockAddress, TRACE("operation: lun: %u; op: 0x%x; lba: %lu; tlen: %u; data: %p;"
transferLength, data, dataLength, dataLength ? *dataLength : 0, " dlen: %p (%lu); in: %c\n", lun->logical_unit_number, operation[0],
directionIn ? 'y' : 'n'); logicalBlockAddress, transferLength, data, dataLength,
dataLength ? *dataLength : 0, directionIn ? 'y' : 'n');
disk_device* device = lun->device; disk_device* device = lun->device;
@@ -261,8 +260,8 @@ usb_disk_operation(device_lun *lun, uint8* operation,
device->interface, 12, operation, &actualLength); device->interface, 12, operation, &actualLength);
if (result != B_OK || actualLength != 12) { if (result != B_OK || actualLength != 12) {
TRACE("Command stage: wrote %ld bytes (%s) (interface = %d)\n", actualLength, strerror(result), TRACE("Command stage: wrote %ld bytes (%s) (interface = %d)\n",
device->interface); actualLength, strerror(result), device->interface);
return B_ERROR; return B_ERROR;
} }
@@ -307,12 +306,16 @@ usb_disk_operation(device_lun *lun, uint8* operation,
switch (status.status) { switch (status.status) {
case 0: case 0:
return B_OK; return B_OK;
default: { default:
// command status wrapper is not meaningful TRACE("Interrupt returned non-zero code : %x/%x\n", status.status,
TRACE_ALWAYS("command status wrapper has invalid status\n"); status.misc);
usb_disk_reset_recovery(device); // Maybe we should pass the code to the caller ? But we can't handle
return B_ERROR; // everything as errors at this level, for example test unit ready
} // will return a "not ready code if there is no disk, but this is
// not an operation error.
// The code is also available as data by sending a status request to
// the drive, anyway.
return B_OK;
} }
} }
@@ -433,12 +436,12 @@ usb_disk_test_unit_ready(device_lun *lun)
uint8 commandBlock[12]; uint8 commandBlock[12];
memset(commandBlock, 0, sizeof(commandBlock)); memset(commandBlock, 0, sizeof(commandBlock));
commandBlock[0] = SCSI_INQUIRY_6; commandBlock[0] = SCSI_TEST_UNIT_READY_6;
commandBlock[1] = lun->logical_unit_number << 5; commandBlock[1] = lun->logical_unit_number << 5;
status_t result; status_t result;
result = usb_disk_operation(lun, commandBlock, 0, 0, result = usb_disk_operation(lun, commandBlock, 0, 0,
NULL, NULL, true); NULL, NULL, false);
if (result == B_DEV_INVALID_IOCTL) { if (result == B_DEV_INVALID_IOCTL) {
lun->device->tur_supported = false; lun->device->tur_supported = false;
@@ -655,11 +658,11 @@ usb_disk_device_added(usb_device newDevice, void **cookie)
return device->notify; return device->notify;
} }
interruptLock = create_sem(0, "usb_disk interrupt lock"); device->interruptLock = create_sem(0, "usb_disk interrupt lock");
if (interruptLock < B_OK) { if (device->interruptLock < B_OK) {
mutex_destroy(&device->lock); mutex_destroy(&device->lock);
free(device); free(device);
return interruptLock; return device->interruptLock;
} }
// TODO: handle more than 1 unit // TODO: handle more than 1 unit
@@ -690,6 +693,7 @@ usb_disk_device_added(usb_device newDevice, void **cookie)
// initialize this lun // initialize this lun
result = usb_disk_inquiry(lun); result = usb_disk_inquiry(lun);
TRACE("Probing unit %d\n", lun->logical_unit_number);
for (uint32 tries = 0; tries < 3; tries++) { for (uint32 tries = 0; tries < 3; tries++) {
status_t ready = usb_disk_test_unit_ready(lun); status_t ready = usb_disk_test_unit_ready(lun);
if (ready == B_OK || ready == B_DEV_NO_MEDIA) { if (ready == B_OK || ready == B_DEV_NO_MEDIA) {
@@ -54,6 +54,10 @@ typedef struct disk_device_s {
status_t status; status_t status;
size_t actual_length; size_t actual_length;
// used to store interrupt result
unsigned char interruptBuffer[2];
sem_id interruptLock;
// logical units of this device // logical units of this device
uint8 lun_count; uint8 lun_count;
device_lun **luns; device_lun **luns;