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:
parent
9a2911ca8c
commit
66d6afec5a
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue