switch (State) {
case XENVBD_STATE_INVALID: return "STATE_INVALID";
case XENVBD_INITIALIZED: return "INITIALIZED";
+ case XENVBD_CLOSING: return "CLOSING";
case XENVBD_CLOSED: return "CLOSED";
case XENVBD_PREPARED: return "PREPARED";
case XENVBD_CONNECTED: return "CONNECTED";
switch (Frontend->State) {
case XENVBD_INITIALIZED:
switch (State) {
+ case XENVBD_CLOSING:
case XENVBD_CLOSED:
case XENVBD_PREPARED:
case XENVBD_CONNECTED:
Failed = TRUE;
}
break;
+ case XENVBD_CLOSING:
case XENVBD_CLOSED:
Status = FrontendClose(Frontend);
if (NT_SUCCESS(Status)) {
FrontendEnable(Frontend);
Frontend->State = XENVBD_ENABLED;
break;
+ case XENVBD_CLOSING:
case XENVBD_CLOSED:
case XENVBD_PREPARED:
Status = FrontendClose(Frontend);
- FrontendDisconnect(Frontend);
if (NT_SUCCESS(Status)) {
- Frontend->State = XENVBD_CLOSED;
+ Frontend->State = XENVBD_CLOSING;
} else {
Frontend->State = XENVBD_STATE_INVALID;
Failed = TRUE;
}
break;
+ case XENVBD_CLOSING:
+ switch (State) {
+ case XENVBD_INITIALIZED:
+ case XENVBD_CLOSED:
+ case XENVBD_PREPARED:
+ case XENVBD_CONNECTED:
+ case XENVBD_ENABLED:
+ FrontendDisconnect(Frontend);
+ Frontend->State = XENVBD_CLOSED;
+ break;
+ default:
+ Failed = TRUE;
+ break;
+ }
+ break;
+
case XENVBD_ENABLED:
switch (State) {
+ case XENVBD_CLOSING:
case XENVBD_CLOSED:
case XENVBD_PREPARED:
case XENVBD_CONNECTED:
typedef enum _XENVBD_STATE {
XENVBD_STATE_INVALID,
- XENVBD_INITIALIZED,
- XENVBD_CLOSED,
- XENVBD_PREPARED,
- XENVBD_CONNECTED,
- XENVBD_ENABLED
+ XENVBD_INITIALIZED, // -> { CLOSED }
+ XENVBD_CLOSING, // -> { CLOSED }
+ XENVBD_CLOSED, // -> { PREPARED }
+ XENVBD_PREPARED, // -> { CLOSING, CONNECTED }
+ XENVBD_CONNECTED, // -> { ENABLED, CLOSING }
+ XENVBD_ENABLED // -> { CLOSING }
} XENVBD_STATE, *PXENVBD_STATE;
typedef struct _XENVBD_CAPS {
NotifierTrigger(Notifier);
}
+static FORCEINLINE VOID
+__PdoCleanupSubmittedReqs(
+ IN PXENVBD_PDO Pdo
+ )
+{
+ // Fail PreparedReqs
+ for (;;) {
+ PXENVBD_SRBEXT SrbExt;
+ PXENVBD_REQUEST Request;
+ PLIST_ENTRY Entry = QueuePop(&Pdo->SubmittedReqs);
+ if (Entry == NULL)
+ break;
+ Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry);
+ SrbExt = GetSrbExt(Request->Srb);
+
+ Verbose("Target[%d] : SubmittedReq 0x%p -> FAILED\n", PdoGetTargetId(Pdo), Request);
+
+ RequestCleanup(Pdo, Request);
+ __LookasideFree(&Pdo->RequestList, Request);
+
+ if (InterlockedDecrement(&SrbExt->Count) == 0) {
+ SrbExt->Srb->SrbStatus = SRB_STATUS_ABORTED;
+ SrbExt->Srb->ScsiStatus = 0x40; // SCSI_ABORTED
+ FdoCompleteSrb(PdoGetFdo(Pdo), SrbExt->Srb);
+ }
+ }
+}
+
VOID
PdoReset(
__in PXENVBD_PDO Pdo
if (QueueCount(&Pdo->SubmittedReqs)) {
Error("Target[%d] : backend has %u outstanding requests after a PdoReset\n",
PdoGetTargetId(Pdo), QueueCount(&Pdo->SubmittedReqs));
- BUG("backend contains outstanding requests after reset");
}
+ Status = FrontendSetState(Pdo->Frontend, XENVBD_CLOSING);
+ ASSERT(NT_SUCCESS(Status));
+
+ __PdoCleanupSubmittedReqs(Pdo);
+
Status = FrontendSetState(Pdo->Frontend, XENVBD_CLOSED);
ASSERT(NT_SUCCESS(Status));