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 <waddlesplash@gmail.com>
This commit is contained in:
Michael Lotz 2019-09-01 01:57:52 +02:00 committed by waddlesplash
parent 9a2911ca8c
commit 66d6afec5a
3 changed files with 25 additions and 8 deletions

View File

@ -37,6 +37,7 @@ VirtioSCSIController::VirtioSCSIController(device_node *node)
fVirtioDevice(NULL), fVirtioDevice(NULL),
fStatus(B_NO_INIT), fStatus(B_NO_INIT),
fRequest(NULL), fRequest(NULL),
fCurrentRequest(0),
fEventDPC(NULL) fEventDPC(NULL)
{ {
CALLED(); CALLED();
@ -230,16 +231,20 @@ VirtioSCSIController::ExecuteRequest(scsi_ccb *ccb)
} }
fRequest->FillRequest(inCount, outCount, entries); fRequest->FillRequest(inCount, outCount, entries);
atomic_add(&fCurrentRequest, 1);
fInterruptCondition.Add(&fInterruptConditionEntry); fInterruptCondition.Add(&fInterruptConditionEntry);
fVirtio->queue_request_v(fRequestVirtioQueue, entries, fVirtio->queue_request_v(fRequestVirtioQueue, entries,
outCount, inCount, NULL); outCount, inCount, (void *)(addr_t)fCurrentRequest);
result = fInterruptConditionEntry.Wait(B_RELATIVE_TIMEOUT, result = fInterruptConditionEntry.Wait(B_RELATIVE_TIMEOUT,
fRequest->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 result;
}
return fRequest->Finish(false); return fRequest->Finish(false);
} }
@ -273,11 +278,6 @@ VirtioSCSIController::_RequestCallback(void* driverCookie, void* cookie)
{ {
CALLED(); CALLED();
VirtioSCSIController* controller = (VirtioSCSIController*)driverCookie; VirtioSCSIController* controller = (VirtioSCSIController*)driverCookie;
while (controller->fVirtio->queue_dequeue(
controller->fRequestVirtioQueue, NULL, NULL)) {
}
controller->_RequestInterrupt(); controller->_RequestInterrupt();
} }
@ -285,8 +285,12 @@ VirtioSCSIController::_RequestCallback(void* driverCookie, void* cookie)
void void
VirtioSCSIController::_RequestInterrupt() VirtioSCSIController::_RequestInterrupt()
{ {
void* cookie = NULL;
while (fVirtio->queue_dequeue(fRequestVirtioQueue, &cookie, NULL)) {
if ((int32)(addr_t)cookie == atomic_get(&fCurrentRequest))
fInterruptCondition.NotifyAll(); fInterruptCondition.NotifyAll();
} }
}

View File

@ -91,6 +91,7 @@ private:
VirtioSCSIRequest* fRequest; VirtioSCSIRequest* fRequest;
int32 fCurrentRequest;
ConditionVariable fInterruptCondition; ConditionVariable fInterruptCondition;
ConditionVariableEntry fInterruptConditionEntry; ConditionVariableEntry fInterruptConditionEntry;
@ -123,6 +124,7 @@ public:
{ return fCCB->data_length > 0; } { return fCCB->data_length > 0; }
status_t Finish(bool resubmit); status_t Finish(bool resubmit);
void Abort();
// SCSI stuff // SCSI stuff
status_t Start(scsi_ccb *ccb); status_t Start(scsi_ccb *ccb);

View File

@ -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 void
VirtioSCSIRequest::RequestSense() VirtioSCSIRequest::RequestSense()
{ {