[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [win-pv-devel] [PATCH 3/3] Add XenDisk device upper filter.



> -----Original Message-----
> From: Owen Smith [mailto:owen.smith@xxxxxxxxxx]
> Sent: 28 October 2014 11:27
> To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
> Cc: Paul Durrant; Owen Smith
> Subject: [PATCH 3/3] Add XenDisk device upper filter.
> 
> XenDisk intercepts and translates
> IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES
> into SCSIOP_UNMAP SRBs. Storport will pass on these SCSIOP_UNMAP
> requests
> to XenVbd, which will create the appropriate BLKIF_OP_DISCARD requests.
> XenDisk is only neccessary because Storport does not do the translation
> to SCSIOP_UNMAPs.
> 
> Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx>

Acked-by: Paul Durrant <paul.durrant@xxxxxxxxxx>

> ---
>  build.py                            |    1 +
>  src/xendisk/assert.h                |  220 ++++
>  src/xendisk/debug.h                 |   94 ++
>  src/xendisk/driver.c                |  203 ++++
>  src/xendisk/driver.h                |   68 ++
>  src/xendisk/fdo.c                   | 1862 +++++++++++++++++++++++++++++++
>  src/xendisk/fdo.h                   |   78 ++
>  src/xendisk/mutex.h                 |  113 ++
>  src/xendisk/pdo.c                   | 2079
> +++++++++++++++++++++++++++++++++++
>  src/xendisk/pdo.h                   |   90 ++
>  src/xendisk/thread.c                |  225 ++++
>  src/xendisk/thread.h                |   73 ++
>  src/xendisk/types.h                 |   53 +
>  src/xendisk/util.h                  |  222 ++++
>  src/xendisk/xendisk.rc              |   56 +
>  src/xenvbd.inf                      |   18 +
>  vs2012/package/package.vcxproj      |    3 +
>  vs2012/xendisk/xendisk.vcxproj      |   84 ++
>  vs2012/xendisk/xendisk.vcxproj.user |    8 +
>  vs2012/xenvbd.sln                   |   28 +
>  vs2013/package/package.vcxproj      |    3 +
>  vs2013/xendisk/xendisk.vcxproj      |  112 ++
>  vs2013/xendisk/xendisk.vcxproj.user |    8 +
>  vs2013/xenvbd.sln                   |   28 +
>  24 files changed, 5729 insertions(+)
>  create mode 100644 src/xendisk/assert.h
>  create mode 100644 src/xendisk/debug.h
>  create mode 100644 src/xendisk/driver.c
>  create mode 100644 src/xendisk/driver.h
>  create mode 100644 src/xendisk/fdo.c
>  create mode 100644 src/xendisk/fdo.h
>  create mode 100644 src/xendisk/mutex.h
>  create mode 100644 src/xendisk/pdo.c
>  create mode 100644 src/xendisk/pdo.h
>  create mode 100644 src/xendisk/thread.c
>  create mode 100644 src/xendisk/thread.h
>  create mode 100644 src/xendisk/types.h
>  create mode 100644 src/xendisk/util.h
>  create mode 100644 src/xendisk/xendisk.rc
>  create mode 100644 vs2012/xendisk/xendisk.vcxproj
>  create mode 100644 vs2012/xendisk/xendisk.vcxproj.user
>  create mode 100644 vs2013/xendisk/xendisk.vcxproj
>  create mode 100644 vs2013/xendisk/xendisk.vcxproj.user
> 
> diff --git a/build.py b/build.py
> index 26261ad..3a71d0c 100644
> --- a/build.py
> +++ b/build.py
> @@ -368,6 +368,7 @@ if __name__ == '__main__':
> 
>      if len(sys.argv) <= 2 or sdv[sys.argv[2]]:
>          run_sdv('xencrsh', driver, vs)
> +        run_sdv('xendisk', driver, vs)
>          run_sdv('xenvbd', driver, vs)
> 
>      archive(driver + '\\source.tgz', manifest().splitlines(), tgz=True)
> diff --git a/src/xendisk/assert.h b/src/xendisk/assert.h
> new file mode 100644
> index 0000000..cd571bd
> --- /dev/null
> +++ b/src/xendisk/assert.h
> @@ -0,0 +1,220 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#ifndef _XENDISK_ASSERT_H
> +#define _XENDISK_ASSERT_H
> +
> +#include <ntddk.h>
> +
> +#include "debug.h"
> +
> +static FORCEINLINE VOID
> +__BugCheck(
> +    __in  ULONG       Code,
> +    __in_opt ULONG_PTR   Parameter1,
> +    __in_opt ULONG_PTR   Parameter2,
> +    __in_opt ULONG_PTR   Parameter3,
> +    __in_opt ULONG_PTR   Parameter4
> +    )
> +{
> +#pragma prefast(suppress:28159)
> +    KeBugCheckEx(Code,
> +                 Parameter1,
> +                 Parameter2,
> +                 Parameter3,
> +                 Parameter4);
> +}
> +
> +#define ASSERTION_FAILURE   0x0000DEAD
> +
> +
> +#define BUG(_TEXT)                                              \
> +        do {                                                    \
> +            const CHAR  *_Text = (_TEXT);                       \
> +            const CHAR  *_File = __FILE__;                      \
> +            ULONG       _Line = __LINE__;                       \
> +                                                                \
> +            Error("BUG: " _TEXT "\n");                          \
> +            __BugCheck(ASSERTION_FAILURE,                       \
> +                       (ULONG_PTR)_Text,                        \
> +                       (ULONG_PTR)_File,                        \
> +                       (ULONG_PTR)_Line,                        \
> +                       0);                                      \
> +        } while (FALSE)
> +
> +#define BUG_MSG(_TEXT1, _TEXT2)                                 \
> +        do {                                                    \
> +            const CHAR  *_Text1 = (_TEXT1);                     \
> +            const CHAR  *_Text2 = (_TEXT2);                     \
> +            const CHAR  *_File = __FILE__;                      \
> +            ULONG       _Line = __LINE__;                       \
> +                                                                \
> +            Error("BUG: " _TEXT1 " %s\n", _Text2);              \
> +            __BugCheck(ASSERTION_FAILURE,                       \
> +                       (ULONG_PTR)_Text1,                       \
> +                       (ULONG_PTR)_File,                        \
> +                       (ULONG_PTR)_Line,                        \
> +                       (ULONG_PTR)_Text2);                      \
> +        } while (FALSE)
> +
> +#define BUG_ON(_EXP)                           \
> +        if (_EXP) BUG(#_EXP)
> +
> +#define BUG_ON_MSG(_EXP, _TEXT)                \
> +        if (_EXP) BUG_MSG(#_EXP, _TEXT)
> +
> +#if DBG
> +
> +#define __NT_ASSERT(_EXP)                                       \
> +        ((!(_EXP)) ?                                            \
> +        (Error("ASSERTION FAILED: " #_EXP "\n"),                \
> +         __annotation(L"Debug", L"AssertFail", L#_EXP),         \
> +         DbgRaiseAssertionFailure(), FALSE) :                   \
> +        TRUE)
> +
> +#define __NT_ASSERT_MSG(_EXP, _TEXT)                            \
> +        ((!(_EXP)) ?                                            \
> +        (Error("ASSERTION FAILED: " #_EXP " " #_TEXT "\n"),     \
> +         __annotation(L"Debug", L"AssertFail", L#_EXP),         \
> +         DbgRaiseAssertionFailure(), FALSE) :                   \
> +        TRUE)
> +
> +#define __ASSERT(_EXP)              __NT_ASSERT(_EXP)
> +#define __ASSERT_MSG(_EXP, _TEXT)   __NT_ASSERT_MSG(_EXP, _TEXT)
> +
> +#else   // DBG
> +
> +#define __ASSERT(_EXP)              BUG_ON(!(_EXP))
> +#define __ASSERT_MSG(_EXP, _TEXT)   BUG_ON_MSG(!(_EXP), _TEXT)
> +
> +#endif  // DBG
> +
> +#undef  ASSERT
> +
> +#define ASSERT(_EXP)                    \
> +        do {                            \
> +            __ASSERT(_EXP);             \
> +            __analysis_assume(_EXP);    \
> +        } while (FALSE)
> +
> +#define ASSERT_MSG(_EXP, _TEXT)         \
> +        do {                            \
> +            __ASSERT_MSG(_EXP, _TEXT);  \
> +            __analysis_assume(_EXP);    \
> +        } while (FALSE)
> +
> +#define ASSERT3U(_X, _OP, _Y)                       \
> +        do {                                        \
> +            ULONGLONG   _Lval = (ULONGLONG)(_X);    \
> +            ULONGLONG   _Rval = (ULONGLONG)(_Y);    \
> +            if (!(_Lval _OP _Rval)) {               \
> +                Error("%s = %llu\n", #_X, _Lval);   \
> +                Error("%s = %llu\n", #_Y, _Rval);   \
> +                ASSERT(_X _OP _Y);                  \
> +            }                                       \
> +        } while (FALSE)
> +
> +#define ASSERT3S(_X, _OP, _Y)                       \
> +        do {                                        \
> +            LONGLONG    _Lval = (LONGLONG)(_X);     \
> +            LONGLONG    _Rval = (LONGLONG)(_Y);     \
> +            if (!(_Lval _OP _Rval)) {               \
> +                Error("%s = %lld\n", #_X, _Lval);   \
> +                Error("%s = %lld\n", #_Y, _Rval);   \
> +                ASSERT(_X _OP _Y);                  \
> +            }                                       \
> +        } while (FALSE)
> +
> +#define ASSERT3P(_X, _OP, _Y)                       \
> +        do {                                        \
> +            PVOID   _Lval = (PVOID)(_X);            \
> +            PVOID   _Rval = (PVOID)(_Y);            \
> +            if (!(_Lval _OP _Rval)) {               \
> +                Error("%s = %p\n", #_X, _Lval);     \
> +                Error("%s = %p\n", #_Y, _Rval);     \
> +                ASSERT(_X _OP _Y);                  \
> +            }                                       \
> +        } while (FALSE)
> +
> +#define ASSERTREFCOUNT(_X, _OP, _Y, _Z)             \
> +        do {                                        \
> +            LONG    _L = (LONG)(_X);                \
> +            LONG    _R = (LONG)(_Y);                \
> +            if (!(_L _OP _R)) {                     \
> +                Error("%s:%s = %d\n", (_Z), #_X, _L); \
> +                Error("%s:%s = %d\n", (_Z), #_Y, _R); \
> +                ASSERT_MSG(_X _OP _Y, (_Z));        \
> +            }                                       \
> +        } while (FALSE)
> +
> +#ifndef TEST_MEMORY
> +#define TEST_MEMORY DBG
> +#endif
> +
> +#if TEST_MEMORY
> +
> +__checkReturn
> +static __inline BOOLEAN
> +_IsZeroMemory(
> +    __in const PCHAR Caller,
> +    __in const PCHAR Name,
> +    __in PVOID       Buffer,
> +    __in ULONG       Length
> +    )
> +{
> +    ULONG           Offset;
> +
> +    Offset = 0;
> +    while (Offset < Length) {
> +        if (*((PUCHAR)Buffer + Offset) != 0) {
> +            Error("%s: non-zero byte in %s (0x%p+0x%x)\n", Caller, Name,
> Buffer, Offset);
> +            return FALSE;
> +        }
> +        Offset++;
> +    }
> +
> +    return TRUE;
> +}
> +
> +#define IsZeroMemory(_Buffer, _Length) \
> +        _IsZeroMemory(__FUNCTION__, #_Buffer, (_Buffer), (_Length))
> +
> +#else   // TEST_MEMORY
> +
> +#define IsZeroMemory(_Buffer, _Length)  TRUE
> +
> +#endif  // TEST_MEMORY
> +
> +#define IMPLY(_X, _Y)   (!(_X) || (_Y))
> +#define EQUIV(_X, _Y)   (IMPLY((_X), (_Y)) && IMPLY((_Y), (_X)))
> +
> +#endif  // _XENDISK_ASSERT_H
> +
> diff --git a/src/xendisk/debug.h b/src/xendisk/debug.h
> new file mode 100644
> index 0000000..f592f86
> --- /dev/null
> +++ b/src/xendisk/debug.h
> @@ -0,0 +1,94 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#ifndef _DEBUG_H
> +#define _DEBUG_H
> +
> +#include <ntddk.h>
> +#include <stdarg.h>
> +
> +#ifdef  _SDV_
> +#define __MODULE__ ""
> +#endif
> +
> +// DEBUG_FILTER_MASKs
> +// Set these to see relevant output
> +// ERROR        0x00000001
> +// WARNING      0x00000002
> +// TRACE        0x00000004
> +// INFO         0x00000008
> +
> +#pragma warning(disable:4127)   // conditional expression is constant
> +
> +//
> +// Debug Output and Logging
> +//
> +static __inline VOID
> +__DebugMessage(
> +    __in    ULONG       Level,
> +    __in __nullterminated const CHAR  *Prefix,
> +    __in __nullterminated const CHAR  *Format,
> +    ...
> +    )
> +{
> +    va_list         Arguments;
> +
> +    va_start(Arguments, Format);
> +
> +#pragma prefast(suppress:6001) // Using uninitialized memory
> +    vDbgPrintExWithPrefix(Prefix,
> +                          DPFLTR_IHVDRIVER_ID,
> +                          Level,
> +                          Format,
> +                          Arguments);
> +    va_end(Arguments);
> +}
> +
> +#define Error(...)  \
> +        __DebugMessage(DPFLTR_ERROR_LEVEL, __MODULE__ "|"
> __FUNCTION__ ":", __VA_ARGS__)
> +
> +#define Warning(...)  \
> +        __DebugMessage(DPFLTR_WARNING_LEVEL, __MODULE__ "|"
> __FUNCTION__ ":", __VA_ARGS__)
> +
> +#if DBG
> +#define Trace(...)  \
> +        __DebugMessage(DPFLTR_TRACE_LEVEL, __MODULE__ "|"
> __FUNCTION__ ":", __VA_ARGS__)
> +#else   // DBG
> +#define Trace(...) \
> +        (VOID)(__VA_ARGS__)
> +#endif  // DBG
> +
> +#define Verbose(...) \
> +        __DebugMessage(DPFLTR_INFO_LEVEL, __MODULE__ "|"
> __FUNCTION__ ":", __VA_ARGS__)
> +
> +#include "assert.h"
> +
> +#endif  // _DEBUG_H
> diff --git a/src/xendisk/driver.c b/src/xendisk/driver.c
> new file mode 100644
> index 0000000..743fc61
> --- /dev/null
> +++ b/src/xendisk/driver.c
> @@ -0,0 +1,203 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#include <ntddk.h>
> +#include "driver.h"
> +#include "util.h"
> +#include "debug.h"
> +#include "assert.h"
> +#include <version.h>
> +
> +extern PULONG       InitSafeBootMode;
> +
> +typedef struct _XENDISK_DRIVER {
> +    PDRIVER_OBJECT              DriverObject;
> +} XENDISK_DRIVER, *PXENDISK_DRIVER;
> +
> +static XENDISK_DRIVER   Driver;
> +
> +static FORCEINLINE VOID
> +__DriverSetDriverObject(
> +    IN  PDRIVER_OBJECT  DriverObject
> +    )
> +{
> +    Driver.DriverObject = DriverObject;
> +}
> +
> +static FORCEINLINE PDRIVER_OBJECT
> +__DriverGetDriverObject(
> +    VOID
> +    )
> +{
> +    return Driver.DriverObject;
> +}
> +
> +PDRIVER_OBJECT
> +DriverGetDriverObject(
> +    VOID
> +    )
> +{
> +    return __DriverGetDriverObject();
> +}
> +
> +DRIVER_UNLOAD   DriverUnload;
> +
> +VOID
> +DriverUnload(
> +    IN  PDRIVER_OBJECT  DriverObject
> +    )
> +{
> +    ASSERT3P(DriverObject, ==, __DriverGetDriverObject());
> +
> +    Trace("====>\n");
> +
> +    __DriverSetDriverObject(NULL);
> +
> +    ASSERT(IsZeroMemory(&Driver, sizeof (XENDISK_DRIVER)));
> +
> +    Trace("<====\n");
> +}
> +
> +DRIVER_ADD_DEVICE   AddDevice;
> +
> +NTSTATUS
> +#pragma prefast(suppress:28152) // Does not clear
> DO_DEVICE_INITIALIZING
> +AddDevice(
> +    IN  PDRIVER_OBJECT  DriverObject,
> +    IN  PDEVICE_OBJECT  PhysicalDeviceObject
> +    )
> +{
> +    NTSTATUS            status;
> +
> +    ASSERT3P(DriverObject, ==, __DriverGetDriverObject());
> +
> +    status = FdoCreate(PhysicalDeviceObject);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    return STATUS_SUCCESS;
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    return status;
> +}
> +
> +DRIVER_DISPATCH Dispatch;
> +
> +NTSTATUS
> +Dispatch(
> +    IN PDEVICE_OBJECT   DeviceObject,
> +    IN PIRP             Irp
> +    )
> +{
> +    PXENDISK_DX         Dx;
> +    NTSTATUS            status;
> +
> +    Dx = (PXENDISK_DX)DeviceObject->DeviceExtension;
> +    ASSERT3P(Dx->DeviceObject, ==, DeviceObject);
> +
> +    if (Dx->DevicePnpState == Deleted) {
> +        status = STATUS_NO_SUCH_DEVICE;
> +
> +        Irp->IoStatus.Status = status;
> +        IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +        goto done;
> +    }
> +
> +    status = STATUS_NOT_SUPPORTED;
> +    switch (Dx->Type) {
> +    case PHYSICAL_DEVICE_OBJECT: {
> +        PXENDISK_PDO    Pdo = Dx->Pdo;
> +
> +        status = PdoDispatch(Pdo, Irp);
> +        break;
> +    }
> +    case FUNCTION_DEVICE_OBJECT: {
> +        PXENDISK_FDO    Fdo = Dx->Fdo;
> +
> +        status = FdoDispatch(Fdo, Irp);
> +        break;
> +    }
> +    default:
> +        ASSERT(FALSE);
> +        break;
> +    }
> +
> +done:
> +    return status;
> +}
> +
> +DRIVER_INITIALIZE   DriverEntry;
> +
> +NTSTATUS
> +DriverEntry(
> +    IN  PDRIVER_OBJECT  DriverObject,
> +    IN  PUNICODE_STRING RegistryPath
> +    )
> +{
> +    ULONG               Index;
> +
> +    ASSERT3P(__DriverGetDriverObject(), ==, NULL);
> +    UNREFERENCED_PARAMETER(RegistryPath);
> +
> +    ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
> +
> +    Trace("====>\n");
> +
> +    __DriverSetDriverObject(DriverObject);
> +
> +    DriverObject->DriverUnload = DriverUnload;
> +
> +    if (*InitSafeBootMode > 0)
> +        goto done;
> +
> +    Verbose("XENDISK %d.%d.%d (%d) (%02d.%02d.%04d)\n",
> +            MAJOR_VERSION,
> +            MINOR_VERSION,
> +            MICRO_VERSION,
> +            BUILD_NUMBER,
> +            DAY,
> +            MONTH,
> +            YEAR);
> +
> +    DriverObject->DriverExtension->AddDevice = AddDevice;
> +
> +    for (Index = 0; Index <= IRP_MJ_MAXIMUM_FUNCTION; Index++) {
> +#pragma prefast(suppress:28169) // No __drv_dispatchType annotation
> +#pragma prefast(suppress:28168) // No matching __drv_dispatchType
> annotation for IRP_MJ_CREATE
> +        DriverObject->MajorFunction[Index] = Dispatch;
> +    }
> +
> +done:
> +    Trace("<====\n");
> +    return STATUS_SUCCESS;
> +}
> diff --git a/src/xendisk/driver.h b/src/xendisk/driver.h
> new file mode 100644
> index 0000000..b47e21b
> --- /dev/null
> +++ b/src/xendisk/driver.h
> @@ -0,0 +1,68 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#ifndef _XENDISK_DRIVER_H
> +#define _XENDISK_DRIVER_H
> +
> +#include "fdo.h"
> +#include "pdo.h"
> +
> +extern PDRIVER_OBJECT
> +DriverGetDriverObject(
> +    VOID
> +    );
> +
> +#pragma warning(push)
> +#pragma warning(disable:4201) // nonstandard extension used : nameless
> struct/union
> +
> +typedef struct _XENDISK_DX {
> +    PDEVICE_OBJECT      DeviceObject;
> +    DEVICE_OBJECT_TYPE  Type;
> +
> +    DEVICE_PNP_STATE    DevicePnpState;
> +    DEVICE_PNP_STATE    PreviousDevicePnpState;
> +
> +    SYSTEM_POWER_STATE  SystemPowerState;
> +    DEVICE_POWER_STATE  DevicePowerState;
> +
> +    IO_REMOVE_LOCK      RemoveLock;
> +
> +    LIST_ENTRY          ListEntry;
> +
> +    union {
> +        PXENDISK_FDO    Fdo;
> +        PXENDISK_PDO    Pdo;
> +    };
> +} XENDISK_DX, *PXENDISK_DX;
> +
> +#pragma warning(pop)
> +
> +#endif // _XENDISK_DRIVER_H
> diff --git a/src/xendisk/fdo.c b/src/xendisk/fdo.c
> new file mode 100644
> index 0000000..771c82e
> --- /dev/null
> +++ b/src/xendisk/fdo.c
> @@ -0,0 +1,1862 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#define INITGUID 1
> +
> +#include <ntddk.h>
> +#include <wdmguid.h>
> +#include <ntstrsafe.h>
> +#include <stdlib.h>
> +#include <names.h>
> +
> +#include "driver.h"
> +#include "fdo.h"
> +#include "pdo.h"
> +#include "thread.h"
> +#include "mutex.h"
> +#include "debug.h"
> +#include "assert.h"
> +#include "util.h"
> +
> +#define FDO_TAG 'ODF'
> +
> +struct _XENDISK_FDO {
> +    PXENDISK_DX                     Dx;
> +    PDEVICE_OBJECT                  LowerDeviceObject;
> +    PDEVICE_OBJECT                  PhysicalDeviceObject;
> +
> +    PXENDISK_THREAD                 SystemPowerThread;
> +    PIRP                            SystemPowerIrp;
> +    PXENDISK_THREAD                 DevicePowerThread;
> +    PIRP                            DevicePowerIrp;
> +
> +    MUTEX                           Mutex;
> +    ULONG                           References;
> +};
> +
> +static FORCEINLINE PVOID
> +__FdoAllocate(
> +    IN  ULONG   Length
> +    )
> +{
> +    return __AllocateNonPagedPoolWithTag(__FUNCTION__, __LINE__,
> Length, FDO_TAG);
> +}
> +
> +static FORCEINLINE VOID
> +__FdoFree(
> +    IN  PVOID   Buffer
> +    )
> +{
> +    __FreePoolWithTag(Buffer, FDO_TAG);
> +}
> +
> +static FORCEINLINE VOID
> +__FdoSetDevicePnpState(
> +    IN  PXENDISK_FDO        Fdo,
> +    IN  DEVICE_PNP_STATE    State
> +    )
> +{
> +    PXENDISK_DX             Dx = Fdo->Dx;
> +
> +    // We can never transition out of the deleted state
> +    ASSERT(Dx->DevicePnpState != Deleted || State == Deleted);
> +
> +    Dx->PreviousDevicePnpState = Dx->DevicePnpState;
> +    Dx->DevicePnpState = State;
> +}
> +
> +static FORCEINLINE VOID
> +__FdoRestoreDevicePnpState(
> +    IN  PXENDISK_FDO        Fdo,
> +    IN  DEVICE_PNP_STATE    State
> +    )
> +{
> +    PXENDISK_DX             Dx = Fdo->Dx;
> +
> +    if (Dx->DevicePnpState == State)
> +        Dx->DevicePnpState = Dx->PreviousDevicePnpState;
> +}
> +
> +static FORCEINLINE DEVICE_PNP_STATE
> +__FdoGetDevicePnpState(
> +    IN  PXENDISK_FDO    Fdo
> +    )
> +{
> +    PXENDISK_DX         Dx = Fdo->Dx;
> +
> +    return Dx->DevicePnpState;
> +}
> +
> +static FORCEINLINE VOID
> +__FdoSetDevicePowerState(
> +    IN  PXENDISK_FDO        Fdo,
> +    IN  DEVICE_POWER_STATE  State
> +    )
> +{
> +    PXENDISK_DX             Dx = Fdo->Dx;
> +
> +    Dx->DevicePowerState = State;
> +}
> +
> +static FORCEINLINE DEVICE_POWER_STATE
> +__FdoGetDevicePowerState(
> +    IN  PXENDISK_FDO    Fdo
> +    )
> +{
> +    PXENDISK_DX         Dx = Fdo->Dx;
> +
> +    return Dx->DevicePowerState;
> +}
> +
> +static FORCEINLINE VOID
> +__FdoSetSystemPowerState(
> +    IN  PXENDISK_FDO        Fdo,
> +    IN  SYSTEM_POWER_STATE  State
> +    )
> +{
> +    PXENDISK_DX              Dx = Fdo->Dx;
> +
> +    Dx->SystemPowerState = State;
> +}
> +
> +static FORCEINLINE SYSTEM_POWER_STATE
> +__FdoGetSystemPowerState(
> +    IN  PXENDISK_FDO    Fdo
> +    )
> +{
> +    PXENDISK_DX         Dx = Fdo->Dx;
> +
> +    return Dx->SystemPowerState;
> +}
> +
> +static FORCEINLINE PDEVICE_OBJECT
> +__FdoGetPhysicalDeviceObject(
> +    IN  PXENDISK_FDO    Fdo
> +    )
> +{
> +    return Fdo->PhysicalDeviceObject;
> +}
> +
> +VOID
> +FdoAddPhysicalDeviceObject(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PDEVICE_OBJECT  DeviceObject
> +    )
> +{
> +    PXENDISK_DX         Dx;
> +
> +    Dx = (PXENDISK_DX)DeviceObject->DeviceExtension;
> +    ASSERT3U(Dx->Type, ==, PHYSICAL_DEVICE_OBJECT);
> +
> +    InsertTailList(&Fdo->Dx->ListEntry, &Dx->ListEntry);
> +    ASSERT3U(Fdo->References, !=, 0);
> +    Fdo->References++;
> +}
> +
> +VOID
> +FdoRemovePhysicalDeviceObject(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PDEVICE_OBJECT  DeviceObject
> +    )
> +{
> +    PXENDISK_DX         Dx;
> +
> +    Dx = (PXENDISK_DX)DeviceObject->DeviceExtension;
> +    ASSERT3U(Dx->Type, ==, PHYSICAL_DEVICE_OBJECT);
> +
> +    RemoveEntryList(&Dx->ListEntry);
> +    ASSERT3U(Fdo->References, !=, 0);
> +    --Fdo->References;
> +}
> +
> +static FORCEINLINE VOID
> +__FdoAcquireMutex(
> +    IN  PXENDISK_FDO     Fdo
> +    )
> +{
> +    AcquireMutex(&Fdo->Mutex);
> +}
> +
> +VOID
> +FdoAcquireMutex(
> +    IN  PXENDISK_FDO     Fdo
> +    )
> +{
> +    __FdoAcquireMutex(Fdo);
> +}
> +
> +static FORCEINLINE VOID
> +__FdoReleaseMutex(
> +    IN  PXENDISK_FDO     Fdo
> +    )
> +{
> +    ReleaseMutex(&Fdo->Mutex);
> +}
> +
> +VOID
> +FdoReleaseMutex(
> +    IN  PXENDISK_FDO     Fdo
> +    )
> +{
> +    __FdoReleaseMutex(Fdo);
> +
> +    if (Fdo->References == 0)
> +        FdoDestroy(Fdo);
> +}
> +
> +static FORCEINLINE VOID
> +__FdoEnumerate(
> +    IN  PXENDISK_FDO        Fdo,
> +    IN  PDEVICE_RELATIONS   Relations
> +    )
> +{
> +    PDEVICE_OBJECT          *PhysicalDeviceObject;
> +    ULONG                   Count;
> +    PLIST_ENTRY             ListEntry;
> +    ULONG                   Index;
> +    NTSTATUS                status;
> +
> +    Count = Relations->Count;
> +    ASSERT(Count != 0);
> +
> +    PhysicalDeviceObject = __FdoAllocate(sizeof (PDEVICE_OBJECT) *
> Count);
> +
> +    status = STATUS_NO_MEMORY;
> +    if (PhysicalDeviceObject == NULL)
> +        goto fail1;
> +
> +    RtlCopyMemory(PhysicalDeviceObject,
> +                  Relations->Objects,
> +                  sizeof (PDEVICE_OBJECT) * Count);
> +
> +    AcquireMutex(&Fdo->Mutex);
> +
> +    // Remove any PDOs that do not appear in the device list
> +    ListEntry = Fdo->Dx->ListEntry.Flink;
> +    while (ListEntry != &Fdo->Dx->ListEntry) {
> +        PLIST_ENTRY     Next = ListEntry->Flink;
> +        PXENDISK_DX     Dx = CONTAINING_RECORD(ListEntry, XENDISK_DX,
> ListEntry);
> +        PXENDISK_PDO    Pdo = Dx->Pdo;
> +        BOOLEAN         Missing;
> +
> +        Missing = TRUE;
> +        for (Index = 0; Index < Count; Index++) {
> +            if (PdoGetPhysicalDeviceObject(Pdo) ==
> PhysicalDeviceObject[Index]) {
> +                Missing = FALSE;
> +#pragma prefast(suppress:6387)  // PhysicalDeviceObject[Index] could be
> NULL
> +                ObDereferenceObject(PhysicalDeviceObject[Index]);
> +                PhysicalDeviceObject[Index] = NULL; // avoid duplication
> +                break;
> +            }
> +        }
> +
> +        if (Missing && !PdoIsMissing(Pdo)) {
> +            if (PdoGetDevicePnpState(Pdo) == Present) {
> +                PdoSetDevicePnpState(Pdo, Deleted);
> +                PdoDestroy(Pdo);
> +            } else {
> +                PdoSetMissing(Pdo, "device disappeared");
> +            }
> +        }
> +
> +        ListEntry = Next;
> +    }
> +
> +    // Walk the list and create PDO filters for any new devices
> +    for (Index = 0; Index < Count; Index++) {
> +#pragma warning(suppress:6385)  // Reading invalid data from
> 'PhysicalDeviceObject'
> +        if (PhysicalDeviceObject[Index] != NULL) {
> +            (VOID) PdoCreate(Fdo,
> +                             PhysicalDeviceObject[Index]);
> +            ObDereferenceObject(PhysicalDeviceObject[Index]);
> +        }
> +    }
> +
> +    ReleaseMutex(&Fdo->Mutex);
> +
> +    __FdoFree(PhysicalDeviceObject);
> +    return;
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__FdoForwardIrpSynchronously(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PKEVENT             Event = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +    UNREFERENCED_PARAMETER(Irp);
> +
> +    KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
> +
> +    return STATUS_MORE_PROCESSING_REQUIRED;
> +}
> +
> +static NTSTATUS
> +FdoForwardIrpSynchronously(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    KEVENT              Event;
> +    NTSTATUS            status;
> +
> +    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
> +
> +    KeInitializeEvent(&Event, NotificationEvent, FALSE);
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __FdoForwardIrpSynchronously,
> +                           &Event,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
> +    if (status == STATUS_PENDING) {
> +        (VOID) KeWaitForSingleObject(&Event,
> +                                     Executive,
> +                                     KernelMode,
> +                                     FALSE,
> +                                     NULL);
> +        status = Irp->IoStatus.Status;
> +    } else {
> +        ASSERT3U(status, ==, Irp->IoStatus.Status);
> +    }
> +
> +    return status;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +FdoStartDevice(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    POWER_STATE         PowerState;
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    status = FdoForwardIrpSynchronously(Fdo, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail2;
> +
> +    __FdoSetSystemPowerState(Fdo, PowerSystemWorking);
> +    __FdoSetDevicePowerState(Fdo, PowerDeviceD0);
> +
> +    PowerState.DeviceState = PowerDeviceD0;
> +    PoSetPowerState(Fdo->Dx->DeviceObject,
> +                    DevicePowerState,
> +                    PowerState);
> +
> +    __FdoSetDevicePnpState(Fdo, Started);
> +
> +    IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +
> +fail2:
> +    Error("fail2\n");
> +
> +    IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__FdoQueryStopDevice(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_FDO        Fdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +FdoQueryStopDevice(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    __FdoSetDevicePnpState(Fdo, StopPending);
> +    Irp->IoStatus.Status = STATUS_SUCCESS;
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __FdoQueryStopDevice,
> +                           Fdo,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
> +
> +    return status;
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__FdoCancelStopDevice(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_FDO        Fdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +FdoCancelStopDevice(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    Irp->IoStatus.Status = STATUS_SUCCESS;
> +
> +    __FdoRestoreDevicePnpState(Fdo, StopPending);
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __FdoCancelStopDevice,
> +                           Fdo,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
> +
> +    return status;
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__FdoStopDevice(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_FDO        Fdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +FdoStopDevice(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    POWER_STATE         PowerState;
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    if (__FdoGetDevicePowerState(Fdo) != PowerDeviceD0)
> +        goto done;
> +
> +    PowerState.DeviceState = PowerDeviceD3;
> +    PoSetPowerState(Fdo->Dx->DeviceObject,
> +                    DevicePowerState,
> +                    PowerState);
> +
> +    __FdoSetDevicePowerState(Fdo, PowerDeviceD3);
> +    __FdoSetSystemPowerState(Fdo, PowerSystemShutdown);
> +
> +done:
> +    __FdoSetDevicePnpState(Fdo, Stopped);
> +    Irp->IoStatus.Status = STATUS_SUCCESS;
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __FdoStopDevice,
> +                           Fdo,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
> +
> +    return status;
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__FdoQueryRemoveDevice(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_FDO        Fdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +FdoQueryRemoveDevice(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    __FdoSetDevicePnpState(Fdo, RemovePending);
> +    Irp->IoStatus.Status = STATUS_SUCCESS;
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __FdoQueryRemoveDevice,
> +                           Fdo,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
> +
> +    return status;
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__FdoCancelRemoveDevice(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_FDO        Fdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +FdoCancelRemoveDevice(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    __FdoRestoreDevicePnpState(Fdo, RemovePending);
> +    Irp->IoStatus.Status = STATUS_SUCCESS;
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __FdoCancelRemoveDevice,
> +                           Fdo,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
> +
> +    return status;
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__FdoSurpriseRemoval(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_FDO        Fdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +FdoSurpriseRemoval(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    __FdoSetDevicePnpState(Fdo, SurpriseRemovePending);
> +    Irp->IoStatus.Status = STATUS_SUCCESS;
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __FdoSurpriseRemoval,
> +                           Fdo,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
> +
> +    return status;
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +FdoRemoveDevice(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    POWER_STATE         PowerState;
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    if (__FdoGetDevicePowerState(Fdo) != PowerDeviceD0)
> +        goto done;
> +
> +    PowerState.DeviceState = PowerDeviceD3;
> +    PoSetPowerState(Fdo->Dx->DeviceObject,
> +                    DevicePowerState,
> +                    PowerState);
> +
> +    __FdoSetDevicePowerState(Fdo, PowerDeviceD3);
> +    __FdoSetSystemPowerState(Fdo, PowerSystemShutdown);
> +
> +done:
> +    __FdoSetDevicePnpState(Fdo, Deleted);
> +
> +    IoReleaseRemoveLockAndWait(&Fdo->Dx->RemoveLock, Irp);
> +
> +    status = FdoForwardIrpSynchronously(Fdo, Irp);
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    AcquireMutex(&Fdo->Mutex);
> +    ASSERT3U(Fdo->References, !=, 0);
> +    --Fdo->References;
> +    ReleaseMutex(&Fdo->Mutex);
> +
> +    if (Fdo->References == 0)
> +        FdoDestroy(Fdo);
> +
> +    return status;
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__FdoQueryDeviceRelations(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PKEVENT             Event = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +    UNREFERENCED_PARAMETER(Irp);
> +
> +    KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
> +
> +    return STATUS_MORE_PROCESSING_REQUIRED;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +FdoQueryDeviceRelations(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    KEVENT              Event;
> +    PIO_STACK_LOCATION  StackLocation;
> +    ULONG               Size;
> +    PDEVICE_RELATIONS   Relations;
> +    PLIST_ENTRY         ListEntry;
> +    ULONG               Count;
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    KeInitializeEvent(&Event, NotificationEvent, FALSE);
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __FdoQueryDeviceRelations,
> +                           &Event,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
> +    if (status == STATUS_PENDING) {
> +        (VOID) KeWaitForSingleObject(&Event,
> +                                     Executive,
> +                                     KernelMode,
> +                                     FALSE,
> +                                     NULL);
> +        status = Irp->IoStatus.Status;
> +    } else {
> +        ASSERT3U(status, ==, Irp->IoStatus.Status);
> +    }
> +
> +    if (!NT_SUCCESS(status))
> +        goto fail2;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    if (StackLocation->Parameters.QueryDeviceRelations.Type !=
> BusRelations)
> +        goto done;
> +
> +    Relations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
> +
> +    if (Relations->Count != 0)
> +        __FdoEnumerate(Fdo, Relations);
> +
> +    ExFreePool(Relations);
> +
> +    AcquireMutex(&Fdo->Mutex);
> +
> +    Count = 0;
> +    for (ListEntry = Fdo->Dx->ListEntry.Flink;
> +         ListEntry != &Fdo->Dx->ListEntry;
> +         ListEntry = ListEntry->Flink)
> +        Count++;
> +
> +    Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) + (sizeof
> (DEVICE_OBJECT) * __min(Count, 1));
> +
> +    Relations = ExAllocatePoolWithTag(PagedPool, Size, 'TLIF');
> +
> +    status = STATUS_NO_MEMORY;
> +    if (Relations == NULL)
> +        goto fail3;
> +
> +    RtlZeroMemory(Relations, Size);
> +
> +    for (ListEntry = Fdo->Dx->ListEntry.Flink;
> +         ListEntry != &Fdo->Dx->ListEntry;
> +         ListEntry = ListEntry->Flink) {
> +        PXENDISK_DX     Dx = CONTAINING_RECORD(ListEntry, XENDISK_DX,
> ListEntry);
> +        PXENDISK_PDO    Pdo = Dx->Pdo;
> +
> +        ASSERT3U(Dx->Type, ==, PHYSICAL_DEVICE_OBJECT);
> +
> +        if (PdoGetDevicePnpState(Pdo) == Present)
> +            PdoSetDevicePnpState(Pdo, Enumerated);
> +
> +        ObReferenceObject(PdoGetPhysicalDeviceObject(Pdo));
> +        Relations->Objects[Relations->Count++] =
> PdoGetPhysicalDeviceObject(Pdo);
> +    }
> +
> +    ASSERT3U(Relations->Count, ==, Count);
> +
> +    Trace("%d PDO(s)\n", Relations->Count);
> +
> +    ReleaseMutex(&Fdo->Mutex);
> +
> +    Irp->IoStatus.Information = (ULONG_PTR)Relations;
> +    status = STATUS_SUCCESS;
> +
> +done:
> +    IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +
> +fail3:
> +    ReleaseMutex(&Fdo->Mutex);
> +
> +fail2:
> +    IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__FdoDispatchPnp(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_FDO        Fdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +FdoDispatchPnp(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    UCHAR               MinorFunction;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    MinorFunction = StackLocation->MinorFunction;
> +
> +    switch (StackLocation->MinorFunction) {
> +    case IRP_MN_START_DEVICE:
> +        status = FdoStartDevice(Fdo, Irp);
> +        break;
> +
> +    case IRP_MN_QUERY_STOP_DEVICE:
> +        status = FdoQueryStopDevice(Fdo, Irp);
> +        break;
> +
> +    case IRP_MN_CANCEL_STOP_DEVICE:
> +        status = FdoCancelStopDevice(Fdo, Irp);
> +        break;
> +
> +    case IRP_MN_STOP_DEVICE:
> +        status = FdoStopDevice(Fdo, Irp);
> +        break;
> +
> +    case IRP_MN_QUERY_REMOVE_DEVICE:
> +        status = FdoQueryRemoveDevice(Fdo, Irp);
> +        break;
> +
> +    case IRP_MN_SURPRISE_REMOVAL:
> +        status = FdoSurpriseRemoval(Fdo, Irp);
> +        break;
> +
> +    case IRP_MN_REMOVE_DEVICE:
> +        status = FdoRemoveDevice(Fdo, Irp);
> +        break;
> +
> +    case IRP_MN_CANCEL_REMOVE_DEVICE:
> +        status = FdoCancelRemoveDevice(Fdo, Irp);
> +        break;
> +
> +    case IRP_MN_QUERY_DEVICE_RELATIONS:
> +        status = FdoQueryDeviceRelations(Fdo, Irp);
> +        break;
> +
> +    default:
> +        status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +        if (!NT_SUCCESS(status))
> +            goto fail1;
> +
> +        IoCopyCurrentIrpStackLocationToNext(Irp);
> +        IoSetCompletionRoutine(Irp,
> +                               __FdoDispatchPnp,
> +                               Fdo,
> +                               TRUE,
> +                               TRUE,
> +                               TRUE);
> +
> +        status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
> +        break;
> +    }
> +
> +    return status;
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__FdoSetDevicePowerUp(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    DEVICE_POWER_STATE  DeviceState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
> +
> +    ASSERT3U(DeviceState, <,  __FdoGetDevicePowerState(Fdo));
> +
> +    status = FdoForwardIrpSynchronously(Fdo, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto done;
> +
> +    Verbose("%p: %s -> %s\n",
> +         Fdo->Dx->DeviceObject,
> +         PowerDeviceStateName(__FdoGetDevicePowerState(Fdo)),
> +         PowerDeviceStateName(DeviceState));
> +
> +    __FdoSetDevicePowerState(Fdo, DeviceState);
> +
> +done:
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__FdoSetDevicePowerDown(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    DEVICE_POWER_STATE  DeviceState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
> +
> +    ASSERT3U(DeviceState, >,  __FdoGetDevicePowerState(Fdo));
> +
> +    Verbose("%p: %s -> %s\n",
> +         Fdo->Dx->DeviceObject,
> +         PowerDeviceStateName(__FdoGetDevicePowerState(Fdo)),
> +         PowerDeviceStateName(DeviceState));
> +
> +    __FdoSetDevicePowerState(Fdo, DeviceState);
> +
> +    status = FdoForwardIrpSynchronously(Fdo, Irp);
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__FdoSetDevicePower(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    DEVICE_POWER_STATE  DeviceState;
> +    POWER_ACTION        PowerAction;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
> +    PowerAction = StackLocation->Parameters.Power.ShutdownType;
> +
> +    Trace("====> (%s:%s)\n",
> +          PowerDeviceStateName(DeviceState),
> +          PowerActionName(PowerAction));
> +
> +    if (DeviceState == __FdoGetDevicePowerState(Fdo)) {
> +        status = FdoForwardIrpSynchronously(Fdo, Irp);
> +        IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +        goto done;
> +    }
> +
> +    status = (DeviceState < __FdoGetDevicePowerState(Fdo)) ?
> +             __FdoSetDevicePowerUp(Fdo, Irp) :
> +             __FdoSetDevicePowerDown(Fdo, Irp);
> +
> +done:
> +    Trace("<==== (%s:%s)(%08x)\n",
> +          PowerDeviceStateName(DeviceState),
> +          PowerActionName(PowerAction),
> +          status);
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__FdoSetSystemPowerUp(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    SYSTEM_POWER_STATE  SystemState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    SystemState = StackLocation->Parameters.Power.State.SystemState;
> +
> +    ASSERT3U(SystemState, <,  __FdoGetSystemPowerState(Fdo));
> +
> +    status = FdoForwardIrpSynchronously(Fdo, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto done;
> +
> +    Verbose("%p: %s -> %s\n",
> +         Fdo->Dx->DeviceObject,
> +         PowerSystemStateName(__FdoGetSystemPowerState(Fdo)),
> +         PowerSystemStateName(SystemState));
> +
> +    __FdoSetSystemPowerState(Fdo, SystemState);
> +
> +done:
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__FdoSetSystemPowerDown(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    SYSTEM_POWER_STATE  SystemState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    SystemState = StackLocation->Parameters.Power.State.SystemState;
> +
> +    ASSERT3U(SystemState, >,  __FdoGetSystemPowerState(Fdo));
> +
> +    Verbose("%p: %s -> %s\n",
> +         Fdo->Dx->DeviceObject,
> +         PowerSystemStateName(__FdoGetSystemPowerState(Fdo)),
> +         PowerSystemStateName(SystemState));
> +
> +    __FdoSetSystemPowerState(Fdo, SystemState);
> +
> +    status = FdoForwardIrpSynchronously(Fdo, Irp);
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__FdoSetSystemPower(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    SYSTEM_POWER_STATE  SystemState;
> +    POWER_ACTION        PowerAction;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    SystemState = StackLocation->Parameters.Power.State.SystemState;
> +    PowerAction = StackLocation->Parameters.Power.ShutdownType;
> +
> +    Trace("====> (%s:%s)\n",
> +          PowerSystemStateName(SystemState),
> +          PowerActionName(PowerAction));
> +
> +    if (SystemState == __FdoGetSystemPowerState(Fdo)) {
> +        status = FdoForwardIrpSynchronously(Fdo, Irp);
> +        IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +        goto done;
> +    }
> +
> +    status = (SystemState < __FdoGetSystemPowerState(Fdo)) ?
> +             __FdoSetSystemPowerUp(Fdo, Irp) :
> +             __FdoSetSystemPowerDown(Fdo, Irp);
> +
> +done:
> +    Trace("<==== (%s:%s)(%08x)\n",
> +          PowerSystemStateName(SystemState),
> +          PowerActionName(PowerAction),
> +          status);
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__FdoQueryDevicePowerUp(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    DEVICE_POWER_STATE  DeviceState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
> +
> +    ASSERT3U(DeviceState, <,  __FdoGetDevicePowerState(Fdo));
> +
> +    status = FdoForwardIrpSynchronously(Fdo, Irp);
> +
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__FdoQueryDevicePowerDown(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    DEVICE_POWER_STATE  DeviceState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
> +
> +    ASSERT3U(DeviceState, >,  __FdoGetDevicePowerState(Fdo));
> +
> +    status = FdoForwardIrpSynchronously(Fdo, Irp);
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__FdoQueryDevicePower(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    DEVICE_POWER_STATE  DeviceState;
> +    POWER_ACTION        PowerAction;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
> +    PowerAction = StackLocation->Parameters.Power.ShutdownType;
> +
> +    Trace("====> (%s:%s)\n",
> +          PowerDeviceStateName(DeviceState),
> +          PowerActionName(PowerAction));
> +
> +    if (DeviceState == __FdoGetDevicePowerState(Fdo)) {
> +        status = FdoForwardIrpSynchronously(Fdo, Irp);
> +        IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +        goto done;
> +    }
> +
> +    status = (DeviceState < __FdoGetDevicePowerState(Fdo)) ?
> +             __FdoQueryDevicePowerUp(Fdo, Irp) :
> +             __FdoQueryDevicePowerDown(Fdo, Irp);
> +
> +done:
> +    Trace("<==== (%s:%s)(%08x)\n",
> +          PowerDeviceStateName(DeviceState),
> +          PowerActionName(PowerAction),
> +          status);
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__FdoQuerySystemPowerUp(
> +    IN  PXENDISK_FDO     Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    SYSTEM_POWER_STATE  SystemState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    SystemState = StackLocation->Parameters.Power.State.SystemState;
> +
> +    ASSERT3U(SystemState, <,  __FdoGetSystemPowerState(Fdo));
> +
> +    status = FdoForwardIrpSynchronously(Fdo, Irp);
> +
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__FdoQuerySystemPowerDown(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    SYSTEM_POWER_STATE  SystemState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    SystemState = StackLocation->Parameters.Power.State.SystemState;
> +
> +    ASSERT3U(SystemState, >,  __FdoGetSystemPowerState(Fdo));
> +
> +    status = FdoForwardIrpSynchronously(Fdo, Irp);
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__FdoQuerySystemPower(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    SYSTEM_POWER_STATE  SystemState;
> +    POWER_ACTION        PowerAction;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    SystemState = StackLocation->Parameters.Power.State.SystemState;
> +    PowerAction = StackLocation->Parameters.Power.ShutdownType;
> +
> +    Trace("====> (%s:%s)\n",
> +          PowerSystemStateName(SystemState),
> +          PowerActionName(PowerAction));
> +
> +    if (SystemState == __FdoGetSystemPowerState(Fdo)) {
> +        status = FdoForwardIrpSynchronously(Fdo, Irp);
> +        IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +        goto done;
> +    }
> +
> +    status = (SystemState < __FdoGetSystemPowerState(Fdo)) ?
> +             __FdoQuerySystemPowerUp(Fdo, Irp) :
> +             __FdoQuerySystemPowerDown(Fdo, Irp);
> +
> +done:
> +    Trace("<==== (%s:%s)(%08x)\n",
> +          PowerSystemStateName(SystemState),
> +          PowerActionName(PowerAction),
> +          status);
> +
> +    return status;
> +}
> +
> +static NTSTATUS
> +FdoDevicePower(
> +    IN  PXENDISK_THREAD Self,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_FDO        Fdo = Context;
> +    PKEVENT             Event;
> +
> +    Event = ThreadGetEvent(Self);
> +
> +    for (;;) {
> +        PIRP                Irp;
> +        PIO_STACK_LOCATION  StackLocation;
> +        UCHAR               MinorFunction;
> +
> +        if (Fdo->DevicePowerIrp == NULL) {
> +            (VOID) KeWaitForSingleObject(Event,
> +                                         Executive,
> +                                         KernelMode,
> +                                         FALSE,
> +                                         NULL);
> +            KeClearEvent(Event);
> +        }
> +
> +        if (ThreadIsAlerted(Self))
> +            break;
> +
> +        Irp = Fdo->DevicePowerIrp;
> +
> +        if (Irp == NULL)
> +            continue;
> +
> +        Fdo->DevicePowerIrp = NULL;
> +        KeMemoryBarrier();
> +
> +        StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +        MinorFunction = StackLocation->MinorFunction;
> +
> +        switch (StackLocation->MinorFunction) {
> +        case IRP_MN_SET_POWER:
> +            (VOID) __FdoSetDevicePower(Fdo, Irp);
> +            break;
> +
> +        case IRP_MN_QUERY_POWER:
> +            (VOID) __FdoQueryDevicePower(Fdo, Irp);
> +            break;
> +
> +        default:
> +            ASSERT(FALSE);
> +            break;
> +        }
> +
> +        IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    }
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static NTSTATUS
> +FdoSystemPower(
> +    IN  PXENDISK_THREAD Self,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_FDO        Fdo = Context;
> +    PKEVENT             Event;
> +
> +    Event = ThreadGetEvent(Self);
> +
> +    for (;;) {
> +        PIRP                Irp;
> +        PIO_STACK_LOCATION  StackLocation;
> +        UCHAR               MinorFunction;
> +
> +        if (Fdo->SystemPowerIrp == NULL) {
> +            (VOID) KeWaitForSingleObject(Event,
> +                                         Executive,
> +                                         KernelMode,
> +                                         FALSE,
> +                                         NULL);
> +            KeClearEvent(Event);
> +        }
> +
> +        if (ThreadIsAlerted(Self))
> +            break;
> +
> +        Irp = Fdo->SystemPowerIrp;
> +
> +        if (Irp == NULL)
> +            continue;
> +
> +        Fdo->SystemPowerIrp = NULL;
> +        KeMemoryBarrier();
> +
> +        StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +        MinorFunction = StackLocation->MinorFunction;
> +
> +        switch (StackLocation->MinorFunction) {
> +        case IRP_MN_SET_POWER:
> +            (VOID) __FdoSetSystemPower(Fdo, Irp);
> +            break;
> +
> +        case IRP_MN_QUERY_POWER:
> +            (VOID) __FdoQuerySystemPower(Fdo, Irp);
> +            break;
> +
> +        default:
> +            ASSERT(FALSE);
> +            break;
> +        }
> +
> +        IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    }
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__FdoDispatchPower(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_FDO        Fdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +FdoDispatchPower(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    UCHAR               MinorFunction;
> +    POWER_STATE_TYPE    PowerType;
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    MinorFunction = StackLocation->MinorFunction;
> +
> +    if (MinorFunction != IRP_MN_QUERY_POWER &&
> +        MinorFunction != IRP_MN_SET_POWER) {
> +        IoCopyCurrentIrpStackLocationToNext(Irp);
> +        IoSetCompletionRoutine(Irp,
> +                               __FdoDispatchPower,
> +                               Fdo,
> +                               TRUE,
> +                               TRUE,
> +                               TRUE);
> +
> +        status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
> +
> +        goto done;
> +    }
> +
> +    PowerType = StackLocation->Parameters.Power.Type;
> +
> +    Trace("====> (%02x:%s)\n",
> +          MinorFunction,
> +          PowerMinorFunctionName(MinorFunction));
> +
> +    switch (PowerType) {
> +    case DevicePowerState:
> +        IoMarkIrpPending(Irp);
> +
> +        ASSERT3P(Fdo->DevicePowerIrp, ==, NULL);
> +        Fdo->DevicePowerIrp = Irp;
> +        KeMemoryBarrier();
> +
> +        ThreadWake(Fdo->DevicePowerThread);
> +
> +        status = STATUS_PENDING;
> +        break;
> +
> +    case SystemPowerState:
> +        IoMarkIrpPending(Irp);
> +
> +        ASSERT3P(Fdo->SystemPowerIrp, ==, NULL);
> +        Fdo->SystemPowerIrp = Irp;
> +        KeMemoryBarrier();
> +
> +        ThreadWake(Fdo->SystemPowerThread);
> +
> +        status = STATUS_PENDING;
> +        break;
> +
> +    default:
> +        IoCopyCurrentIrpStackLocationToNext(Irp);
> +        IoSetCompletionRoutine(Irp,
> +                               __FdoDispatchPower,
> +                               Fdo,
> +                               TRUE,
> +                               TRUE,
> +                               TRUE);
> +
> +        status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
> +        break;
> +    }
> +
> +    Trace("<==== (%02x:%s) (%08x)\n",
> +          MinorFunction,
> +          PowerMinorFunctionName(MinorFunction),
> +          status);
> +
> +done:
> +    return status;
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__FdoDispatchDefault(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_FDO        Fdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +FdoDispatchDefault(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __FdoDispatchDefault,
> +                           Fdo,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
> +
> +    return status;
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +NTSTATUS
> +FdoDispatch(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +
> +    switch (StackLocation->MajorFunction) {
> +    case IRP_MJ_PNP:
> +        status = FdoDispatchPnp(Fdo, Irp);
> +        break;
> +
> +    case IRP_MJ_POWER:
> +        status = FdoDispatchPower(Fdo, Irp);
> +        break;
> +
> +    default:
> +        status = FdoDispatchDefault(Fdo, Irp);
> +        break;
> +    }
> +
> +    return status;
> +}
> +
> +NTSTATUS
> +FdoCreate(
> +    IN  PDEVICE_OBJECT  PhysicalDeviceObject
> +    )
> +{
> +    PDEVICE_OBJECT      LowerDeviceObject;
> +    ULONG               DeviceType;
> +    PDEVICE_OBJECT      FilterDeviceObject;
> +    PXENDISK_DX         Dx;
> +    PXENDISK_FDO        Fdo;
> +    NTSTATUS            status;
> +
> +    LowerDeviceObject =
> IoGetAttachedDeviceReference(PhysicalDeviceObject);
> +    DeviceType = LowerDeviceObject->DeviceType;
> +    ObDereferenceObject(LowerDeviceObject);
> +
> +#pragma prefast(suppress:28197) // Possibly leaking memory
> 'FilterDeviceObject'
> +    status = IoCreateDevice(DriverGetDriverObject(),
> +                            sizeof (XENDISK_DX),
> +                            NULL,
> +                            DeviceType,
> +                            FILE_DEVICE_SECURE_OPEN,
> +                            FALSE,
> +                            &FilterDeviceObject);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    Dx = (PXENDISK_DX)FilterDeviceObject->DeviceExtension;
> +    RtlZeroMemory(Dx, sizeof (XENDISK_DX));
> +
> +    Dx->Type = FUNCTION_DEVICE_OBJECT;
> +    Dx->DeviceObject = FilterDeviceObject;
> +    Dx->DevicePnpState = Added;
> +    Dx->SystemPowerState = PowerSystemShutdown;
> +    Dx->DevicePowerState = PowerDeviceD3;
> +
> +    IoInitializeRemoveLock(&Dx->RemoveLock, FDO_TAG, 0, 0);
> +
> +    Fdo = __FdoAllocate(sizeof (XENDISK_FDO));
> +
> +    status = STATUS_NO_MEMORY;
> +    if (Fdo == NULL)
> +        goto fail2;
> +
> +    LowerDeviceObject = IoAttachDeviceToDeviceStack(FilterDeviceObject,
> +                                                    PhysicalDeviceObject);
> +
> +    status = STATUS_UNSUCCESSFUL;
> +    if (LowerDeviceObject == NULL)
> +        goto fail3;
> +
> +    Fdo->Dx = Dx;
> +    Fdo->PhysicalDeviceObject = PhysicalDeviceObject;
> +    Fdo->LowerDeviceObject = LowerDeviceObject;
> +
> +    status = ThreadCreate(FdoSystemPower, Fdo, &Fdo-
> >SystemPowerThread);
> +    if (!NT_SUCCESS(status))
> +        goto fail4;
> +
> +    status = ThreadCreate(FdoDevicePower, Fdo, &Fdo-
> >DevicePowerThread);
> +    if (!NT_SUCCESS(status))
> +        goto fail5;
> +
> +    InitializeMutex(&Fdo->Mutex);
> +    InitializeListHead(&Dx->ListEntry);
> +    Fdo->References = 1;
> +
> +    Verbose("%p\n", FilterDeviceObject);
> +
> +    Dx->Fdo = Fdo;
> +
> +#pragma prefast(suppress:28182)  // Dereferencing NULL pointer
> +    FilterDeviceObject->DeviceType = LowerDeviceObject->DeviceType;
> +    FilterDeviceObject->Characteristics = LowerDeviceObject-
> >Characteristics;
> +
> +    FilterDeviceObject->Flags |= LowerDeviceObject->Flags;
> +    FilterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
> +
> +    return STATUS_SUCCESS;
> +
> +fail5:
> +    Error("fail5\n");
> +
> +    ThreadAlert(Fdo->SystemPowerThread);
> +    ThreadJoin(Fdo->SystemPowerThread);
> +    Fdo->SystemPowerThread = NULL;
> +
> +fail4:
> +    Error("fail4\n");
> +
> +    Fdo->PhysicalDeviceObject = NULL;
> +    Fdo->LowerDeviceObject = NULL;
> +    Fdo->Dx = NULL;
> +
> +    IoDetachDevice(LowerDeviceObject);
> +
> +fail3:
> +    Error("fail3\n");
> +
> +    ASSERT(IsZeroMemory(Fdo, sizeof (XENDISK_FDO)));
> +    __FdoFree(Fdo);
> +
> +fail2:
> +    Error("fail2\n");
> +
> +    IoDeleteDevice(FilterDeviceObject);
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    return status;
> +}
> +
> +VOID
> +FdoDestroy(
> +    IN  PXENDISK_FDO    Fdo
> +    )
> +{
> +    PDEVICE_OBJECT      LowerDeviceObject = Fdo->LowerDeviceObject;
> +    PXENDISK_DX         Dx = Fdo->Dx;
> +    PDEVICE_OBJECT      FilterDeviceObject = Dx->DeviceObject;
> +
> +    ASSERT(IsListEmpty(&Dx->ListEntry));
> +    ASSERT3U(Fdo->References, ==, 0);
> +    ASSERT3U(__FdoGetDevicePnpState(Fdo), ==, Deleted);
> +
> +    Dx->Fdo = NULL;
> +
> +    RtlZeroMemory(&Fdo->Mutex, sizeof (MUTEX));
> +
> +    ThreadAlert(Fdo->DevicePowerThread);
> +    ThreadJoin(Fdo->DevicePowerThread);
> +    Fdo->DevicePowerThread = NULL;
> +
> +    ThreadAlert(Fdo->SystemPowerThread);
> +    ThreadJoin(Fdo->SystemPowerThread);
> +    Fdo->SystemPowerThread = NULL;
> +
> +    Fdo->LowerDeviceObject = NULL;
> +    Fdo->PhysicalDeviceObject = NULL;
> +    Fdo->Dx = NULL;
> +
> +    IoDetachDevice(LowerDeviceObject);
> +
> +    ASSERT(IsZeroMemory(Fdo, sizeof (XENDISK_FDO)));
> +    __FdoFree(Fdo);
> +
> +    IoDeleteDevice(FilterDeviceObject);
> +}
> diff --git a/src/xendisk/fdo.h b/src/xendisk/fdo.h
> new file mode 100644
> index 0000000..8aa0529
> --- /dev/null
> +++ b/src/xendisk/fdo.h
> @@ -0,0 +1,78 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#ifndef _XENDISK_FDO_H
> +#define _XENDISK_FDO_H
> +
> +#include <ntddk.h>
> +#include "types.h"
> +
> +typedef struct _XENDISK_FDO XENDISK_FDO, *PXENDISK_FDO;
> +
> +extern VOID
> +FdoAddPhysicalDeviceObject(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PDEVICE_OBJECT  DeviceObject
> +    );
> +
> +extern VOID
> +FdoRemovePhysicalDeviceObject(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PDEVICE_OBJECT  DeviceObject
> +    );
> +
> +extern VOID
> +FdoAcquireMutex(
> +    IN  PXENDISK_FDO     Fdo
> +    );
> +
> +extern VOID
> +FdoReleaseMutex(
> +    IN  PXENDISK_FDO     Fdo
> +    );
> +
> +extern NTSTATUS
> +FdoDispatch(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PIRP            Irp
> +    );
> +
> +extern NTSTATUS
> +FdoCreate(
> +    IN  PDEVICE_OBJECT  PhysicalDeviceObject
> +    );
> +
> +extern VOID
> +FdoDestroy(
> +    IN  PXENDISK_FDO    Fdo
> +    );
> +
> +#endif // _XENDISK_FDO_H
> diff --git a/src/xendisk/mutex.h b/src/xendisk/mutex.h
> new file mode 100644
> index 0000000..bcc2414
> --- /dev/null
> +++ b/src/xendisk/mutex.h
> @@ -0,0 +1,113 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#ifndef _XENDISK_MUTEX_H
> +#define _XENDISK_MUTEX_H
> +
> +#include <ntddk.h>
> +
> +#include "assert.h"
> +
> +typedef struct _MUTEX {
> +    PKTHREAD    Owner;
> +    KEVENT      Event;
> +} MUTEX, *PMUTEX;
> +
> +static FORCEINLINE VOID
> +InitializeMutex(
> +    IN  PMUTEX  Mutex
> +    )
> +{
> +    RtlZeroMemory(Mutex, sizeof (MUTEX));
> +
> +    KeInitializeEvent(&Mutex->Event, SynchronizationEvent, TRUE);
> +}
> +
> +static FORCEINLINE BOOLEAN
> +__drv_maxIRQL(PASSIVE_LEVEL)
> +TryAcquireMutex(
> +    IN  PMUTEX      Mutex
> +    )
> +{
> +    LARGE_INTEGER   Timeout;
> +    NTSTATUS        status;
> +
> +    Timeout.QuadPart = 0;
> +
> +    status = KeWaitForSingleObject(&Mutex->Event,
> +                                   Executive,
> +                                   KernelMode,
> +                                   FALSE,
> +                                   &Timeout);
> +    if (status == STATUS_TIMEOUT)
> +        return FALSE;
> +
> +    ASSERT(NT_SUCCESS(status));
> +
> +    ASSERT3P(Mutex->Owner, ==, NULL);
> +    Mutex->Owner = KeGetCurrentThread();
> +
> +    return TRUE;
> +}
> +
> +static FORCEINLINE VOID
> +__drv_maxIRQL(PASSIVE_LEVEL)
> +AcquireMutex(
> +    IN  PMUTEX  Mutex
> +    )
> +{
> +    NTSTATUS    status;
> +
> +    status = KeWaitForSingleObject(&Mutex->Event,
> +                                   Executive,
> +                                   KernelMode,
> +                                   FALSE,
> +                                   NULL);
> +
> +    ASSERT(NT_SUCCESS(status));
> +
> +    ASSERT3P(Mutex->Owner, ==, NULL);
> +    Mutex->Owner = KeGetCurrentThread();
> +}
> +
> +static FORCEINLINE VOID
> +__drv_maxIRQL(PASSIVE_LEVEL)
> +ReleaseMutex(
> +    IN  PMUTEX  Mutex
> +    )
> +{
> +    ASSERT3P(Mutex->Owner, ==, KeGetCurrentThread());
> +    Mutex->Owner = NULL;
> +
> +    KeSetEvent(&Mutex->Event, IO_NO_INCREMENT, FALSE);
> +}
> +
> +#endif  // _XENDISK_MUTEX_H
> diff --git a/src/xendisk/pdo.c b/src/xendisk/pdo.c
> new file mode 100644
> index 0000000..3de958a
> --- /dev/null
> +++ b/src/xendisk/pdo.c
> @@ -0,0 +1,2079 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#define INITGUID 1
> +
> +#include <ntddk.h>
> +#include <wdmguid.h>
> +#include <ntstrsafe.h>
> +#include <stdlib.h>
> +#include <storport.h>
> +#include <Ntddstor.h>
> +#include <Ntddscsi.h>
> +#include <names.h>
> +
> +#include "fdo.h"
> +#include "pdo.h"
> +#include "driver.h"
> +#include "thread.h"
> +#include "debug.h"
> +#include "assert.h"
> +#include "util.h"
> +
> +#define PDO_TAG 'ODP'
> +
> +struct _XENDISK_PDO {
> +    PXENDISK_DX                 Dx;
> +    PDEVICE_OBJECT              LowerDeviceObject;
> +    PDEVICE_OBJECT              PhysicalDeviceObject;
> +
> +    PXENDISK_THREAD             SystemPowerThread;
> +    PIRP                        SystemPowerIrp;
> +    PXENDISK_THREAD             DevicePowerThread;
> +    PIRP                        DevicePowerIrp;
> +
> +    PXENDISK_FDO                Fdo;
> +    BOOLEAN                     Missing;
> +    const CHAR                  *Reason;
> +
> +    ULONG                       SectorSize;
> +};
> +
> +static FORCEINLINE PVOID
> +__PdoAllocate(
> +    IN  ULONG   Length
> +    )
> +{
> +    return __AllocateNonPagedPoolWithTag(__FUNCTION__, __LINE__,
> Length, PDO_TAG);
> +}
> +
> +static FORCEINLINE VOID
> +__PdoFree(
> +    IN  PVOID   Buffer
> +    )
> +{
> +    __FreePoolWithTag(Buffer, PDO_TAG);
> +}
> +
> +static FORCEINLINE VOID
> +__PdoSetDevicePnpState(
> +    IN  PXENDISK_PDO        Pdo,
> +    IN  DEVICE_PNP_STATE    State
> +    )
> +{
> +    PXENDISK_DX             Dx = Pdo->Dx;
> +
> +    // We can never transition out of the deleted state
> +    ASSERT(Dx->DevicePnpState != Deleted || State == Deleted);
> +
> +    Dx->PreviousDevicePnpState = Dx->DevicePnpState;
> +    Dx->DevicePnpState = State;
> +}
> +
> +VOID
> +PdoSetDevicePnpState(
> +    IN  PXENDISK_PDO        Pdo,
> +    IN  DEVICE_PNP_STATE    State
> +    )
> +{
> +    __PdoSetDevicePnpState(Pdo, State);
> +}
> +
> +static FORCEINLINE VOID
> +__PdoRestoreDevicePnpState(
> +    IN  PXENDISK_PDO        Pdo,
> +    IN  DEVICE_PNP_STATE    State
> +    )
> +{
> +    PXENDISK_DX             Dx = Pdo->Dx;
> +
> +    if (Dx->DevicePnpState == State)
> +        Dx->DevicePnpState = Dx->PreviousDevicePnpState;
> +}
> +
> +static FORCEINLINE DEVICE_PNP_STATE
> +__PdoGetDevicePnpState(
> +    IN  PXENDISK_PDO    Pdo
> +    )
> +{
> +    PXENDISK_DX         Dx = Pdo->Dx;
> +
> +    return Dx->DevicePnpState;
> +}
> +
> +DEVICE_PNP_STATE
> +PdoGetDevicePnpState(
> +    IN  PXENDISK_PDO    Pdo
> +    )
> +{
> +    return __PdoGetDevicePnpState(Pdo);
> +}
> +
> +static FORCEINLINE VOID
> +__PdoSetDevicePowerState(
> +    IN  PXENDISK_PDO        Pdo,
> +    IN  DEVICE_POWER_STATE  State
> +    )
> +{
> +    PXENDISK_DX             Dx = Pdo->Dx;
> +
> +    Dx->DevicePowerState = State;
> +}
> +
> +static FORCEINLINE DEVICE_POWER_STATE
> +__PdoGetDevicePowerState(
> +    IN  PXENDISK_PDO    Pdo
> +    )
> +{
> +    PXENDISK_DX         Dx = Pdo->Dx;
> +
> +    return Dx->DevicePowerState;
> +}
> +
> +static FORCEINLINE VOID
> +__PdoSetSystemPowerState(
> +    IN  PXENDISK_PDO        Pdo,
> +    IN  SYSTEM_POWER_STATE  State
> +    )
> +{
> +    PXENDISK_DX             Dx = Pdo->Dx;
> +
> +    Dx->SystemPowerState = State;
> +}
> +
> +static FORCEINLINE SYSTEM_POWER_STATE
> +__PdoGetSystemPowerState(
> +    IN  PXENDISK_PDO    Pdo
> +    )
> +{
> +    PXENDISK_DX         Dx = Pdo->Dx;
> +
> +    return Dx->SystemPowerState;
> +}
> +
> +PDEVICE_OBJECT
> +PdoGetPhysicalDeviceObject(
> +    IN  PXENDISK_PDO    Pdo
> +    )
> +{
> +    return Pdo->PhysicalDeviceObject;
> +}
> +
> +static FORCEINLINE VOID
> +__PdoSetMissing(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  const CHAR      *Reason
> +    )
> +{
> +    Pdo->Reason = Reason;
> +    Pdo->Missing = TRUE;
> +}
> +
> +VOID
> +PdoSetMissing(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  const CHAR      *Reason
> +    )
> +{
> +    __PdoSetMissing(Pdo, Reason);
> +}
> +
> +static FORCEINLINE BOOLEAN
> +__PdoIsMissing(
> +    IN  PXENDISK_PDO    Pdo
> +    )
> +{
> +    return Pdo->Missing;
> +}
> +
> +BOOLEAN
> +PdoIsMissing(
> +    IN  PXENDISK_PDO    Pdo
> +    )
> +{
> +    return __PdoIsMissing(Pdo);
> +}
> +
> +static FORCEINLINE VOID
> +__PdoLink(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PXENDISK_FDO    Fdo
> +    )
> +{
> +    Pdo->Fdo = Fdo;
> +    FdoAddPhysicalDeviceObject(Fdo, Pdo->Dx->DeviceObject);
> +}
> +
> +static FORCEINLINE VOID
> +__PdoUnlink(
> +    IN  PXENDISK_PDO    Pdo
> +    )
> +{
> +    PXENDISK_FDO        Fdo = Pdo->Fdo;
> +
> +    ASSERT(Fdo != NULL);
> +
> +    FdoRemovePhysicalDeviceObject(Fdo, Pdo->Dx->DeviceObject);
> +
> +    Pdo->Fdo = NULL;
> +}
> +
> +static FORCEINLINE PXENDISK_FDO
> +__PdoGetFdo(
> +    IN  PXENDISK_PDO Pdo
> +    )
> +{
> +    return Pdo->Fdo;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__PdoForwardIrpSynchronously(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PKEVENT             Event = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +    UNREFERENCED_PARAMETER(Irp);
> +
> +    KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
> +
> +    return STATUS_MORE_PROCESSING_REQUIRED;
> +}
> +
> +static NTSTATUS
> +PdoForwardIrpSynchronously(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    KEVENT              Event;
> +    NTSTATUS            status;
> +
> +    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
> +
> +    KeInitializeEvent(&Event, NotificationEvent, FALSE);
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __PdoForwardIrpSynchronously,
> +                           &Event,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
> +    if (status == STATUS_PENDING) {
> +        (VOID) KeWaitForSingleObject(&Event,
> +                                     Executive,
> +                                     KernelMode,
> +                                     FALSE,
> +                                     NULL);
> +        status = Irp->IoStatus.Status;
> +    } else {
> +        ASSERT3U(status, ==, Irp->IoStatus.Status);
> +    }
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__PdoForwardIrpAndForget(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_PDO        Pdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static NTSTATUS
> +PdoForwardIrpAndForget(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                            __PdoForwardIrpAndForget,
> +                            Pdo,
> +                            TRUE,
> +                            TRUE,
> +                            TRUE);
> +
> +    return IoCallDriver(Pdo->LowerDeviceObject, Irp);
> +}
> +
> +static NTSTATUS
> +PdoCompleteIrp(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp,
> +    IN  NTSTATUS        Status
> +    )
> +{
> +    Irp->IoStatus.Status = Status;
> +    IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +    return Status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__PdoQueryProperty(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_PDO        Pdo = Context;
> +    PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR    Descriptor = Irp-
> >UserBuffer;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    if (!NT_SUCCESS(Irp->IoStatus.Status))
> +        goto done;
> +
> +    Descriptor = Irp->UserBuffer;
> +    Pdo->SectorSize = Descriptor->BytesPerLogicalSector;
> +    Verbose("%p : %u bytes per sector\n", Pdo->Dx->DeviceObject, Pdo-
> >SectorSize);
> +
> +done:
> +    IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoQueryProperty(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PSTORAGE_PROPERTY_QUERY Query;
> +    PDEVICE_TRIM_DESCRIPTOR Trim;
> +    NTSTATUS                status;
> +
> +    Query = Irp->AssociatedIrp.SystemBuffer;
> +
> +    switch (Query->PropertyId) {
> +    case StorageAccessAlignmentProperty:
> +        IoCopyCurrentIrpStackLocationToNext(Irp);
> +        IoSetCompletionRoutine(Irp,
> +                                __PdoQueryProperty,
> +                                Pdo,
> +                                TRUE,
> +                                TRUE,
> +                                TRUE);
> +
> +        status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
> +        break;
> +
> +    case StorageDeviceTrimProperty:
> +        Trim = Irp->AssociatedIrp.SystemBuffer;
> +
> +        Trim->Version = 0;
> +        Trim->Size = sizeof(DEVICE_TRIM_DESCRIPTOR);
> +        Trim->TrimEnabled = TRUE;
> +
> +        Irp->IoStatus.Information =
> (ULONG_PTR)sizeof(DEVICE_TRIM_DESCRIPTOR);
> +        status = PdoCompleteIrp(Pdo, Irp, STATUS_SUCCESS);
> +        break;
> +
> +    default:
> +        status = PdoForwardIrpAndForget(Pdo, Irp);
> +        break;
> +    }
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__PdoSendAwaitSrb(
> +    IN  PDEVICE_OBJECT          DeviceObject,
> +    IN  PIRP                    Irp,
> +    IN  PVOID                   Context
> +    )
> +{
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +    UNREFERENCED_PARAMETER(Context);
> +
> +    *(Irp->UserIosb) = Irp->IoStatus;
> +
> +    if (Irp->MdlAddress) {
> +        MmUnlockPages(Irp->MdlAddress);
> +        IoFreeMdl(Irp->MdlAddress);
> +    }
> +
> +    KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
> +
> +    IoFreeIrp(Irp);
> +    return STATUS_MORE_PROCESSING_REQUIRED;
> +}
> +
> +static NTSTATUS
> +PdoSendAwaitSrb(
> +    IN  PXENDISK_PDO            Pdo,
> +    IN  PSCSI_REQUEST_BLOCK     Srb
> +    )
> +{
> +    PIRP                        Irp;
> +    IO_STATUS_BLOCK             IoStatus;
> +    KEVENT                      Event;
> +    PIO_STACK_LOCATION          Stack;
> +    NTSTATUS                    status;
> +
> +    KeInitializeEvent(&Event, NotificationEvent, FALSE);
> +
> +    status = STATUS_NO_MEMORY;
> +    Irp = IoAllocateIrp((CCHAR)(Pdo->LowerDeviceObject->StackSize + 1),
> FALSE);
> +    if (Irp == NULL)
> +        goto fail1;
> +
> +    Stack = IoGetNextIrpStackLocation(Irp);
> +    Stack->MajorFunction = IRP_MJ_SCSI;
> +    Stack->Parameters.Scsi.Srb = Srb;
> +
> +    IoSetCompletionRoutine(Irp,
> +                            __PdoSendAwaitSrb,
> +                            Srb,
> +                            TRUE,
> +                            TRUE,
> +                            TRUE);
> +    Irp->UserIosb = &IoStatus;
> +    Irp->UserEvent = &Event;
> +
> +    Irp->MdlAddress = IoAllocateMdl(Srb->DataBuffer,
> +                                    Srb->DataTransferLength,
> +                                    FALSE,
> +                                    FALSE,
> +                                    Irp);
> +    if (Irp->MdlAddress == NULL)
> +        goto fail2;
> +
> +#pragma warning(disable:6320)
> +    try {
> +        MmProbeAndLockPages(Irp->MdlAddress, KernelMode,
> IoReadAccess);
> +    } except (EXCEPTION_EXECUTE_HANDLER) {
> +        status = GetExceptionCode();
> +
> +        goto fail3;
> +    }
> +#pragma warning(default:6320)
> +
> +    Srb->OriginalRequest = Irp;
> +
> +    status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
> +    if (status == STATUS_PENDING) {
> +        (VOID) KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE,
> NULL);
> +        status = IoStatus.Status;
> +    }
> +
> +    return status;
> +
> +fail3:
> +    Error("fail3\n");
> +
> +    IoFreeMdl(Irp->MdlAddress);
> +
> +fail2:
> +    Error("fail2\n");
> +
> +    IoFreeIrp(Irp);
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    return status;
> +}
> +
> +static NTSTATUS
> +PdoSendTrimSynchronous(
> +    IN  PXENDISK_PDO            Pdo,
> +    IN  PDEVICE_DATA_SET_RANGE  Ranges,
> +    IN  ULONG                   Count
> +    )
> +{
> +    SCSI_REQUEST_BLOCK          Srb;
> +    PCDB                        Cdb;
> +    PUNMAP_LIST_HEADER          Unmap;
> +    ULONG                       Length;
> +    ULONG                       Index;
> +    NTSTATUS                    status;
> +
> +    Length = sizeof(UNMAP_LIST_HEADER) +
> +             (Count * sizeof(UNMAP_BLOCK_DESCRIPTOR));
> +
> +    status = STATUS_NO_MEMORY;
> +    Unmap = __PdoAllocate(Length);
> +    if (Unmap == NULL)
> +        goto fail1;
> +
> +    RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
> +    Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
> +    Srb.SrbFlags = 0;
> +    Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
> +    Srb.DataBuffer = Unmap;
> +    Srb.DataTransferLength = Length;
> +    Srb.TimeOutValue = (ULONG)-1;
> +    Srb.CdbLength = 10;
> +
> +    Cdb = (PCDB)&Srb.Cdb[0];
> +    Cdb->UNMAP.OperationCode = SCSIOP_UNMAP;
> +    *(PUSHORT)Cdb->UNMAP.AllocationLength =
> _byteswap_ushort((USHORT)Length);
> +
> +    *(PUSHORT)Unmap->DataLength =
> _byteswap_ushort((USHORT)Length);
> +    *(PUSHORT)Unmap->BlockDescrDataLength =
> _byteswap_ushort((USHORT)sizeof(UNMAP_BLOCK_DESCRIPTOR));
> +
> +    for (Index = 0; Index < Count; ++Index) {
> +        PUNMAP_BLOCK_DESCRIPTOR Block = &Unmap->Descriptors[Index];
> +        PDEVICE_DATA_SET_RANGE  Range = &Ranges[Index];
> +
> +        ULONG   LengthInSectors = (ULONG)(Range->LengthInBytes / Pdo-
> >SectorSize);
> +        ULONG64 OffsetInSectors = (ULONG64)(Range->StartingOffset / Pdo-
> >SectorSize);
> +
> +        Trace("TRIM[%x] %x @ %llx\n",
> +                        Index,
> +                        LengthInSectors,
> +                        OffsetInSectors);
> +
> +        *(PULONG64)Block->StartingLba = _byteswap_uint64(OffsetInSectors);
> +        *(PULONG)Block->LbaCount = _byteswap_ulong(LengthInSectors);
> +    }
> +
> +    status = PdoSendAwaitSrb(Pdo, &Srb);
> +    if (!NT_SUCCESS(status))
> +        goto fail2;
> +
> +    __PdoFree(Unmap);
> +    return status;
> +
> +fail2:
> +    Error("fail2\n");
> +
> +    __PdoFree(Unmap);
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    return status;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoManageDataSetAttributes(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PDEVICE_MANAGE_DATA_SET_ATTRIBUTES  Attributes;
> +    PDEVICE_DATA_SET_RANGE              Ranges;
> +    ULONG                               NumRanges;
> +    NTSTATUS                            status;
> +
> +    Attributes = Irp->AssociatedIrp.SystemBuffer;
> +
> +    switch (Attributes->Action) {
> +    case DeviceDsmAction_Trim:
> +        Ranges = (PDEVICE_DATA_SET_RANGE)((PUCHAR)Attributes +
> Attributes->DataSetRangesOffset);
> +        NumRanges = Attributes->DataSetRangesLength /
> sizeof(DEVICE_DATA_SET_RANGE);
> +
> +        status = PdoSendTrimSynchronous(Pdo, Ranges, NumRanges);
> +
> +        status = PdoCompleteIrp(Pdo, Irp, status);
> +        break;
> +
> +    default:
> +        status = PdoForwardIrpAndForget(Pdo, Irp);
> +        break;
> +    }
> +
> +    return status;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoDispatchControl(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    ULONG               ControlCode;
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    ControlCode = StackLocation-
> >Parameters.DeviceIoControl.IoControlCode;
> +
> +    switch (ControlCode) {
> +    case IOCTL_STORAGE_QUERY_PROPERTY:
> +        status = PdoQueryProperty(Pdo, Irp);
> +        break;
> +
> +    case IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES:
> +        status = PdoManageDataSetAttributes(Pdo, Irp);
> +        break;
> +
> +    default:
> +        status = PdoForwardIrpAndForget(Pdo, Irp);
> +        break;
> +    }
> +
> +    return status;
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoStartDevice(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    POWER_STATE         PowerState;
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    status = PdoForwardIrpSynchronously(Pdo, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail2;
> +
> +    __PdoSetSystemPowerState(Pdo, PowerSystemWorking);
> +    __PdoSetDevicePowerState(Pdo, PowerDeviceD0);
> +
> +    PowerState.DeviceState = PowerDeviceD0;
> +    PoSetPowerState(Pdo->Dx->DeviceObject,
> +                    DevicePowerState,
> +                    PowerState);
> +
> +    __PdoSetDevicePnpState(Pdo, Started);
> +
> +    IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +
> +    Irp->IoStatus.Status = STATUS_SUCCESS;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return STATUS_SUCCESS;
> +
> +fail2:
> +    IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__PdoQueryStopDevice(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_PDO        Pdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoQueryStopDevice(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    __PdoSetDevicePnpState(Pdo, StopPending);
> +    Irp->IoStatus.Status = STATUS_SUCCESS;
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __PdoQueryStopDevice,
> +                           Pdo,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
> +
> +    return status;
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__PdoCancelStopDevice(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_PDO        Pdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoCancelStopDevice(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    Irp->IoStatus.Status = STATUS_SUCCESS;
> +
> +    __PdoRestoreDevicePnpState(Pdo, StopPending);
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __PdoCancelStopDevice,
> +                           Pdo,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
> +
> +    return status;
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__PdoStopDevice(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_PDO        Pdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoStopDevice(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    POWER_STATE         PowerState;
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    if (__PdoGetDevicePowerState(Pdo) != PowerDeviceD0)
> +        goto done;
> +
> +    __PdoSetDevicePowerState(Pdo, PowerDeviceD3);
> +    __PdoSetSystemPowerState(Pdo, PowerSystemShutdown);
> +
> +    PowerState.DeviceState = PowerDeviceD3;
> +    PoSetPowerState(Pdo->Dx->DeviceObject,
> +                    DevicePowerState,
> +                    PowerState);
> +
> +done:
> +    __PdoSetDevicePnpState(Pdo, Stopped);
> +    Irp->IoStatus.Status = STATUS_SUCCESS;
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __PdoStopDevice,
> +                           Pdo,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
> +
> +    return status;
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__PdoQueryRemoveDevice(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_PDO        Pdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoQueryRemoveDevice(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    __PdoSetDevicePnpState(Pdo, RemovePending);
> +    Irp->IoStatus.Status = STATUS_SUCCESS;
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __PdoQueryRemoveDevice,
> +                           Pdo,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
> +
> +    return status;
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__PdoCancelRemoveDevice(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_PDO        Pdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoCancelRemoveDevice(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    __PdoRestoreDevicePnpState(Pdo, RemovePending);
> +    Irp->IoStatus.Status = STATUS_SUCCESS;
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __PdoCancelRemoveDevice,
> +                           Pdo,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
> +
> +    return status;
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__PdoSurpriseRemoval(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_PDO        Pdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoSurpriseRemoval(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    __PdoSetDevicePnpState(Pdo, SurpriseRemovePending);
> +    Irp->IoStatus.Status = STATUS_SUCCESS;
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __PdoSurpriseRemoval,
> +                           Pdo,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
> +
> +    return status;
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoRemoveDevice(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PXENDISK_FDO        Fdo = __PdoGetFdo(Pdo);
> +    POWER_STATE         PowerState;
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    if (__PdoGetDevicePowerState(Pdo) != PowerDeviceD0)
> +        goto done;
> +
> +    __PdoSetDevicePowerState(Pdo, PowerDeviceD3);
> +    __PdoSetSystemPowerState(Pdo, PowerSystemShutdown);
> +
> +    PowerState.DeviceState = PowerDeviceD3;
> +    PoSetPowerState(Pdo->Dx->DeviceObject,
> +                    DevicePowerState,
> +                    PowerState);
> +
> +done:
> +    if (__PdoIsMissing(Pdo)) {
> +        __PdoSetDevicePnpState(Pdo, Deleted);
> +        IoReleaseRemoveLockAndWait(&Pdo->Dx->RemoveLock, Irp);
> +    } else {
> +        __PdoSetDevicePnpState(Pdo, Enumerated);
> +        IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    }
> +
> +    status = PdoForwardIrpSynchronously(Pdo, Irp);
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    if (__PdoIsMissing(Pdo)) {
> +        FdoAcquireMutex(Fdo);
> +        PdoDestroy(Pdo);
> +        FdoReleaseMutex(Fdo);
> +    }
> +
> +    return status;
> +
> +fail1:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoEject(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PXENDISK_FDO        Fdo = __PdoGetFdo(Pdo);
> +    NTSTATUS            status;
> +
> +    __PdoSetMissing(Pdo, "Ejected");
> +    __PdoSetDevicePnpState(Pdo, Deleted);
> +
> +    status = PdoForwardIrpSynchronously(Pdo, Irp);
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    FdoAcquireMutex(Fdo);
> +    PdoDestroy(Pdo);
> +    FdoReleaseMutex(Fdo);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__PdoDispatchPnp(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_PDO        Pdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoDispatchPnp(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    UCHAR               MinorFunction;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    MinorFunction = StackLocation->MinorFunction;
> +
> +    switch (StackLocation->MinorFunction) {
> +    case IRP_MN_START_DEVICE:
> +        status = PdoStartDevice(Pdo, Irp);
> +        break;
> +
> +    case IRP_MN_QUERY_STOP_DEVICE:
> +        status = PdoQueryStopDevice(Pdo, Irp);
> +        break;
> +
> +    case IRP_MN_CANCEL_STOP_DEVICE:
> +        status = PdoCancelStopDevice(Pdo, Irp);
> +        break;
> +
> +    case IRP_MN_STOP_DEVICE:
> +        status = PdoStopDevice(Pdo, Irp);
> +        break;
> +
> +    case IRP_MN_QUERY_REMOVE_DEVICE:
> +        status = PdoQueryRemoveDevice(Pdo, Irp);
> +        break;
> +
> +    case IRP_MN_SURPRISE_REMOVAL:
> +        status = PdoSurpriseRemoval(Pdo, Irp);
> +        break;
> +
> +    case IRP_MN_REMOVE_DEVICE:
> +        status = PdoRemoveDevice(Pdo, Irp);
> +        break;
> +
> +    case IRP_MN_CANCEL_REMOVE_DEVICE:
> +        status = PdoCancelRemoveDevice(Pdo, Irp);
> +        break;
> +
> +    case IRP_MN_EJECT:
> +        status = PdoEject(Pdo, Irp);
> +        break;
> +
> +    default:
> +        status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +        if (!NT_SUCCESS(status))
> +            goto fail1;
> +
> +        IoCopyCurrentIrpStackLocationToNext(Irp);
> +        IoSetCompletionRoutine(Irp,
> +                               __PdoDispatchPnp,
> +                               Pdo,
> +                               TRUE,
> +                               TRUE,
> +                               TRUE);
> +
> +        status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
> +        break;
> +    }
> +
> +    return status;
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__PdoSetDevicePowerUp(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    DEVICE_POWER_STATE  DeviceState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
> +
> +    ASSERT3U(DeviceState, <,  __PdoGetDevicePowerState(Pdo));
> +
> +    status = PdoForwardIrpSynchronously(Pdo, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto done;
> +
> +    Verbose("%p: %s -> %s\n",
> +         Pdo->Dx->DeviceObject,
> +         PowerDeviceStateName(__PdoGetDevicePowerState(Pdo)),
> +         PowerDeviceStateName(DeviceState));
> +
> +    __PdoSetDevicePowerState(Pdo, DeviceState);
> +
> +done:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__PdoSetDevicePowerDown(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    DEVICE_POWER_STATE  DeviceState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
> +
> +    ASSERT3U(DeviceState, >,  __PdoGetDevicePowerState(Pdo));
> +
> +    Verbose("%p: %s -> %s\n",
> +         Pdo->Dx->DeviceObject,
> +         PowerDeviceStateName(__PdoGetDevicePowerState(Pdo)),
> +         PowerDeviceStateName(DeviceState));
> +
> +    __PdoSetDevicePowerState(Pdo, DeviceState);
> +
> +    status = PdoForwardIrpSynchronously(Pdo, Irp);
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__PdoSetDevicePower(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    DEVICE_POWER_STATE  DeviceState;
> +    POWER_ACTION        PowerAction;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
> +    PowerAction = StackLocation->Parameters.Power.ShutdownType;
> +
> +    Trace("====> (%s:%s)\n",
> +          PowerDeviceStateName(DeviceState),
> +          PowerActionName(PowerAction));
> +
> +    if (DeviceState == __PdoGetDevicePowerState(Pdo)) {
> +        status = PdoForwardIrpSynchronously(Pdo, Irp);
> +        IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +        goto done;
> +    }
> +
> +    status = (DeviceState < __PdoGetDevicePowerState(Pdo)) ?
> +             __PdoSetDevicePowerUp(Pdo, Irp) :
> +             __PdoSetDevicePowerDown(Pdo, Irp);
> +
> +done:
> +    Trace("<==== (%s:%s)(%08x)\n",
> +          PowerDeviceStateName(DeviceState),
> +          PowerActionName(PowerAction),
> +          status);
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__PdoSetSystemPowerUp(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    SYSTEM_POWER_STATE  SystemState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    SystemState = StackLocation->Parameters.Power.State.SystemState;
> +
> +    ASSERT3U(SystemState, <,  __PdoGetSystemPowerState(Pdo));
> +
> +    status = PdoForwardIrpSynchronously(Pdo, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto done;
> +
> +    Verbose("%p: %s -> %s\n",
> +         Pdo->Dx->DeviceObject,
> +         PowerSystemStateName(__PdoGetSystemPowerState(Pdo)),
> +         PowerSystemStateName(SystemState));
> +
> +    __PdoSetSystemPowerState(Pdo, SystemState);
> +
> +done:
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__PdoSetSystemPowerDown(
> +    IN  PXENDISK_PDO     Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    SYSTEM_POWER_STATE  SystemState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    SystemState = StackLocation->Parameters.Power.State.SystemState;
> +
> +    ASSERT3U(SystemState, >,  __PdoGetSystemPowerState(Pdo));
> +
> +    Verbose("%p: %s -> %s\n",
> +         Pdo->Dx->DeviceObject,
> +         PowerSystemStateName(__PdoGetSystemPowerState(Pdo)),
> +         PowerSystemStateName(SystemState));
> +
> +    __PdoSetSystemPowerState(Pdo, SystemState);
> +
> +    status = PdoForwardIrpSynchronously(Pdo, Irp);
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__PdoSetSystemPower(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    SYSTEM_POWER_STATE  SystemState;
> +    POWER_ACTION        PowerAction;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    SystemState = StackLocation->Parameters.Power.State.SystemState;
> +    PowerAction = StackLocation->Parameters.Power.ShutdownType;
> +
> +    Trace("====> (%s:%s)\n",
> +          PowerSystemStateName(SystemState),
> +          PowerActionName(PowerAction));
> +
> +    if (SystemState == __PdoGetSystemPowerState(Pdo)) {
> +        status = PdoForwardIrpSynchronously(Pdo, Irp);
> +        IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +        goto done;
> +    }
> +
> +    status = (SystemState < __PdoGetSystemPowerState(Pdo)) ?
> +             __PdoSetSystemPowerUp(Pdo, Irp) :
> +             __PdoSetSystemPowerDown(Pdo, Irp);
> +
> +done:
> +    Trace("<==== (%s:%s)(%08x)\n",
> +          PowerSystemStateName(SystemState),
> +          PowerActionName(PowerAction),
> +          status);
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__PdoQueryDevicePowerUp(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    DEVICE_POWER_STATE  DeviceState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
> +
> +    ASSERT3U(DeviceState, <,  __PdoGetDevicePowerState(Pdo));
> +
> +    status = PdoForwardIrpSynchronously(Pdo, Irp);
> +
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__PdoQueryDevicePowerDown(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    DEVICE_POWER_STATE  DeviceState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
> +
> +    ASSERT3U(DeviceState, >,  __PdoGetDevicePowerState(Pdo));
> +
> +    status = PdoForwardIrpSynchronously(Pdo, Irp);
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__PdoQueryDevicePower(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    DEVICE_POWER_STATE  DeviceState;
> +    POWER_ACTION        PowerAction;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    DeviceState = StackLocation->Parameters.Power.State.DeviceState;
> +    PowerAction = StackLocation->Parameters.Power.ShutdownType;
> +
> +    Trace("====> (%s:%s)\n",
> +          PowerDeviceStateName(DeviceState),
> +          PowerActionName(PowerAction));
> +
> +    if (DeviceState == __PdoGetDevicePowerState(Pdo)) {
> +        status = PdoForwardIrpSynchronously(Pdo, Irp);
> +        IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +        goto done;
> +    }
> +
> +    status = (DeviceState < __PdoGetDevicePowerState(Pdo)) ?
> +             __PdoQueryDevicePowerUp(Pdo, Irp) :
> +             __PdoQueryDevicePowerDown(Pdo, Irp);
> +
> +done:
> +    Trace("<==== (%s:%s)(%08x)\n",
> +          PowerDeviceStateName(DeviceState),
> +          PowerActionName(PowerAction),
> +          status);
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__PdoQuerySystemPowerUp(
> +    IN  PXENDISK_PDO     Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    SYSTEM_POWER_STATE  SystemState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    SystemState = StackLocation->Parameters.Power.State.SystemState;
> +
> +    ASSERT3U(SystemState, <,  __PdoGetSystemPowerState(Pdo));
> +
> +    status = PdoForwardIrpSynchronously(Pdo, Irp);
> +
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__PdoQuerySystemPowerDown(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    SYSTEM_POWER_STATE  SystemState;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    SystemState = StackLocation->Parameters.Power.State.SystemState;
> +
> +    ASSERT3U(SystemState, >,  __PdoGetSystemPowerState(Pdo));
> +
> +    status = PdoForwardIrpSynchronously(Pdo, Irp);
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +static FORCEINLINE NTSTATUS
> +__PdoQuerySystemPower(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    SYSTEM_POWER_STATE  SystemState;
> +    POWER_ACTION        PowerAction;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    SystemState = StackLocation->Parameters.Power.State.SystemState;
> +    PowerAction = StackLocation->Parameters.Power.ShutdownType;
> +
> +    Trace("====> (%s:%s)\n",
> +          PowerSystemStateName(SystemState),
> +          PowerActionName(PowerAction));
> +
> +    if (SystemState == __PdoGetSystemPowerState(Pdo)) {
> +        status = PdoForwardIrpSynchronously(Pdo, Irp);
> +        IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +        goto done;
> +    }
> +
> +    status = (SystemState < __PdoGetSystemPowerState(Pdo)) ?
> +             __PdoQuerySystemPowerUp(Pdo, Irp) :
> +             __PdoQuerySystemPowerDown(Pdo, Irp);
> +
> +done:
> +    Trace("<==== (%s:%s)(%08x)\n",
> +          PowerSystemStateName(SystemState),
> +          PowerActionName(PowerAction),
> +          status);
> +
> +    return status;
> +}
> +
> +static NTSTATUS
> +PdoDevicePower(
> +    IN  PXENDISK_THREAD Self,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_PDO        Pdo = Context;
> +    PKEVENT             Event;
> +
> +    Event = ThreadGetEvent(Self);
> +
> +    for (;;) {
> +        PIRP                Irp;
> +        PIO_STACK_LOCATION  StackLocation;
> +        UCHAR               MinorFunction;
> +
> +        if (Pdo->DevicePowerIrp == NULL) {
> +            (VOID) KeWaitForSingleObject(Event,
> +                                         Executive,
> +                                         KernelMode,
> +                                         FALSE,
> +                                         NULL);
> +            KeClearEvent(Event);
> +        }
> +
> +        if (ThreadIsAlerted(Self))
> +            break;
> +
> +        Irp = Pdo->DevicePowerIrp;
> +
> +        if (Irp == NULL)
> +            continue;
> +
> +        Pdo->DevicePowerIrp = NULL;
> +        KeMemoryBarrier();
> +
> +        StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +        MinorFunction = StackLocation->MinorFunction;
> +
> +        switch (StackLocation->MinorFunction) {
> +        case IRP_MN_SET_POWER:
> +            (VOID) __PdoSetDevicePower(Pdo, Irp);
> +            break;
> +
> +        case IRP_MN_QUERY_POWER:
> +            (VOID) __PdoQueryDevicePower(Pdo, Irp);
> +            break;
> +
> +        default:
> +            ASSERT(FALSE);
> +            break;
> +        }
> +
> +        IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    }
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static NTSTATUS
> +PdoSystemPower(
> +    IN  PXENDISK_THREAD Self,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_PDO        Pdo = Context;
> +    PKEVENT             Event;
> +
> +    Event = ThreadGetEvent(Self);
> +
> +    for (;;) {
> +        PIRP                Irp;
> +        PIO_STACK_LOCATION  StackLocation;
> +        UCHAR               MinorFunction;
> +
> +        if (Pdo->SystemPowerIrp == NULL) {
> +            (VOID) KeWaitForSingleObject(Event,
> +                                         Executive,
> +                                         KernelMode,
> +                                         FALSE,
> +                                         NULL);
> +            KeClearEvent(Event);
> +        }
> +
> +        if (ThreadIsAlerted(Self))
> +            break;
> +
> +        Irp = Pdo->SystemPowerIrp;
> +
> +        if (Irp == NULL)
> +            continue;
> +
> +        Pdo->SystemPowerIrp = NULL;
> +        KeMemoryBarrier();
> +
> +        StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +        MinorFunction = StackLocation->MinorFunction;
> +
> +        switch (StackLocation->MinorFunction) {
> +        case IRP_MN_SET_POWER:
> +            (VOID) __PdoSetSystemPower(Pdo, Irp);
> +            break;
> +
> +        case IRP_MN_QUERY_POWER:
> +            (VOID) __PdoQuerySystemPower(Pdo, Irp);
> +            break;
> +
> +        default:
> +            ASSERT(FALSE);
> +            break;
> +        }
> +
> +        IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    }
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__PdoDispatchPower(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_PDO        Pdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoDispatchPower(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    UCHAR               MinorFunction;
> +    POWER_STATE_TYPE    PowerType;
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +    MinorFunction = StackLocation->MinorFunction;
> +
> +    if (MinorFunction != IRP_MN_QUERY_POWER &&
> +        MinorFunction != IRP_MN_SET_POWER) {
> +        IoCopyCurrentIrpStackLocationToNext(Irp);
> +        IoSetCompletionRoutine(Irp,
> +                               __PdoDispatchPower,
> +                               Pdo,
> +                               TRUE,
> +                               TRUE,
> +                               TRUE);
> +
> +        status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
> +
> +        goto done;
> +    }
> +
> +    PowerType = StackLocation->Parameters.Power.Type;
> +
> +    Trace("====> (%02x:%s)\n",
> +          MinorFunction,
> +          PowerMinorFunctionName(MinorFunction));
> +
> +    switch (PowerType) {
> +    case DevicePowerState:
> +        IoMarkIrpPending(Irp);
> +
> +        ASSERT3P(Pdo->DevicePowerIrp, ==, NULL);
> +        Pdo->DevicePowerIrp = Irp;
> +        KeMemoryBarrier();
> +
> +        ThreadWake(Pdo->DevicePowerThread);
> +
> +        status = STATUS_PENDING;
> +        break;
> +
> +    case SystemPowerState:
> +        IoMarkIrpPending(Irp);
> +
> +        ASSERT3P(Pdo->SystemPowerIrp, ==, NULL);
> +        Pdo->SystemPowerIrp = Irp;
> +        KeMemoryBarrier();
> +
> +        ThreadWake(Pdo->SystemPowerThread);
> +
> +        status = STATUS_PENDING;
> +        break;
> +
> +    default:
> +        IoCopyCurrentIrpStackLocationToNext(Irp);
> +        IoSetCompletionRoutine(Irp,
> +                               __PdoDispatchPower,
> +                               Pdo,
> +                               TRUE,
> +                               TRUE,
> +                               TRUE);
> +
> +        status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
> +        break;
> +    }
> +
> +    Trace("<==== (%02x:%s) (%08x)\n",
> +          MinorFunction,
> +          PowerMinorFunctionName(MinorFunction),
> +          status);
> +
> +done:
> +    return status;
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +__drv_functionClass(IO_COMPLETION_ROUTINE)
> +__drv_sameIRQL
> +static NTSTATUS
> +__PdoDispatchDefault(
> +    IN  PDEVICE_OBJECT  DeviceObject,
> +    IN  PIRP            Irp,
> +    IN  PVOID           Context
> +    )
> +{
> +    PXENDISK_PDO        Pdo = Context;
> +
> +    UNREFERENCED_PARAMETER(DeviceObject);
> +
> +    if (Irp->PendingReturned)
> +        IoMarkIrpPending(Irp);
> +
> +    IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +
> +    return STATUS_SUCCESS;
> +}
> +
> +static DECLSPEC_NOINLINE NTSTATUS
> +PdoDispatchDefault(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    NTSTATUS            status;
> +
> +    status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    IoCopyCurrentIrpStackLocationToNext(Irp);
> +    IoSetCompletionRoutine(Irp,
> +                           __PdoDispatchDefault,
> +                           Pdo,
> +                           TRUE,
> +                           TRUE,
> +                           TRUE);
> +
> +    status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
> +
> +    return status;
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    Irp->IoStatus.Status = status;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +
> +    return status;
> +}
> +
> +NTSTATUS
> +PdoDispatch(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    )
> +{
> +    PIO_STACK_LOCATION  StackLocation;
> +    NTSTATUS            status;
> +
> +    StackLocation = IoGetCurrentIrpStackLocation(Irp);
> +
> +    switch (StackLocation->MajorFunction) {
> +    case IRP_MJ_DEVICE_CONTROL:
> +        status = PdoDispatchControl(Pdo, Irp);
> +        break;
> +
> +    case IRP_MJ_PNP:
> +        status = PdoDispatchPnp(Pdo, Irp);
> +        break;
> +
> +    case IRP_MJ_POWER:
> +        status = PdoDispatchPower(Pdo, Irp);
> +        break;
> +
> +    default:
> +        status = PdoDispatchDefault(Pdo, Irp);
> +        break;
> +    }
> +
> +    return status;
> +}
> +
> +NTSTATUS
> +PdoCreate(
> +    PXENDISK_FDO                    Fdo,
> +    PDEVICE_OBJECT                  PhysicalDeviceObject
> +    )
> +{
> +    PDEVICE_OBJECT                  LowerDeviceObject;
> +    ULONG                           DeviceType;
> +    PDEVICE_OBJECT                  FilterDeviceObject;
> +    PXENDISK_DX                     Dx;
> +    PXENDISK_PDO                    Pdo;
> +    NTSTATUS                        status;
> +
> +    LowerDeviceObject =
> IoGetAttachedDeviceReference(PhysicalDeviceObject);
> +    DeviceType = LowerDeviceObject->DeviceType;
> +    ObDereferenceObject(LowerDeviceObject);
> +
> +#pragma prefast(suppress:28197) // Possibly leaking memory
> 'PhysicalDeviceObject'
> +    status = IoCreateDevice(DriverGetDriverObject(),
> +                            sizeof(XENDISK_DX),
> +                            NULL,
> +                            DeviceType,
> +                            FILE_DEVICE_SECURE_OPEN,
> +                            FALSE,
> +                            &FilterDeviceObject);
> +    if (!NT_SUCCESS(status))
> +        goto fail1;
> +
> +    Dx = (PXENDISK_DX)FilterDeviceObject->DeviceExtension;
> +    RtlZeroMemory(Dx, sizeof (XENDISK_DX));
> +
> +    Dx->Type = PHYSICAL_DEVICE_OBJECT;
> +    Dx->DeviceObject = FilterDeviceObject;
> +    Dx->DevicePnpState = Present;
> +    Dx->SystemPowerState = PowerSystemShutdown;
> +    Dx->DevicePowerState = PowerDeviceD3;
> +
> +    IoInitializeRemoveLock(&Dx->RemoveLock, PDO_TAG, 0, 0);
> +
> +    Pdo = __PdoAllocate(sizeof (XENDISK_PDO));
> +
> +    status = STATUS_NO_MEMORY;
> +    if (Pdo == NULL)
> +        goto fail2;
> +
> +    LowerDeviceObject = IoAttachDeviceToDeviceStack(FilterDeviceObject,
> +                                                    PhysicalDeviceObject);
> +
> +    status = STATUS_UNSUCCESSFUL;
> +    if (LowerDeviceObject == NULL)
> +        goto fail3;
> +
> +    Pdo->Dx = Dx;
> +    Pdo->PhysicalDeviceObject = PhysicalDeviceObject;
> +    Pdo->LowerDeviceObject = LowerDeviceObject;
> +    Pdo->SectorSize = 512;
> +
> +    status = ThreadCreate(PdoSystemPower, Pdo, &Pdo-
> >SystemPowerThread);
> +    if (!NT_SUCCESS(status))
> +        goto fail4;
> +
> +    status = ThreadCreate(PdoDevicePower, Pdo, &Pdo-
> >DevicePowerThread);
> +    if (!NT_SUCCESS(status))
> +        goto fail5;
> +
> +    Verbose("%p\n", FilterDeviceObject);
> +
> +    Dx->Pdo = Pdo;
> +
> +#pragma prefast(suppress:28182) // Dereferencing NULL pointer
> +    FilterDeviceObject->DeviceType = LowerDeviceObject->DeviceType;
> +    FilterDeviceObject->Characteristics = LowerDeviceObject-
> >Characteristics;
> +
> +    FilterDeviceObject->Flags |= LowerDeviceObject->Flags;
> +    FilterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
> +
> +    __PdoLink(Pdo, Fdo);
> +
> +    return STATUS_SUCCESS;
> +
> +fail5:
> +    Error("fail5\n");
> +
> +    ThreadAlert(Pdo->SystemPowerThread);
> +    ThreadJoin(Pdo->SystemPowerThread);
> +    Pdo->SystemPowerThread = NULL;
> +
> +fail4:
> +    Error("fail4\n");
> +
> +    Pdo->PhysicalDeviceObject = NULL;
> +    Pdo->LowerDeviceObject = NULL;
> +    Pdo->Dx = NULL;
> +
> +    IoDetachDevice(LowerDeviceObject);
> +
> +fail3:
> +    Error("fail3\n");
> +
> +    ASSERT(IsZeroMemory(Pdo, sizeof (XENDISK_PDO)));
> +    __PdoFree(Pdo);
> +
> +fail2:
> +    Error("fail2\n");
> +
> +    IoDeleteDevice(FilterDeviceObject);
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    return status;
> +}
> +
> +VOID
> +PdoDestroy(
> +    IN  PXENDISK_PDO    Pdo
> +    )
> +{
> +    PDEVICE_OBJECT      LowerDeviceObject = Pdo->LowerDeviceObject;
> +    PXENDISK_DX         Dx = Pdo->Dx;
> +    PDEVICE_OBJECT      FilterDeviceObject = Dx->DeviceObject;
> +
> +    ASSERT3U(__PdoGetDevicePnpState(Pdo), ==, Deleted);
> +
> +    ASSERT(__PdoIsMissing(Pdo));
> +    Pdo->Missing = FALSE;
> +
> +    __PdoUnlink(Pdo);
> +
> +    Verbose("%p (%s)\n",
> +         FilterDeviceObject,
> +         Pdo->Reason);
> +    Pdo->Reason = NULL;
> +
> +    Dx->Pdo = NULL;
> +
> +    ThreadAlert(Pdo->DevicePowerThread);
> +    ThreadJoin(Pdo->DevicePowerThread);
> +    Pdo->DevicePowerThread = NULL;
> +
> +    ThreadAlert(Pdo->SystemPowerThread);
> +    ThreadJoin(Pdo->SystemPowerThread);
> +    Pdo->SystemPowerThread = NULL;
> +
> +    Pdo->SectorSize = 0;
> +    Pdo->PhysicalDeviceObject = NULL;
> +    Pdo->LowerDeviceObject = NULL;
> +    Pdo->Dx = NULL;
> +
> +    IoDetachDevice(LowerDeviceObject);
> +
> +    ASSERT(IsZeroMemory(Pdo, sizeof (XENDISK_PDO)));
> +    __PdoFree(Pdo);
> +
> +    IoDeleteDevice(FilterDeviceObject);
> +}
> diff --git a/src/xendisk/pdo.h b/src/xendisk/pdo.h
> new file mode 100644
> index 0000000..5e2e5d6
> --- /dev/null
> +++ b/src/xendisk/pdo.h
> @@ -0,0 +1,90 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#ifndef _XENDISK_PDO_H
> +#define _XENDISK_PDO_H
> +
> +#include <ntddk.h>
> +#include "types.h"
> +#include "fdo.h"
> +
> +typedef struct _XENDISK_PDO XENDISK_PDO, *PXENDISK_PDO;
> +
> +extern VOID
> +PdoSetDevicePnpState(
> +    IN  PXENDISK_PDO        Pdo,
> +    IN  DEVICE_PNP_STATE    State
> +    );
> +
> +extern DEVICE_PNP_STATE
> +PdoGetDevicePnpState(
> +    IN  PXENDISK_PDO    Pdo
> +    );
> +
> +extern PDEVICE_OBJECT
> +PdoGetPhysicalDeviceObject(
> +    IN  PXENDISK_PDO    Pdo
> +    );
> +
> +extern BOOLEAN
> +PdoIsMissing(
> +    IN  PXENDISK_PDO    Pdo
> +    );
> +
> +extern VOID
> +PdoSetMissing(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  const CHAR      *Reason
> +    );
> +
> +extern BOOLEAN
> +PdoIsMasked(
> +    IN  PXENDISK_PDO    Pdo
> +    );
> +
> +extern NTSTATUS
> +PdoCreate(
> +    IN  PXENDISK_FDO    Fdo,
> +    IN  PDEVICE_OBJECT  PhysicalDeviceObject
> +    );
> +
> +extern VOID
> +PdoDestroy(
> +    IN  PXENDISK_PDO    Pdo
> +    );
> +
> +extern NTSTATUS
> +PdoDispatch(
> +    IN  PXENDISK_PDO    Pdo,
> +    IN  PIRP            Irp
> +    );
> +
> +#endif // _XENDISK_PDO_H
> diff --git a/src/xendisk/thread.c b/src/xendisk/thread.c
> new file mode 100644
> index 0000000..92e2b94
> --- /dev/null
> +++ b/src/xendisk/thread.c
> @@ -0,0 +1,225 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#include <ntddk.h>
> +
> +#include "thread.h"
> +#include "debug.h"
> +#include "assert.h"
> +#include "util.h"
> +
> +#define THREAD_POOL 'ERHT'
> +
> +struct _XENDISK_THREAD {
> +    XENDISK_THREAD_FUNCTION Function;
> +    PVOID                   Context;
> +    KEVENT                  Event;
> +    BOOLEAN                 Alerted;
> +    LONG                    References;
> +    PKTHREAD                Thread;
> +};
> +
> +static FORCEINLINE PVOID
> +__ThreadAllocate(
> +    IN  ULONG   Length
> +    )
> +{
> +    return __AllocateNonPagedPoolWithTag(__FUNCTION__, __LINE__,
> Length, THREAD_POOL);
> +}
> +
> +static FORCEINLINE VOID
> +__ThreadFree(
> +    IN  PVOID   Buffer
> +    )
> +{
> +    __FreePoolWithTag(Buffer, THREAD_POOL);
> +}
> +
> +static FORCEINLINE VOID
> +__ThreadWake(
> +    IN  PXENDISK_THREAD Thread
> +    )
> +{
> +    KeSetEvent(&Thread->Event, IO_NO_INCREMENT, FALSE);
> +}
> +
> +VOID
> +ThreadWake(
> +    IN  PXENDISK_THREAD Thread
> +    )
> +{
> +    __ThreadWake(Thread);
> +}
> +
> +static FORCEINLINE VOID
> +__ThreadAlert(
> +    IN  PXENDISK_THREAD Thread
> +    )
> +{
> +    Thread->Alerted = TRUE;
> +    __ThreadWake(Thread);
> +}
> +
> +VOID
> +ThreadAlert(
> +    IN  PXENDISK_THREAD Thread
> +    )
> +{
> +    __ThreadAlert(Thread);
> +}
> +
> +KSTART_ROUTINE  ThreadFunction;
> +
> +VOID
> +ThreadFunction(
> +    IN  PVOID       Argument
> +    )
> +{
> +    PXENDISK_THREAD Self = Argument;
> +    NTSTATUS        status;
> +
> +    status = Self->Function(Self, Self->Context);
> +
> +    if (InterlockedDecrement(&Self->References) == 0)
> +        __ThreadFree(Self);
> +
> +    PsTerminateSystemThread(status);
> +    // NOT REACHED
> +}
> +
> +NTSTATUS
> +ThreadCreate(
> +    IN  XENDISK_THREAD_FUNCTION Function,
> +    IN  PVOID                   Context,
> +    OUT PXENDISK_THREAD         *Thread
> +    )
> +{
> +    HANDLE                      Handle;
> +    NTSTATUS                    status;
> +
> +    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
> +
> +    (*Thread) = __ThreadAllocate(sizeof (XENDISK_THREAD));
> +
> +    status = STATUS_NO_MEMORY;
> +    if (*Thread == NULL)
> +        goto fail1;
> +
> +    (*Thread)->Function = Function;
> +    (*Thread)->Context = Context;
> +    (*Thread)->Alerted = FALSE;
> +    (*Thread)->References = 2; // One for us, one for the thread function
> +
> +    KeInitializeEvent(&(*Thread)->Event, NotificationEvent, FALSE);
> +
> +    status = PsCreateSystemThread(&Handle,
> +                                  STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
> +                                  NULL,
> +                                  NULL,
> +                                  NULL,
> +                                  ThreadFunction,
> +                                  *Thread);
> +    if (!NT_SUCCESS(status)) {
> +        --(*Thread)->References;    // Fake thread function termination
> +        goto fail2;
> +    }
> +
> +    status = ObReferenceObjectByHandle(Handle,
> +                                       SYNCHRONIZE,
> +                                       *PsThreadType,
> +                                       KernelMode,
> +                                       &(*Thread)->Thread,
> +                                       NULL);
> +    if (!NT_SUCCESS(status))
> +        goto fail3;
> +
> +    ZwClose(Handle);
> +
> +    return STATUS_SUCCESS;
> +
> +fail3:
> +    Error("fail3\n");
> +
> +    __ThreadAlert(*Thread);
> +    ZwClose(Handle);
> +
> +fail2:
> +    Error("fail2\n");
> +
> +    if (InterlockedDecrement(&(*Thread)->References) == 0)
> +        __ThreadFree(*Thread);
> +
> +    *Thread = NULL;
> +
> +fail1:
> +    Error("fail1 (%08x)\n", status);
> +
> +    return status;
> +}
> +
> +PKEVENT
> +ThreadGetEvent(
> +    IN  PXENDISK_THREAD Thread
> +    )
> +{
> +    return &Thread->Event;
> +}
> +
> +BOOLEAN
> +ThreadIsAlerted(
> +    IN  PXENDISK_THREAD Thread
> +    )
> +{
> +    return Thread->Alerted;
> +}
> +
> +VOID
> +ThreadJoin(
> +    IN  PXENDISK_THREAD Thread
> +    )
> +{
> +    LONG                References;
> +
> +    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
> +    ASSERT3P(KeGetCurrentThread(), !=, Thread->Thread);
> +
> +    (VOID) KeWaitForSingleObject(Thread->Thread,
> +                                 Executive,
> +                                 KernelMode,
> +                                 FALSE,
> +                                 NULL);
> +
> +    References = InterlockedDecrement(&Thread->References);
> +    ASSERT3U(References, ==, 0);
> +
> +    __ThreadFree(Thread);
> +}
> +
> diff --git a/src/xendisk/thread.h b/src/xendisk/thread.h
> new file mode 100644
> index 0000000..c197337
> --- /dev/null
> +++ b/src/xendisk/thread.h
> @@ -0,0 +1,73 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#ifndef _XENDISK_THREAD_H
> +#define _XENDISK_THREAD_H
> +
> +#include <ntddk.h>
> +
> +typedef struct _XENDISK_THREAD XENDISK_THREAD, *PXENDISK_THREAD;
> +
> +typedef NTSTATUS (*XENDISK_THREAD_FUNCTION)(PXENDISK_THREAD,
> PVOID);
> +
> +extern NTSTATUS
> +ThreadCreate(
> +    IN  XENDISK_THREAD_FUNCTION Function,
> +    IN  PVOID                   Context,
> +    OUT PXENDISK_THREAD         *Thread
> +    );
> +
> +extern PKEVENT
> +ThreadGetEvent(
> +    IN  PXENDISK_THREAD Self
> +    );
> +
> +extern BOOLEAN
> +ThreadIsAlerted(
> +    IN  PXENDISK_THREAD Self
> +    );
> +
> +extern VOID
> +ThreadWake(
> +    IN  PXENDISK_THREAD Thread
> +    );
> +
> +extern VOID
> +ThreadAlert(
> +    IN  PXENDISK_THREAD Thread
> +    );
> +
> +extern VOID
> +ThreadJoin(
> +    IN  PXENDISK_THREAD Thread
> +    );
> +
> +#endif  // _XENDISK_THREAD_H
> diff --git a/src/xendisk/types.h b/src/xendisk/types.h
> new file mode 100644
> index 0000000..b2b4218
> --- /dev/null
> +++ b/src/xendisk/types.h
> @@ -0,0 +1,53 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#ifndef _XENDISK_TYPES_H
> +#define _XENDISK_TYPES_H
> +
> +typedef enum _DEVICE_OBJECT_TYPE {
> +    PHYSICAL_DEVICE_OBJECT = 'ODP',
> +    FUNCTION_DEVICE_OBJECT = 'ODF'
> +} DEVICE_OBJECT_TYPE, *PDEVICE_OBJECT_TYPE;
> +
> +typedef enum _DEVICE_PNP_STATE {
> +    Invalid = 0,
> +    Present,        // PDO only
> +    Enumerated,     // PDO only
> +    Added,          // FDO only
> +    Started,
> +    StopPending,
> +    Stopped,
> +    RemovePending,
> +    SurpriseRemovePending,
> +    Deleted
> +} DEVICE_PNP_STATE, *PDEVICE_PNP_STATE;
> +
> +#endif  // _XENDISK_TYPES_H
> diff --git a/src/xendisk/util.h b/src/xendisk/util.h
> new file mode 100644
> index 0000000..e7adc22
> --- /dev/null
> +++ b/src/xendisk/util.h
> @@ -0,0 +1,222 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#ifndef _UTIL_H
> +#define _UTIL_H
> +
> +#include <ntddk.h>
> +
> +#include "assert.h"
> +
> +typedef struct _NON_PAGED_BUFFER_HEADER {
> +    SIZE_T  Length;
> +    ULONG   Tag;
> +} NON_PAGED_BUFFER_HEADER, *PNON_PAGED_BUFFER_HEADER;
> +
> +typedef struct _NON_PAGED_BUFFER_TRAILER {
> +    ULONG   Tag;
> +} NON_PAGED_BUFFER_TRAILER, *PNON_PAGED_BUFFER_TRAILER;
> +
> +static FORCEINLINE PVOID
> +__AllocateNonPagedPoolWithTag(
> +    IN  PCHAR                   Caller,
> +    IN  ULONG                   Line,
> +    IN  SIZE_T                  Length,
> +    IN  ULONG                   Tag
> +    )
> +{
> +    PUCHAR                      Buffer;
> +    PNON_PAGED_BUFFER_HEADER    Header;
> +    PNON_PAGED_BUFFER_TRAILER   Trailer;
> +
> +    ASSERT3S(Length, !=, 0);
> +
> +    Buffer = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool,
> +                                   sizeof (NON_PAGED_BUFFER_HEADER) +
> +                                   Length +
> +                                   sizeof (NON_PAGED_BUFFER_TRAILER),
> +                                   Tag);
> +    if (Buffer == NULL) {
> +        Warning("%s:%u : AllocFailed %d bytes, %08x tag\n", Caller, Line,
> Length, Tag);
> +        goto done;
> +    }
> +
> +    RtlZeroMemory(Buffer,
> +                  sizeof (NON_PAGED_BUFFER_HEADER) +
> +                  Length +
> +                  sizeof (NON_PAGED_BUFFER_TRAILER));
> +
> +    Header = (PNON_PAGED_BUFFER_HEADER)Buffer;
> +    Header->Length = Length;
> +    Header->Tag = Tag;
> +
> +    Buffer += sizeof (NON_PAGED_BUFFER_HEADER);
> +
> +    Trailer = (PNON_PAGED_BUFFER_TRAILER)(Buffer + Length);
> +    Trailer->Tag = Tag;
> +
> +done:
> +    return Buffer;
> +}
> +
> +static FORCEINLINE VOID
> +__FreePoolWithTag(
> +    IN  PVOID                   _Buffer,
> +    IN  ULONG                   Tag
> +    )
> +{
> +    PUCHAR                      Buffer = (PUCHAR)_Buffer;
> +    SIZE_T                      Length;
> +    PNON_PAGED_BUFFER_HEADER    Header;
> +    PNON_PAGED_BUFFER_TRAILER   Trailer;
> +
> +    ASSERT3P(Buffer, !=, NULL);
> +
> +    Buffer -= sizeof (NON_PAGED_BUFFER_HEADER);
> +
> +    Header = (PNON_PAGED_BUFFER_HEADER)Buffer;
> +    ASSERT3U(Tag, ==, Header->Tag);
> +    Length = Header->Length;
> +
> +    Buffer += sizeof (NON_PAGED_BUFFER_HEADER);
> +
> +    Trailer = (PNON_PAGED_BUFFER_TRAILER)(Buffer + Length);
> +    ASSERT3U(Tag, ==, Trailer->Tag);
> +
> +    Buffer -= sizeof (NON_PAGED_BUFFER_HEADER);
> +
> +    RtlFillMemory(Buffer,
> +                  sizeof (NON_PAGED_BUFFER_HEADER) +
> +                  Length +
> +                  sizeof (NON_PAGED_BUFFER_TRAILER),
> +                  0xAA);
> +
> +    ExFreePoolWithTag(Buffer, Tag);
> +}
> +
> +static FORCEINLINE PMDL
> +__AllocPagesForMdl(
> +    IN  SIZE_T          Size
> +    )
> +{
> +    PMDL                Mdl;
> +    PHYSICAL_ADDRESS    LowAddr;
> +    PHYSICAL_ADDRESS    HighAddr;
> +    PHYSICAL_ADDRESS    SkipBytes;
> +
> +    SkipBytes.QuadPart = 0ull;
> +    HighAddr.QuadPart = ~0ull;
> +
> +    // try > 4GB
> +    LowAddr.QuadPart = 0x100000000ull;
> +    Mdl = MmAllocatePagesForMdlEx(LowAddr, HighAddr, SkipBytes, Size,
> MmCached, 0);
> +    if (Mdl) {
> +        if (MmGetMdlByteCount(Mdl) == Size) {
> +            goto done;
> +        }
> +        MmFreePagesFromMdl(Mdl);
> +        ExFreePool(Mdl);
> +        Mdl = NULL;
> +    }
> +
> +    // try > 2GB
> +    LowAddr.QuadPart = 0x80000000ull;
> +    Mdl = MmAllocatePagesForMdlEx(LowAddr, HighAddr, SkipBytes, Size,
> MmCached, 0);
> +    if (Mdl) {
> +        if (MmGetMdlByteCount(Mdl) == Size) {
> +            goto done;
> +        }
> +        MmFreePagesFromMdl(Mdl);
> +        ExFreePool(Mdl);
> +        Mdl = NULL;
> +    }
> +
> +    // try anywhere
> +    LowAddr.QuadPart = 0ull;
> +    Mdl = MmAllocatePagesForMdlEx(LowAddr, HighAddr, SkipBytes, Size,
> MmCached, 0);
> +    // Mdl byte count gets checked again after this returns
> +
> +done:
> +    return Mdl;
> +}
> +static FORCEINLINE PVOID
> +___AllocPages(
> +    IN  PCHAR           Caller,
> +    IN  ULONG           Line,
> +    IN  SIZE_T          Size,
> +    OUT PMDL*           Mdl
> +    )
> +{
> +    PVOID               Buffer;
> +
> +    *Mdl = __AllocPagesForMdl(Size);
> +    if (*Mdl == NULL) {
> +        Warning("%s:%u : MmAllocatePagesForMdlEx Failed %d bytes\n",
> Caller, Line, Size);
> +        goto fail1;
> +    }
> +
> +    if (MmGetMdlByteCount(*Mdl) != Size) {
> +        Warning("%s:%u : %d bytes != %d bytes requested\n", Caller, Line,
> MmGetMdlByteCount(*Mdl), Size);
> +        goto fail2;
> +    }
> +
> +    Buffer = MmMapLockedPagesSpecifyCache(*Mdl, KernelMode,
> MmCached, NULL, FALSE, NormalPagePriority);
> +    if (Buffer == NULL) {
> +        Warning("%s:%u : MmMapLockedPagesSpecifyCache Failed %d
> bytes\n", Caller, Line, Size);
> +        goto fail3;
> +    }
> +
> +    return Buffer;
> +
> +fail3:
> +fail2:
> +    MmFreePagesFromMdl(*Mdl);
> +    ExFreePool(*Mdl);
> +fail1:
> +    *Mdl = NULL;
> +    return NULL;
> +}
> +#define __AllocPages(Size, Mdl) ___AllocPages(__FUNCTION__, __LINE__,
> Size, Mdl)
> +
> +static FORCEINLINE VOID
> +__FreePages(
> +    IN  PVOID           Buffer,
> +    IN  PMDL            Mdl
> +    )
> +{
> +    if (Buffer && Mdl) {
> +        MmUnmapLockedPages(Buffer, Mdl);
> +        MmFreePagesFromMdl(Mdl);
> +        ExFreePool(Mdl);
> +    }
> +}
> +
> +#endif  // _UTIL_H
> diff --git a/src/xendisk/xendisk.rc b/src/xendisk/xendisk.rc
> new file mode 100644
> index 0000000..df2e5b6
> --- /dev/null
> +++ b/src/xendisk/xendisk.rc
> @@ -0,0 +1,56 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#include <windows.h>
> +#include <ntverp.h>
> +
> +
> +#undef VER_COMPANYNAME_STR
> +#undef VER_PRODUCTNAME_STR
> +#undef VER_PRODUCTVERSION
> +#undef VER_PRODUCTVERSION_STR
> +
> +#include <version.h>
> +
> +#define      VER_COMPANYNAME_STR         COMPANY_NAME_STR
> +#define VER_LEGALCOPYRIGHT_STR      "Copyright (c) Citrix Systems Inc."
> +
> +#define VER_PRODUCTNAME_STR         "XENDISK"
> +#define VER_PRODUCTVERSION
> MAJOR_VERSION,MINOR_VERSION,MICRO_VERSION,BUILD_NUMBER
> +#define VER_PRODUCTVERSION_STR      MAJOR_VERSION_STR "."
> MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR
> +
> +#define VER_INTERNALNAME_STR        "XENDISK.SYS"
> +#define VER_FILEDESCRIPTION_STR     "XENDISK"
> +
> +#define VER_FILETYPE                VFT_DRV
> +#define VER_FILESUBTYPE             VFT2_DRV_SYSTEM
> +
> +#include <common.ver>
> diff --git a/src/xenvbd.inf b/src/xenvbd.inf
> index bc8627b..0d58453 100644
> --- a/src/xenvbd.inf
> +++ b/src/xenvbd.inf
> @@ -46,6 +46,7 @@ CoInst_CopyFiles=11
>  [SourceDisksFiles]
>  xenvbd.sys=0,,
>  xencrsh.sys=0,,
> +xendisk.sys=0,,
>  xenvbd_coinst.dll=0,,
> 
>  [Manufacturer]
> @@ -62,9 +63,25 @@ CopyFiles=XenVbd_Copyfiles
>  [XenVbd_Copyfiles]
>  xenvbd.sys
>  xencrsh.sys
> +xendisk.sys
> +
> +[XenVbd_Inst.HW]
> +AddReg=XenVbd_AddReg
> +
> +[XenVbd_AddReg]
> +HKR,,"UpperFilters",0x00010000,"xendisk"
> 
>  [XenVbd_Inst.Services]
>  AddService=xenvbd,2,XenVbd_Service,
> +AddService=xendisk,,XenDisk_Service,
> +
> +[XenDisk_Service]
> +DisplayName=%XenDiskDesc%
> +ServiceType=%SERVICE_KERNEL_DRIVER%
> +StartType=%SERVICE_BOOT_START%
> +ErrorControl=%SERVICE_ERROR_NORMAL%
> +ServiceBinary=%12%\xendisk.sys
> +LoadOrderGroup="Scsi Miniport"
> 
>  [XenVbd_Service]
>  DisplayName=%XenVbdDesc%
> @@ -95,6 +112,7 @@
> HKR,,CoInstallers32,0x00010000,"xenvbd_coinst_@MAJOR_VERSION@_@M
> INOR_VERSION@_@M
>  Company = "@COMPANY_NAME@"
>  DiskDesc = "@PRODUCT_NAME@ PV Storage Host Adapter Package"
>  XenVbdDesc= "@PRODUCT_NAME@ PV Storage Host Adapter"
> +XenDiskDesc= "@PRODUCT_NAME@ PV Storage Filter"
> 
>  SERVICE_BOOT_START = 0x0
>  SERVICE_SYSTEM_START = 0x1
> diff --git a/vs2012/package/package.vcxproj
> b/vs2012/package/package.vcxproj
> index 5e5fcbc..9782f19 100644
> --- a/vs2012/package/package.vcxproj
> +++ b/vs2012/package/package.vcxproj
> @@ -51,6 +51,9 @@
>               <ProjectReference Include="..\xenvbd\xenvbd.vcxproj">
>                       <Project>{ef236371-3145-41b1-99c9-
> 82b33e353f17}</Project>
>               </ProjectReference>
> +             <ProjectReference Include="..\xendisk\xendisk.vcxproj">
> +                     <Project>{d7411b2c-2c43-434d-9f56-
> e10a3d2f5bad}</Project>
> +             </ProjectReference>
>       </ItemGroup>
>       <ItemGroup>
>               <FilesToPackage
> Include="$(KIT)\Redist\DIFx\dpinst\EngMui\x86\dpinst.exe"
> Condition="'$(Platform)'=='Win32'" />
> diff --git a/vs2012/xendisk/xendisk.vcxproj
> b/vs2012/xendisk/xendisk.vcxproj
> new file mode 100644
> index 0000000..333bc40
> --- /dev/null
> +++ b/vs2012/xendisk/xendisk.vcxproj
> @@ -0,0 +1,84 @@
> +<?xml version="1.0" encoding="utf-8"?>
> +<Project DefaultTargets="Build" ToolsVersion="4.0"
> xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
> +     <Import Project="..\configs.props" />
> +
> +     <PropertyGroup Label="Globals">
> +             <Configuration>Windows Vista Debug</Configuration>
> +             <Platform Condition="'$(Platform)' == ''">Win32</Platform>
> +
>       <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
> +     </PropertyGroup>
> +     <PropertyGroup Label="ProeprtySheets">
> +
>       <PlatformToolset>WindowsKernelModeDriver8.0</PlatformToolset
> >
> +             <ConfigurationType>Driver</ConfigurationType>
> +             <DriverType>WDM</DriverType>
> +     </PropertyGroup>
> +
> +     <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
> +
> +     <PropertyGroup Label="Globals">
> +             <ProjectGuid>{D7411B2C-2C43-434D-9F56-
> E10A3D2F5BAD}</ProjectGuid>
> +     </PropertyGroup>
> +
> +     <Import Project="..\targets.props" />
> +     <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
> +
> +     <PropertyGroup>
> +
>       <IncludePath>$(ProjectDir)..\..\include;$(IncludePath)</IncludePath
> >
> +             <RunCodeAnalysis>true</RunCodeAnalysis>
> +             <EnableInf2cat>false</EnableInf2cat>
> +
>       <IntDir>..\$(ProjectName)\$(ConfigurationName)\$(Platform)\</Int
> Dir>
> +             <OutDir>..\$(ConfigurationName)\$(Platform)\</OutDir>
> +     </PropertyGroup>
> +
> +     <ItemDefinitionGroup>
> +             <ClCompile>
> +                     <BufferSecurityCheck>false</BufferSecurityCheck>
> +
>       <PreprocessorDefinitions>__MODULE__="XENDISK";%(Preprocesso
> rDefinitions)</PreprocessorDefinitions>
> +                     <WarningLevel>EnableAllWarnings</WarningLevel>
> +
>       <DisableSpecificWarnings>4548;4711;4820;4668;4255;6001;6054;28196
> ;%(DisableSpecificWarnings)</DisableSpecificWarnings>
> +
>       <MultiProcessorCompilation>true</MultiProcessorCompilation>
> +                     <EnablePREfast>true</EnablePREfast>
> +             </ClCompile>
> +             <Link>
> +
>       <AdditionalDependencies>$(DDK_LIB_PATH)/libcntpr.lib;%(Addition
> alDependencies)</AdditionalDependencies>
> +             </Link>
> +             <Inf>
> +                     <SpecifyArchitecture>true</SpecifyArchitecture>
> +
>       <SpecifyDriverVerDirectiveVersion>true</SpecifyDriverVerDirective
> Version>
> +
>       <TimeStamp>$(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VE
> RSION).$(BUILD_NUMBER)</TimeStamp>
> +                     <EnableVerbose>true</EnableVerbose>
> +             </Inf>
> +     </ItemDefinitionGroup>
> +     <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
> +             <ClCompile>
> +
>       <PreprocessorDefinitions>__i386__;%(PreprocessorDefinitions)</Pr
> eprocessorDefinitions>
> +             </ClCompile>
> +             <Inf>
> +                     <Architecture>x86</Architecture>
> +             </Inf>
> +     </ItemDefinitionGroup>
> +     <ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
> +             <ClCompile>
> +
>       <PreprocessorDefinitions>__x86_64__;%(PreprocessorDefinitions)<
> /PreprocessorDefinitions>
> +             </ClCompile>
> +             <Inf>
> +                     <Architecture>amd64</Architecture>
> +             </Inf>
> +     </ItemDefinitionGroup>
> +
> +     <ItemGroup>
> +             <FilesToPackage Include="$(TargetPath)" />
> +             <FilesToPackage Include="$(OutDir)$(TargetName).pdb" />
> +             <FilesToPackage Include="@(Inf->'%(CopyOutput)')"
> Condition="'@(Inf)'!=''" />
> +     </ItemGroup>
> +     <ItemGroup>
> +             <ClCompile Include="../../src/xendisk/driver.c" />
> +             <ClCompile Include="../../src/xendisk/fdo.c" />
> +             <ClCompile Include="../../src/xendisk/pdo.c" />
> +             <ClCompile Include="../../src/xendisk/thread.c" />
> +     </ItemGroup>
> +     <ItemGroup>
> +             <ResourceCompile Include="..\..\src\xendisk\xendisk.rc" />
> +     </ItemGroup>
> +     <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
> +</Project>
> diff --git a/vs2012/xendisk/xendisk.vcxproj.user
> b/vs2012/xendisk/xendisk.vcxproj.user
> new file mode 100644
> index 0000000..0b2b210
> --- /dev/null
> +++ b/vs2012/xendisk/xendisk.vcxproj.user
> @@ -0,0 +1,8 @@
> +<?xml version="1.0" encoding="utf-8"?>
> +<Project ToolsVersion="4.0"
> xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
> +     <PropertyGroup>
> +             <SignMode>TestSign</SignMode>
> +             <TestCertificate>..\..\src\xenvbd.pfx</TestCertificate>
> +
>       <TimeStampServer>http://timestamp.verisign.com/scripts/timstam
> p.dll</TimeStampServer>
> +     </PropertyGroup>
> +</Project>
> diff --git a/vs2012/xenvbd.sln b/vs2012/xenvbd.sln
> index 86fb1a5..15113cf 100644
> --- a/vs2012/xenvbd.sln
> +++ b/vs2012/xenvbd.sln
> @@ -4,10 +4,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")
> = "xenvbd", "xenvbd\xenvbd.vcx
>       ProjectSection(ProjectDependencies) = postProject
>               {50C08437-C1F3-4349-BF6A-7B55A06BF999} = {50C08437-
> C1F3-4349-BF6A-7B55A06BF999}
>               {58F5BC43-B92E-4A2B-975D-0066EAB29092} = {58F5BC43-
> B92E-4A2B-975D-0066EAB29092}
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD} = {D7411B2C-
> 2C43-434D-9F56-E10A3D2F5BAD}
>       EndProjectSection
>  EndProject
>  Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xencrsh",
> "xencrsh\xencrsh.vcxproj", "{58F5BC43-B92E-4A2B-975D-0066EAB29092}"
>  EndProject
> +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xendisk",
> "xendisk\xendisk.vcxproj", "{D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}"
> +EndProject
>  Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xenvbd_coinst",
> "coinst\xenvbd_coinst.vcxproj", "{50C08437-C1F3-4349-BF6A-
> 7B55A06BF999}"
>       ProjectSection(ProjectDependencies) = postProject
>               {58F5BC43-B92E-4A2B-975D-0066EAB29092} = {58F5BC43-
> B92E-4A2B-975D-0066EAB29092}
> @@ -18,6 +21,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")
> = "package", "package\package.
>               {50C08437-C1F3-4349-BF6A-7B55A06BF999} = {50C08437-
> C1F3-4349-BF6A-7B55A06BF999}
>               {58F5BC43-B92E-4A2B-975D-0066EAB29092} = {58F5BC43-
> B92E-4A2B-975D-0066EAB29092}
>          {EF236371-3145-41B1-99C9-82B33E353F17} = {EF236371-3145-41B1-99C9-
> 82B33E353F17}
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD} = {D7411B2C-
> 2C43-434D-9F56-E10A3D2F5BAD}
>       EndProjectSection
>  EndProject
>  Global
> @@ -36,6 +40,30 @@ Global
>               Windows Vista Release|x64 = Windows Vista Release|x64
>       EndGlobalSection
>       GlobalSection(ProjectConfigurationPlatforms) = postSolution
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Debug|Win32.ActiveCfg = Windows 7 Debug|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Debug|Win32.Build.0 = Windows 7 Debug|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Debug|x64.ActiveCfg = Windows 7 Debug|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Debug|x64.Build.0 = Windows 7 Debug|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Release|Win32.ActiveCfg = Windows 7 Release|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Release|Win32.Build.0 = Windows 7 Release|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Release|x64.ActiveCfg = Windows 7 Release|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Release|x64.Build.0 = Windows 7 Release|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Debug|Win32.ActiveCfg = Windows 8 Debug|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Debug|Win32.Build.0 = Windows 8 Debug|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Debug|x64.ActiveCfg = Windows 8 Debug|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Debug|x64.Build.0 = Windows 8 Debug|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Release|Win32.ActiveCfg = Windows 8 Release|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Release|Win32.Build.0 = Windows 8 Release|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Release|x64.ActiveCfg = Windows 8 Release|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Release|x64.Build.0 = Windows 8 Release|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Debug|Win32.ActiveCfg = Windows Vista Debug|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Debug|Win32.Build.0 = Windows Vista Debug|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Debug|x64.ActiveCfg = Windows Vista Debug|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Debug|x64.Build.0 = Windows Vista Debug|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Release|Win32.ActiveCfg = Windows Vista Release|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Release|Win32.Build.0 = Windows Vista Release|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Release|x64.ActiveCfg = Windows Vista Release|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Release|x64.Build.0 = Windows Vista Release|x64
>               {EF236371-3145-41B1-99C9-82B33E353F17}.Windows 7
> Debug|Win32.ActiveCfg = Windows 7 Debug|Win32
>               {EF236371-3145-41B1-99C9-82B33E353F17}.Windows 7
> Debug|Win32.Build.0 = Windows 7 Debug|Win32
>               {EF236371-3145-41B1-99C9-82B33E353F17}.Windows 7
> Debug|x64.ActiveCfg = Windows 7 Debug|x64
> diff --git a/vs2013/package/package.vcxproj
> b/vs2013/package/package.vcxproj
> index 5d0de4d..8b2fa4f 100644
> --- a/vs2013/package/package.vcxproj
> +++ b/vs2013/package/package.vcxproj
> @@ -80,6 +80,9 @@
>      <ProjectReference Include="..\xenvbd\xenvbd.vcxproj">
>        <Project>{ef236371-3145-41b1-99c9-82b33e353f17}</Project>
>      </ProjectReference>
> +    <ProjectReference Include="..\xendisk\xendisk.vcxproj">
> +      <Project>{d7411b2c-2c43-434d-9f56-e10a3d2f5bad}</Project>
> +    </ProjectReference>
>    </ItemGroup>
>    <ItemGroup>
>      <FilesToPackage
> Include="$(KIT)\Redist\DIFx\dpinst\EngMui\x86\dpinst.exe"
> Condition="'$(Platform)'=='Win32'" />
> diff --git a/vs2013/xendisk/xendisk.vcxproj
> b/vs2013/xendisk/xendisk.vcxproj
> new file mode 100644
> index 0000000..39b9163
> --- /dev/null
> +++ b/vs2013/xendisk/xendisk.vcxproj
> @@ -0,0 +1,112 @@
> +<?xml version="1.0" encoding="utf-8"?>
> +<Project DefaultTargets="Build" ToolsVersion="4.0"
> xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
> +  <Import Project="..\configs.props" />
> +  <PropertyGroup Label="Globals">
> +    <Configuration>Windows Vista Debug</Configuration>
> +    <Platform Condition="'$(Platform)' == ''">Win32</Platform>
> +    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
> +  </PropertyGroup>
> +  <PropertyGroup Label="ProeprtySheets">
> +    <ConfigurationType>Driver</ConfigurationType>
> +    <DriverType>WDM</DriverType>
> +  </PropertyGroup>
> +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
> +  <PropertyGroup Label="Configuration"
> Condition="'$(Configuration)|$(Platform)'=='Windows 8 Release|Win32'">
> +    <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
> +  </PropertyGroup>
> +  <PropertyGroup Label="Configuration"
> Condition="'$(Configuration)|$(Platform)'=='Windows Vista Debug|Win32'">
> +    <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
> +  </PropertyGroup>
> +  <PropertyGroup Label="Configuration"
> Condition="'$(Configuration)|$(Platform)'=='Windows Vista
> Release|Win32'">
> +    <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
> +  </PropertyGroup>
> +  <PropertyGroup Label="Configuration"
> Condition="'$(Configuration)|$(Platform)'=='Windows 7 Release|Win32'">
> +    <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
> +  </PropertyGroup>
> +  <PropertyGroup Label="Configuration"
> Condition="'$(Configuration)|$(Platform)'=='Windows 7 Debug|Win32'">
> +    <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
> +  </PropertyGroup>
> +  <PropertyGroup Label="Configuration"
> Condition="'$(Configuration)|$(Platform)'=='Windows 8 Debug|Win32'">
> +    <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
> +  </PropertyGroup>
> +  <PropertyGroup Label="Configuration"
> Condition="'$(Configuration)|$(Platform)'=='Windows 8 Release|x64'">
> +    <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
> +  </PropertyGroup>
> +  <PropertyGroup Label="Configuration"
> Condition="'$(Configuration)|$(Platform)'=='Windows Vista Debug|x64'">
> +    <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
> +  </PropertyGroup>
> +  <PropertyGroup Label="Configuration"
> Condition="'$(Configuration)|$(Platform)'=='Windows Vista Release|x64'">
> +    <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
> +  </PropertyGroup>
> +  <PropertyGroup Label="Configuration"
> Condition="'$(Configuration)|$(Platform)'=='Windows 7 Release|x64'">
> +    <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
> +  </PropertyGroup>
> +  <PropertyGroup Label="Configuration"
> Condition="'$(Configuration)|$(Platform)'=='Windows 7 Debug|x64'">
> +    <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
> +  </PropertyGroup>
> +  <PropertyGroup Label="Configuration"
> Condition="'$(Configuration)|$(Platform)'=='Windows 8 Debug|x64'">
> +    <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
> +  </PropertyGroup>
> +  <PropertyGroup Label="Globals">
> +    <ProjectGuid>{D7411B2C-2C43-434D-9F56-
> E10A3D2F5BAD}</ProjectGuid>
> +  </PropertyGroup>
> +  <Import Project="..\targets.props" />
> +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
> +  <PropertyGroup>
> +    <IncludePath>$(ProjectDir)..\..\include;$(IncludePath)</IncludePath>
> +    <RunCodeAnalysis>true</RunCodeAnalysis>
> +    <EnableInf2cat>false</EnableInf2cat>
> +    <IntDir>..\$(ProjectName)\$(ConfigurationName)\$(Platform)\</IntDir>
> +    <OutDir>..\$(ConfigurationName)\$(Platform)\</OutDir>
> +  </PropertyGroup>
> +  <ItemDefinitionGroup>
> +    <ClCompile>
> +      <BufferSecurityCheck>false</BufferSecurityCheck>
> +
> <PreprocessorDefinitions>__MODULE__="XENDISK";%(PreprocessorDefiniti
> ons)</PreprocessorDefinitions>
> +      <WarningLevel>EnableAllWarnings</WarningLevel>
> +
> <DisableSpecificWarnings>4548;4711;4820;4668;4255;6001;6054;28196;%(Disa
> bleSpecificWarnings)</DisableSpecificWarnings>
> +      <MultiProcessorCompilation>true</MultiProcessorCompilation>
> +      <EnablePREfast>true</EnablePREfast>
> +    </ClCompile>
> +    <Link>
> +
> <AdditionalDependencies>$(DDK_LIB_PATH)/libcntpr.lib;%(AdditionalDepen
> dencies)</AdditionalDependencies>
> +    </Link>
> +    <Inf>
> +      <SpecifyArchitecture>true</SpecifyArchitecture>
> +
> <SpecifyDriverVerDirectiveVersion>true</SpecifyDriverVerDirectiveVersion
> >
> +
> <TimeStamp>$(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION).
> $(BUILD_NUMBER)</TimeStamp>
> +      <EnableVerbose>true</EnableVerbose>
> +    </Inf>
> +  </ItemDefinitionGroup>
> +  <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
> +    <ClCompile>
> +
> <PreprocessorDefinitions>__i386__;%(PreprocessorDefinitions)</Preproces
> sorDefinitions>
> +    </ClCompile>
> +    <Inf>
> +      <Architecture>x86</Architecture>
> +    </Inf>
> +  </ItemDefinitionGroup>
> +  <ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
> +    <ClCompile>
> +
> <PreprocessorDefinitions>__x86_64__;%(PreprocessorDefinitions)</Prepro
> cessorDefinitions>
> +    </ClCompile>
> +    <Inf>
> +      <Architecture>amd64</Architecture>
> +    </Inf>
> +  </ItemDefinitionGroup>
> +  <ItemGroup>
> +    <FilesToPackage Include="$(TargetPath)" />
> +    <FilesToPackage Include="$(OutDir)$(TargetName).pdb" />
> +    <FilesToPackage Include="@(Inf->'%(CopyOutput)')"
> Condition="'@(Inf)'!=''" />
> +  </ItemGroup>
> +  <ItemGroup>
> +    <ClCompile Include="../../src/xendisk/driver.c" />
> +    <ClCompile Include="../../src/xendisk/fdo.c" />
> +    <ClCompile Include="../../src/xendisk/pdo.c" />
> +    <ClCompile Include="../../src/xendisk/thread.c" />
> +  </ItemGroup>
> +  <ItemGroup>
> +    <ResourceCompile Include="..\..\src\xendisk\xendisk.rc" />
> +  </ItemGroup>
> +  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
> +</Project>
> diff --git a/vs2013/xendisk/xendisk.vcxproj.user
> b/vs2013/xendisk/xendisk.vcxproj.user
> new file mode 100644
> index 0000000..1f1f3c0
> --- /dev/null
> +++ b/vs2013/xendisk/xendisk.vcxproj.user
> @@ -0,0 +1,8 @@
> +<?xml version="1.0" encoding="utf-8"?>
> +<Project ToolsVersion="4.0"
> xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
> +  <PropertyGroup>
> +    <SignMode>TestSign</SignMode>
> +    <TestCertificate>..\..\src\xenvbd.pfx</TestCertificate>
> +
> <TimeStampServer>http://timestamp.verisign.com/scripts/timstamp.dll</Ti
> meStampServer>
> +  </PropertyGroup>
> +</Project>
> diff --git a/vs2013/xenvbd.sln b/vs2013/xenvbd.sln
> index 13128c5..da798d2 100644
> --- a/vs2013/xenvbd.sln
> +++ b/vs2013/xenvbd.sln
> @@ -4,10 +4,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")
> = "xenvbd", "xenvbd\xenvbd.vcx
>       ProjectSection(ProjectDependencies) = postProject
>               {50C08437-C1F3-4349-BF6A-7B55A06BF999} = {50C08437-
> C1F3-4349-BF6A-7B55A06BF999}
>               {58F5BC43-B92E-4A2B-975D-0066EAB29092} = {58F5BC43-
> B92E-4A2B-975D-0066EAB29092}
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD} = {D7411B2C-
> 2C43-434D-9F56-E10A3D2F5BAD}
>       EndProjectSection
>  EndProject
>  Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xencrsh",
> "xencrsh\xencrsh.vcxproj", "{58F5BC43-B92E-4A2B-975D-0066EAB29092}"
>  EndProject
> +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xendisk",
> "xendisk\xendisk.vcxproj", "{D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}"
> +EndProject
>  Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xenvbd_coinst",
> "coinst\xenvbd_coinst.vcxproj", "{50C08437-C1F3-4349-BF6A-
> 7B55A06BF999}"
>      ProjectSection(ProjectDependencies) = postProject
>               {58F5BC43-B92E-4A2B-975D-0066EAB29092} = {58F5BC43-
> B92E-4A2B-975D-0066EAB29092}
> @@ -18,6 +21,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")
> = "package", "package\package.
>               {50C08437-C1F3-4349-BF6A-7B55A06BF999} = {50C08437-
> C1F3-4349-BF6A-7B55A06BF999}
>               {58F5BC43-B92E-4A2B-975D-0066EAB29092} = {58F5BC43-
> B92E-4A2B-975D-0066EAB29092}
>          {EF236371-3145-41B1-99C9-82B33E353F17} = {EF236371-3145-41B1-99C9-
> 82B33E353F17}
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD} = {D7411B2C-
> 2C43-434D-9F56-E10A3D2F5BAD}
>       EndProjectSection
>  EndProject
>  Global
> @@ -36,6 +40,30 @@ Global
>               Windows Vista Release|x64 = Windows Vista Release|x64
>       EndGlobalSection
>       GlobalSection(ProjectConfigurationPlatforms) = postSolution
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Debug|Win32.ActiveCfg = Windows 7 Debug|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Debug|Win32.Build.0 = Windows 7 Debug|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Debug|x64.ActiveCfg = Windows 7 Debug|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Debug|x64.Build.0 = Windows 7 Debug|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Release|Win32.ActiveCfg = Windows 7 Release|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Release|Win32.Build.0 = Windows 7 Release|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Release|x64.ActiveCfg = Windows 7 Release|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
> Release|x64.Build.0 = Windows 7 Release|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Debug|Win32.ActiveCfg = Windows 8 Debug|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Debug|Win32.Build.0 = Windows 8 Debug|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Debug|x64.ActiveCfg = Windows 8 Debug|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Debug|x64.Build.0 = Windows 8 Debug|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Release|Win32.ActiveCfg = Windows 8 Release|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Release|Win32.Build.0 = Windows 8 Release|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Release|x64.ActiveCfg = Windows 8 Release|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
> Release|x64.Build.0 = Windows 8 Release|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Debug|Win32.ActiveCfg = Windows Vista Debug|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Debug|Win32.Build.0 = Windows Vista Debug|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Debug|x64.ActiveCfg = Windows Vista Debug|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Debug|x64.Build.0 = Windows Vista Debug|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Release|Win32.ActiveCfg = Windows Vista Release|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Release|Win32.Build.0 = Windows Vista Release|Win32
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Release|x64.ActiveCfg = Windows Vista Release|x64
> +             {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
> Release|x64.Build.0 = Windows Vista Release|x64
>               {EF236371-3145-41B1-99C9-82B33E353F17}.Windows 7
> Debug|Win32.ActiveCfg = Windows 7 Debug|Win32
>               {EF236371-3145-41B1-99C9-82B33E353F17}.Windows 7
> Debug|Win32.Build.0 = Windows 7 Debug|Win32
>               {EF236371-3145-41B1-99C9-82B33E353F17}.Windows 7
> Debug|x64.ActiveCfg = Windows 7 Debug|x64
> --
> 1.9.4.msysgit.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.