From 66d6afec5a89464880e7793ad1b791cbee1efd8d Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sun, 1 Sep 2019 01:57:52 +0200 Subject: [PATCH] virtio_scsi: Abort requests on timeout. Previously the CCB would never complete when a timeout occured, leading to all further IO stopping. Abort the request by setting the CCB status to aborted and handing the CCB back to the SCSI layer. That one will then handle the error (and possibly retrying). This is similar to how such errors are handled in AHCI and the ATA stack. Since it is now possible that we receive a completion interrupt for an already aborted request, we need to keep track of what request the interrupts belong to and only notify when the current one completes. As there currently can't be multiple requests in flight, a simple counter is used. Change-Id: Ib80e146605efd2f81123803f424cc7f66f52a6c8 Reviewed-on: https://review.haiku-os.org/c/haiku/+/1815 Reviewed-by: waddlesplash --- .../scsi/virtio/VirtioSCSIController.cpp | 20 +++++++++++-------- .../busses/scsi/virtio/VirtioSCSIPrivate.h | 2 ++ .../busses/scsi/virtio/VirtioSCSIRequest.cpp | 11 ++++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIController.cpp b/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIController.cpp index 59fa80b6c4..5082f1342f 100644 --- a/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIController.cpp +++ b/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIController.cpp @@ -37,6 +37,7 @@ VirtioSCSIController::VirtioSCSIController(device_node *node) fVirtioDevice(NULL), fStatus(B_NO_INIT), fRequest(NULL), + fCurrentRequest(0), fEventDPC(NULL) { CALLED(); @@ -230,16 +231,20 @@ VirtioSCSIController::ExecuteRequest(scsi_ccb *ccb) } fRequest->FillRequest(inCount, outCount, entries); + atomic_add(&fCurrentRequest, 1); fInterruptCondition.Add(&fInterruptConditionEntry); fVirtio->queue_request_v(fRequestVirtioQueue, entries, - outCount, inCount, NULL); + outCount, inCount, (void *)(addr_t)fCurrentRequest); result = fInterruptConditionEntry.Wait(B_RELATIVE_TIMEOUT, fRequest->Timeout()); - if (result != B_OK) + if (result != B_OK) { + ERROR("wait failed with status: %#" B_PRIx32 "\n", result); + fRequest->Abort(); return result; + } return fRequest->Finish(false); } @@ -273,11 +278,6 @@ VirtioSCSIController::_RequestCallback(void* driverCookie, void* cookie) { CALLED(); VirtioSCSIController* controller = (VirtioSCSIController*)driverCookie; - - while (controller->fVirtio->queue_dequeue( - controller->fRequestVirtioQueue, NULL, NULL)) { - } - controller->_RequestInterrupt(); } @@ -285,7 +285,11 @@ VirtioSCSIController::_RequestCallback(void* driverCookie, void* cookie) void VirtioSCSIController::_RequestInterrupt() { - fInterruptCondition.NotifyAll(); + void* cookie = NULL; + while (fVirtio->queue_dequeue(fRequestVirtioQueue, &cookie, NULL)) { + if ((int32)(addr_t)cookie == atomic_get(&fCurrentRequest)) + fInterruptCondition.NotifyAll(); + } } diff --git a/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIPrivate.h b/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIPrivate.h index 78413e4d3a..a7afe88552 100644 --- a/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIPrivate.h +++ b/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIPrivate.h @@ -91,6 +91,7 @@ private: VirtioSCSIRequest* fRequest; + int32 fCurrentRequest; ConditionVariable fInterruptCondition; ConditionVariableEntry fInterruptConditionEntry; @@ -123,6 +124,7 @@ public: { return fCCB->data_length > 0; } status_t Finish(bool resubmit); + void Abort(); // SCSI stuff status_t Start(scsi_ccb *ccb); diff --git a/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIRequest.cpp b/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIRequest.cpp index ff4244b6b3..49071609e7 100644 --- a/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIRequest.cpp +++ b/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIRequest.cpp @@ -140,6 +140,17 @@ VirtioSCSIRequest::Finish(bool resubmit) } +void +VirtioSCSIRequest::Abort() +{ + scsi_ccb *ccb = fCCB; + mutex_unlock(&fLock); + + ccb->subsys_status = SCSI_REQ_ABORTED; + gSCSI->finished(ccb, 1); +} + + void VirtioSCSIRequest::RequestSense() {