Author: pulkomandy Date: 2010-08-28 00:02:24 +0200 (Sat, 28 Aug 2010) New Revision: 38410 Changeset: http://dev.haiku-os.org/changeset/38410 Modified: haiku/trunk/src/add-ons/kernel/drivers/disk/usb/usb_floppy/usb_disk.cpp Log: Better error handling : do not enter an endless loop in cases of errors, but report them to the caller. Note this leads to KDL if there is a write error, so it may not be the best way for a floppy... This allows the driver to uninitialize properly when all devices are unplugged, which in turns permits updating the driver without rebooting to unload it. Modified: haiku/trunk/src/add-ons/kernel/drivers/disk/usb/usb_floppy/usb_disk.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/disk/usb/usb_floppy/usb_disk.cpp 2010-08-27 21:36:07 UTC (rev 38409) +++ haiku/trunk/src/add-ons/kernel/drivers/disk/usb/usb_floppy/usb_disk.cpp 2010-08-27 22:02:24 UTC (rev 38410) @@ -40,7 +40,7 @@ static char **gDeviceNames = NULL; static uint8 kDeviceIcon[] = { - 0x6e, 0x63, 0x69, 0x66, 0x0c, 0x03, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, + 0x6e, 0x63, 0x69, 0x66, 0x0c, 0x03, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x6a, 0x02, 0x00, 0x16, 0x02, 0x38, 0x6a, 0xad, 0x38, 0xeb, 0x7a, 0xbb, 0x77, 0x73, 0x3a, 0xde, 0x88, 0x48, 0xce, 0xdc, 0x4a, 0x75, 0xed, 0x00, 0x8a, 0xff, 0x4b, 0x02, 0x00, 0x16, 0x02, 0x38, 0x6a, 0xad, 0x38, @@ -195,11 +195,20 @@ void usb_disk_interrupt(void* cookie, int32 status, void* data, uint32 length) { - if (length != 2) - TRACE_ALWAYS("interrupt of length %ld! (expected 2)\n", length); disk_device* dev = (disk_device*)cookie; + // We release the lock even if the interrupt is invalid. This way there + // is at least a chance for the driver to terminate properly. release_sem(dev->interruptLock); + if (length != 2) { + TRACE_ALWAYS("interrupt of length %ld! (expected 2)\n", length); + // In this case we do not reschedule the interrupt. This means the + // driver will be locked. The interrupt should perhaps be scheduled + // when starting a transfer instead. But getting there means something + // is really broken, so... + return; + } + // Reschedule the interrupt for next time gUSBModule->queue_interrupt(dev->interrupt, dev->interruptBuffer, 2, usb_disk_interrupt, cookie); @@ -245,9 +254,9 @@ // There was an error, we have to do a request sense to reset the device if (operation[0] != SCSI_REQUEST_SENSE_6) { - result = usb_disk_request_sense(lun); + usb_disk_request_sense(lun); } - return B_ERROR; + return result; } // Step 2 : data phase : send or receive data @@ -296,23 +305,6 @@ result = usb_disk_request_sense(lun); } return result; - /* - switch (status.status) { - case 0: - TRACE("Command finished ! Everything ok !\n"); - return B_OK; - default: - TRACE("Interrupt returned non-zero code : %x/%x\n", status.status, - status.misc); - // Maybe we should pass the code to the caller ? But we can't handle - // 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; - } - */ } @@ -333,9 +325,11 @@ status_t result = usb_disk_operation(lun, commandBlock, NULL, NULL, false); - while(result == B_DEV_NO_MEDIA) { + int retry = 100; + while(result == B_DEV_NO_MEDIA && retry > 0) { snooze(10000); result = usb_disk_request_sense(lun); + retry--; } if (result != B_OK) @@ -525,16 +519,15 @@ commandBlock[0] = SCSI_READ_CAPACITY_10; commandBlock[1] = lun->logical_unit_number << 5; - // Retry reading the capacity up to three times. The first try might only - // yield a unit attention telling us that the device or media status - // changed, which is more or less expected if it is the first operation - // on the device or the device only clears the unit atention for capacity - // reads. - do { - snooze(10000); + for (int tries = 0; tries < 5; tries++) { result = usb_disk_operation(lun, commandBlock, ¶meter, &dataLength, true); - } while (result != B_OK); + if (result == B_DEV_NO_MEDIA || result == B_TIMED_OUT + || result == B_DEV_STALLED) + snooze(10000); + else + break; + } if (result != B_OK) { TRACE_ALWAYS("failed to update capacity\n"); @@ -829,12 +822,15 @@ commandBlock[8] = blockCount >> 8; commandBlock[9] = blockCount; - status_t result; - do { - snooze(10000); + status_t result = B_OK; + for (int tries = 0; tries < 5; tries++) { result = usb_disk_operation(lun, commandBlock, buffer, length, true); - } while (result != B_OK); + if (result == B_OK) + break; + else + snooze(10000); + } return result; } @@ -858,19 +854,16 @@ commandBlock[9] = blockCount; status_t result; - do { + result = usb_disk_operation(lun, commandBlock, buffer, length, + false); + + int retry = 10; + while (result == B_DEV_NO_MEDIA && retry > 0) { snooze(10000); - result = usb_disk_operation(lun, commandBlock, buffer, length, - false); + result = usb_disk_request_sense(lun); + retry--; + } - TRACE("write result : %s\n", strerror(result)); - - do { - snooze(10000); - result = usb_disk_request_sense(lun); - } while (result != B_OK); - } while (result != B_OK); - if (result == B_OK) lun->should_sync = true; return result;