win-pvdrivers

diff xenvbd_filter/xenvbd_filter.c @ 1027:0f40ce5cb467

Fix hibernate in scsiport
author James Harper <james.harper@bendigoit.com.au>
date Tue Feb 19 20:57:09 2013 +1100 (2013-02-19)
parents aa2e51f67f7c
children b448f01b31e8
line diff
     1.1 --- a/xenvbd_filter/xenvbd_filter.c	Tue Feb 19 20:54:48 2013 +1100
     1.2 +++ b/xenvbd_filter/xenvbd_filter.c	Tue Feb 19 20:57:09 2013 +1100
     1.3 @@ -29,6 +29,7 @@ static EVT_WDF_REQUEST_COMPLETION_ROUTIN
     1.4  static EVT_WDF_DEVICE_D0_ENTRY XenVbd_EvtDeviceD0Entry;
     1.5  static EVT_WDF_DEVICE_D0_EXIT XenVbd_EvtDeviceD0Exit;
     1.6  static EVT_WDFDEVICE_WDM_IRP_PREPROCESS XenVbd_EvtDeviceWdmIrpPreprocess_START_DEVICE;
     1.7 +static EVT_WDFDEVICE_WDM_IRP_PREPROCESS XenVbd_EvtDeviceWdmIrpPreprocess_SET_POWER;
     1.8  static EVT_WDF_DPC XenVbd_EvtDpcEvent;
     1.9  static IO_COMPLETION_ROUTINE XenVbd_IoCompletion_START_DEVICE;
    1.10  
    1.11 @@ -249,11 +250,39 @@ XenVbd_EvtDeviceD0Entry(WDFDEVICE device
    1.12  static NTSTATUS
    1.13  XenVbd_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state) {
    1.14    PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
    1.15 -  NTSTATUS status;
    1.16 -  // if hibernate then same as suspend
    1.17 -  UNREFERENCED_PARAMETER(target_state);
    1.18 +  NTSTATUS status = STATUS_SUCCESS;
    1.19 +
    1.20    FUNCTION_ENTER();
    1.21 -  status = XenVbd_Disconnect(&xvfd->xvdd, FALSE);
    1.22 +  switch (target_state) {
    1.23 +  case WdfPowerDeviceD0:
    1.24 +    FUNCTION_MSG("WdfPowerDeviceD1\n");
    1.25 +    break;
    1.26 +  case WdfPowerDeviceD1:
    1.27 +    FUNCTION_MSG("WdfPowerDeviceD1\n");
    1.28 +    break;
    1.29 +  case WdfPowerDeviceD2:
    1.30 +    FUNCTION_MSG("WdfPowerDeviceD2\n");
    1.31 +    break;
    1.32 +  case WdfPowerDeviceD3:
    1.33 +    FUNCTION_MSG("WdfPowerDeviceD3\n");
    1.34 +    if (xvfd->hibernate_flag) {
    1.35 +      FUNCTION_MSG("(but really WdfPowerDevicePrepareForHibernation)\n");
    1.36 +      target_state = WdfPowerDevicePrepareForHibernation;
    1.37 +    }
    1.38 +    break;
    1.39 +  case WdfPowerDeviceD3Final:
    1.40 +    FUNCTION_MSG("WdfPowerDeviceD3Final\n");
    1.41 +    break;
    1.42 +  case WdfPowerDevicePrepareForHibernation:
    1.43 +    FUNCTION_MSG("WdfPowerDevicePrepareForHibernation\n");
    1.44 +    break;  
    1.45 +  default:
    1.46 +    FUNCTION_MSG("Unknown WdfPowerDevice state %d\n", target_state);
    1.47 +    break;  
    1.48 +  }
    1.49 +  if (target_state != WdfPowerDevicePrepareForHibernation) {
    1.50 +    status = XenVbd_Disconnect(&xvfd->xvdd, FALSE);
    1.51 +  }
    1.52    FUNCTION_EXIT();
    1.53    return status;
    1.54  }
    1.55 @@ -318,6 +347,25 @@ XenVbd_EvtDeviceWdmIrpPreprocess_START_D
    1.56    return WdfDeviceWdmDispatchPreprocessedIrp(device, irp);
    1.57  }
    1.58  
    1.59 +/* scsiport doesn't process SET_POWER correctly so we have to fudge detection of hibernate */
    1.60 +static NTSTATUS
    1.61 +XenVbd_EvtDeviceWdmIrpPreprocess_SET_POWER(WDFDEVICE device, PIRP irp) {
    1.62 +  PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
    1.63 +  PIO_STACK_LOCATION stack;
    1.64 +  
    1.65 +  FUNCTION_ENTER();
    1.66 +  stack = IoGetCurrentIrpStackLocation(irp);
    1.67 +  if (stack->Parameters.Power.Type == DevicePowerState && stack->Parameters.Power.State.DeviceState == PowerDeviceD3 && stack->Parameters.Power.ShutdownType == PowerActionHibernate) {
    1.68 +    FUNCTION_MSG("Going to hibernate\n");
    1.69 +    xvfd->hibernate_flag = TRUE;
    1.70 +  } else {
    1.71 +    xvfd->hibernate_flag = FALSE;
    1.72 +  }
    1.73 +  IoSkipCurrentIrpStackLocation(irp);
    1.74 +  FUNCTION_EXIT();
    1.75 +  return WdfDeviceWdmDispatchPreprocessedIrp(device, irp);
    1.76 +}
    1.77 +
    1.78  static NTSTATUS
    1.79  XenVbd_EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init) {
    1.80    PXENVBD_FILTER_DATA xvfd;
    1.81 @@ -328,6 +376,7 @@ XenVbd_EvtDeviceAdd(WDFDRIVER driver, PW
    1.82    WDF_DPC_CONFIG dpc_config;
    1.83    WDF_OBJECT_ATTRIBUTES oa;
    1.84    UCHAR pnp_minor_functions[] = { IRP_MN_START_DEVICE };
    1.85 +  UCHAR power_minor_functions[] = { IRP_MN_SET_POWER };
    1.86    
    1.87    UNREFERENCED_PARAMETER(driver);
    1.88  
    1.89 @@ -348,6 +397,12 @@ XenVbd_EvtDeviceAdd(WDFDRIVER driver, PW
    1.90      return status;
    1.91    }
    1.92  
    1.93 +  status = WdfDeviceInitAssignWdmIrpPreprocessCallback(device_init, XenVbd_EvtDeviceWdmIrpPreprocess_SET_POWER,
    1.94 +    IRP_MJ_POWER, power_minor_functions, ARRAY_SIZE(power_minor_functions));
    1.95 +  if (!NT_SUCCESS(status)) {
    1.96 +    return status;
    1.97 +  }
    1.98 +
    1.99    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&device_attributes, XENVBD_FILTER_DATA);
   1.100    status = WdfDeviceCreate(&device_init, &device_attributes, &device);
   1.101    if (!NT_SUCCESS(status)) {