win-pvdrivers

changeset 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 d9a2a6de2ab4
children 221ae2b4b859
files xenvbd_filter/xenvbd_filter.c xenvbd_filter/xenvbd_filter.h xenvbd_scsiport/xenvbd.c
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)) {
     2.1 --- a/xenvbd_filter/xenvbd_filter.h	Tue Feb 19 20:54:48 2013 +1100
     2.2 +++ b/xenvbd_filter/xenvbd_filter.h	Tue Feb 19 20:57:09 2013 +1100
     2.3 @@ -58,6 +58,7 @@ typedef struct {
     2.4    WDFIOTARGET wdf_target;
     2.5    WDFDPC dpc;
     2.6    WDFQUEUE io_queue;
     2.7 +  BOOLEAN hibernate_flag;
     2.8    
     2.9    XENVBD_DEVICE_DATA xvdd;
    2.10  } XENVBD_FILTER_DATA, *PXENVBD_FILTER_DATA;
     3.1 --- a/xenvbd_scsiport/xenvbd.c	Tue Feb 19 20:54:48 2013 +1100
     3.2 +++ b/xenvbd_scsiport/xenvbd.c	Tue Feb 19 20:57:09 2013 +1100
     3.3 @@ -77,7 +77,6 @@ XenVbd_NotificationNextLuRequest(PXENVBD
     3.4  /* called in non-dump mode */
     3.5  static ULONG
     3.6  XenVbd_HwScsiFindAdapter(PVOID DeviceExtension, PVOID HwContext, PVOID BusInformation, PCHAR ArgumentString, PPORT_CONFIGURATION_INFORMATION ConfigInfo, PBOOLEAN Again) {
     3.7 -  //NTSTATUS status;
     3.8    PXENVBD_SCSIPORT_DATA xvsd = (PXENVBD_SCSIPORT_DATA)DeviceExtension;
     3.9    PXENVBD_DEVICE_DATA xvdd;
    3.10    PACCESS_RANGE access_range;
    3.11 @@ -87,16 +86,9 @@ XenVbd_HwScsiFindAdapter(PVOID DeviceExt
    3.12    UNREFERENCED_PARAMETER(ArgumentString);
    3.13  
    3.14    FUNCTION_ENTER(); 
    3.15 -  KdPrint((__DRIVER_NAME "     IRQL = %d\n", KeGetCurrentIrql()));
    3.16 -  KdPrint((__DRIVER_NAME "     xvsd = %p\n", xvsd));
    3.17 +  FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
    3.18 +  FUNCTION_MSG("xvsd = %p\n", xvsd);
    3.19  
    3.20 -  if (dump_mode) {
    3.21 -    if (xvsd->xvdd->device_state != DEVICE_STATE_ACTIVE) {
    3.22 -      /* if we are not connected to the ring when we start dump mode then there is nothing we can do */
    3.23 -      FUNCTION_MSG("Cannot connect backend in dump mode - state = %d\n", xvsd->xvdd->device_state);
    3.24 -      return SP_RETURN_ERROR;
    3.25 -    }
    3.26 -  }
    3.27    if (ConfigInfo->NumberOfAccessRanges != 1) {
    3.28      FUNCTION_MSG("NumberOfAccessRanges wrong\n");
    3.29      FUNCTION_EXIT();
    3.30 @@ -107,19 +99,36 @@ XenVbd_HwScsiFindAdapter(PVOID DeviceExt
    3.31      FUNCTION_EXIT();
    3.32      return SP_RETURN_BAD_CONFIG;
    3.33    }
    3.34 -  RtlZeroMemory(xvsd, sizeof(XENVBD_SCSIPORT_DATA));
    3.35 +  RtlZeroMemory(xvsd, FIELD_OFFSET(XENVBD_SCSIPORT_DATA, aligned_buffer_data));
    3.36  
    3.37    access_range = &((*(ConfigInfo->AccessRanges))[0]);
    3.38 -  xvdd = (PXENVBD_DEVICE_DATA)(ULONG_PTR)access_range->RangeStart.QuadPart;
    3.39 -  xvsd->xvdd = xvdd;
    3.40 -  xvdd->xvsd = xvsd;
    3.41 +
    3.42 +  if (!dump_mode) {
    3.43 +    xvdd = (PXENVBD_DEVICE_DATA)(ULONG_PTR)access_range->RangeStart.QuadPart;
    3.44 +    xvsd->xvdd = xvdd;
    3.45 +    xvdd->xvsd = xvsd;
    3.46 +    xvdd->aligned_buffer = (PVOID)((ULONG_PTR)((PUCHAR)xvsd->aligned_buffer_data + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1));
    3.47 +  } else {
    3.48 +    /* make a copy of xvdd and use that copy */
    3.49 +    xvdd = (PXENVBD_DEVICE_DATA)xvsd->aligned_buffer_data;
    3.50 +    memcpy(xvdd, (PVOID)(ULONG_PTR)access_range->RangeStart.QuadPart, sizeof(XENVBD_DEVICE_DATA));
    3.51 +    /* make sure original xvdd is set to DISCONNECTED or resume will not work */
    3.52 +    ((PXENVBD_DEVICE_DATA)(ULONG_PTR)access_range->RangeStart.QuadPart)->device_state = DEVICE_STATE_DISCONNECTED;
    3.53 +    xvsd->xvdd = xvdd;
    3.54 +    xvdd->xvsd = xvsd;
    3.55 +    xvdd->aligned_buffer = (PVOID)((ULONG_PTR)((PUCHAR)xvsd->aligned_buffer_data + sizeof(XENVBD_DEVICE_DATA) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1));
    3.56 +    if (xvsd->xvdd->device_state != DEVICE_STATE_ACTIVE) {
    3.57 +      /* if we are not connected to the ring when we start dump mode then there is nothing we can do */
    3.58 +      FUNCTION_MSG("Cannot connect backend in dump mode - state = %d\n", xvsd->xvdd->device_state);
    3.59 +      return SP_RETURN_ERROR;
    3.60 +    }
    3.61 +  }
    3.62 +  FUNCTION_MSG("aligned_buffer_data = %p\n", xvsd->aligned_buffer_data);
    3.63 +  FUNCTION_MSG("aligned_buffer = %p\n", xvdd->aligned_buffer);
    3.64  
    3.65    InitializeListHead(&xvdd->srb_list);
    3.66    xvdd->aligned_buffer_in_use = FALSE;
    3.67    /* align the buffer to PAGE_SIZE */
    3.68 -  xvdd->aligned_buffer = (PVOID)((ULONG_PTR)((PUCHAR)xvsd->aligned_buffer_data + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1));
    3.69 -  KdPrint((__DRIVER_NAME "     aligned_buffer_data = %p\n", xvsd->aligned_buffer_data));
    3.70 -  KdPrint((__DRIVER_NAME "     aligned_buffer = %p\n", xvdd->aligned_buffer));
    3.71  
    3.72    ConfigInfo->MaximumTransferLength = 4 * 1024 * 1024; //BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE;
    3.73    ConfigInfo->NumberOfPhysicalBreaks = ConfigInfo->MaximumTransferLength >> PAGE_SHIFT; //BLKIF_MAX_SEGMENTS_PER_REQUEST - 1;
    3.74 @@ -130,7 +139,6 @@ XenVbd_HwScsiFindAdapter(PVOID DeviceExt
    3.75    } else {
    3.76      xvdd->aligned_buffer_size = DUMP_MODE_UNALIGNED_PAGES * PAGE_SIZE;
    3.77    }
    3.78 -  //status = XenVbd_Connect(DeviceExtension, FALSE);
    3.79  
    3.80    FUNCTION_MSG("MultipleRequestPerLu = %d\n", ConfigInfo->MultipleRequestPerLu);
    3.81    FUNCTION_MSG("TaggedQueuing = %d\n", ConfigInfo->TaggedQueuing);
    3.82 @@ -165,8 +173,8 @@ XenVbd_HwScsiInitialize(PVOID DeviceExte
    3.83    ULONG i;
    3.84    
    3.85    FUNCTION_ENTER();
    3.86 -  KdPrint((__DRIVER_NAME "     IRQL = %d\n", KeGetCurrentIrql()));
    3.87 -  KdPrint((__DRIVER_NAME "     dump_mode = %d\n", dump_mode));
    3.88 +  FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
    3.89 +  FUNCTION_MSG("dump_mode = %d\n", dump_mode);
    3.90    
    3.91    xvdd->shadow_free = 0;
    3.92    memset(xvdd->shadows, 0, sizeof(blkif_shadow_t) * SHADOW_ENTRIES);
    3.93 @@ -278,52 +286,50 @@ XenVbd_HwScsiStartIo(PVOID DeviceExtensi
    3.94  }
    3.95  
    3.96  static SCSI_ADAPTER_CONTROL_STATUS
    3.97 -XenVbd_HwScsiAdapterControl(PVOID DeviceExtension, SCSI_ADAPTER_CONTROL_TYPE ControlType, PVOID Parameters)
    3.98 -{
    3.99 +XenVbd_HwScsiAdapterControl(PVOID DeviceExtension, SCSI_ADAPTER_CONTROL_TYPE ControlType, PVOID Parameters) {
   3.100    PXENVBD_SCSIPORT_DATA xvsd = DeviceExtension;
   3.101    PXENVBD_DEVICE_DATA xvdd = (PXENVBD_DEVICE_DATA)xvsd->xvdd;
   3.102    SCSI_ADAPTER_CONTROL_STATUS Status = ScsiAdapterControlSuccess;
   3.103    PSCSI_SUPPORTED_CONTROL_TYPE_LIST SupportedControlTypeList;
   3.104  
   3.105    FUNCTION_ENTER();
   3.106 -  KdPrint((__DRIVER_NAME "     IRQL = %d\n", KeGetCurrentIrql()));
   3.107 -  KdPrint((__DRIVER_NAME "     xvsd = %p\n", xvsd));
   3.108 +  FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
   3.109 +  FUNCTION_MSG("xvsd = %p\n", xvsd);
   3.110  
   3.111 -  switch (ControlType)
   3.112 -  {
   3.113 +  switch (ControlType) {
   3.114    case ScsiQuerySupportedControlTypes:
   3.115      SupportedControlTypeList = (PSCSI_SUPPORTED_CONTROL_TYPE_LIST)Parameters;
   3.116 -    KdPrint((__DRIVER_NAME "     ScsiQuerySupportedControlTypes (Max = %d)\n", SupportedControlTypeList->MaxControlType));
   3.117 +    FUNCTION_MSG("ScsiQuerySupportedControlTypes (Max = %d)\n", SupportedControlTypeList->MaxControlType);
   3.118      SupportedControlTypeList->SupportedTypeList[ScsiQuerySupportedControlTypes] = TRUE;
   3.119      SupportedControlTypeList->SupportedTypeList[ScsiStopAdapter] = TRUE;
   3.120      SupportedControlTypeList->SupportedTypeList[ScsiRestartAdapter] = TRUE;
   3.121      break;
   3.122    case ScsiStopAdapter:
   3.123 -    KdPrint((__DRIVER_NAME "     ScsiStopAdapter\n"));
   3.124 +    FUNCTION_MSG("ScsiStopAdapter\n");
   3.125      if (xvdd->device_state == DEVICE_STATE_INACTIVE) {
   3.126 -      KdPrint((__DRIVER_NAME "     inactive - nothing to do\n"));
   3.127 +      FUNCTION_MSG("inactive - nothing to do\n");
   3.128        break;
   3.129      }
   3.130 -    NT_ASSERT(IsListEmpty(&xvdd->srb_list));
   3.131 -    NT_ASSERT(xvdd->shadow_free == SHADOW_ENTRIES);
   3.132 +    XN_ASSERT(IsListEmpty(&xvdd->srb_list));
   3.133 +    XN_ASSERT(xvdd->shadow_free == SHADOW_ENTRIES);
   3.134      break;
   3.135    case ScsiRestartAdapter:
   3.136 -    KdPrint((__DRIVER_NAME "     ScsiRestartAdapter\n"));
   3.137 +    FUNCTION_MSG("ScsiRestartAdapter\n");
   3.138      if (xvdd->device_state == DEVICE_STATE_INACTIVE) {
   3.139 -      KdPrint((__DRIVER_NAME "     inactive - nothing to do\n"));
   3.140 +      FUNCTION_MSG("inactive - nothing to do\n");
   3.141        break;
   3.142      }
   3.143      /* increase the tag every time we stop/start to track where the gref's came from */
   3.144      xvdd->grant_tag++;
   3.145      break;
   3.146    case ScsiSetBootConfig:
   3.147 -    KdPrint((__DRIVER_NAME "     ScsiSetBootConfig\n"));
   3.148 +    FUNCTION_MSG("ScsiSetBootConfig\n");
   3.149      break;
   3.150    case ScsiSetRunningConfig:
   3.151 -    KdPrint((__DRIVER_NAME "     ScsiSetRunningConfig\n"));
   3.152 +    FUNCTION_MSG("ScsiSetRunningConfig\n");
   3.153      break;
   3.154    default:
   3.155 -    KdPrint((__DRIVER_NAME "     UNKNOWN\n"));
   3.156 +    FUNCTION_MSG("UNKNOWN\n");
   3.157      break;
   3.158    }
   3.159  
   3.160 @@ -339,13 +345,13 @@ DriverEntry(PDRIVER_OBJECT DriverObject,
   3.161    
   3.162    /* RegistryPath == NULL when we are invoked as a crash dump driver */
   3.163    if (!RegistryPath) {
   3.164 -    KdPrint((__DRIVER_NAME "     IRQL = %d (if you can read this we aren't in dump mode)\n", KeGetCurrentIrql()));
   3.165      dump_mode = TRUE;
   3.166 +    XnPrintDump();
   3.167    }
   3.168  
   3.169    FUNCTION_ENTER();
   3.170 -  KdPrint((__DRIVER_NAME "     IRQL = %d\n", KeGetCurrentIrql()));
   3.171 -  KdPrint((__DRIVER_NAME "     DriverObject = %p, RegistryPath = %p\n", DriverObject, RegistryPath));
   3.172 +  FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
   3.173 +  FUNCTION_MSG("DriverObject = %p, RegistryPath = %p\n", DriverObject, RegistryPath);
   3.174    
   3.175    RtlZeroMemory(&HwInitializationData, sizeof(HW_INITIALIZATION_DATA));
   3.176    HwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
   3.177 @@ -367,7 +373,7 @@ DriverEntry(PDRIVER_OBJECT DriverObject,
   3.178      HwInitializationData.DeviceExtensionSize = FIELD_OFFSET(XENVBD_SCSIPORT_DATA, aligned_buffer_data) + UNALIGNED_BUFFER_DATA_SIZE;
   3.179    } else {
   3.180      HwInitializationData.HwInterrupt = XenVbd_HwScsiInterrupt;
   3.181 -    HwInitializationData.DeviceExtensionSize = FIELD_OFFSET(XENVBD_SCSIPORT_DATA, aligned_buffer_data) + UNALIGNED_BUFFER_DATA_SIZE_DUMP_MODE;
   3.182 +    HwInitializationData.DeviceExtensionSize = FIELD_OFFSET(XENVBD_SCSIPORT_DATA, aligned_buffer_data) + sizeof(XENVBD_DEVICE_DATA) + UNALIGNED_BUFFER_DATA_SIZE_DUMP_MODE;
   3.183    }
   3.184    status = ScsiPortInitialize(DriverObject, RegistryPath, &HwInitializationData, NULL);
   3.185