win-pvdrivers

view xenvbd_filter/xenvbd_filter.c @ 1025:aa2e51f67f7c

Fix hibernate under Win8. Change debugprints.
author James Harper <james.harper@bendigoit.com.au>
date Tue Feb 19 15:14:53 2013 +1100 (2013-02-19)
parents 2b8784b1a034
children 0f40ce5cb467
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
3 Copyright (C) 2013 James Harper
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
20 #include "xenvbd_filter.h"
21 #include "ntddscsi.h"
22 #include "srb.h"
24 DRIVER_INITIALIZE DriverEntry;
26 static EVT_WDF_DRIVER_UNLOAD XenVbd_EvtDriverUnload;
27 static EVT_WDF_DRIVER_DEVICE_ADD XenVbd_EvtDeviceAdd;
28 static EVT_WDF_REQUEST_COMPLETION_ROUTINE XenVbd_SendRequestComplete;
29 static EVT_WDF_DEVICE_D0_ENTRY XenVbd_EvtDeviceD0Entry;
30 static EVT_WDF_DEVICE_D0_EXIT XenVbd_EvtDeviceD0Exit;
31 static EVT_WDFDEVICE_WDM_IRP_PREPROCESS XenVbd_EvtDeviceWdmIrpPreprocess_START_DEVICE;
32 static EVT_WDF_DPC XenVbd_EvtDpcEvent;
33 static IO_COMPLETION_ROUTINE XenVbd_IoCompletion_START_DEVICE;
35 static VOID XenVbd_DeviceCallback(PVOID context, ULONG callback_type, PVOID value);
36 static VOID XenVbd_HandleEventDIRQL(PVOID context);
37 static VOID XenVbd_StopRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend);
38 static VOID XenVbd_StartRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend);
40 #include "../xenvbd_common/common_xen.h"
42 static VOID XenVbd_SendEvent(WDFDEVICE device);
44 static VOID
45 XenVbd_StopRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend) {
46 PXENVBD_FILTER_DATA xvfd = (PXENVBD_FILTER_DATA)xvdd->xvfd;
47 NTSTATUS status;
48 WDFREQUEST request;
49 WDF_REQUEST_SEND_OPTIONS send_options;
50 IO_STACK_LOCATION stack;
51 SCSI_REQUEST_BLOCK srb;
52 SRB_IO_CONTROL sic;
54 FUNCTION_ENTER();
56 /* send a 'stop' down if we are suspending */
57 if (suspend) {
58 status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, xvfd->wdf_target, &request);
59 FUNCTION_MSG("WdfRequestCreate = %08x\n", status);
61 RtlZeroMemory(&stack, sizeof(IO_STACK_LOCATION));
62 stack.MajorFunction = IRP_MJ_SCSI;
63 stack.MinorFunction = IRP_MN_SCSI_CLASS;
64 stack.Parameters.Scsi.Srb = &srb;
66 RtlZeroMemory(&srb, SCSI_REQUEST_BLOCK_SIZE);
67 srb.SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE;
68 srb.Length = SCSI_REQUEST_BLOCK_SIZE;
69 srb.PathId = 0;
70 srb.TargetId = 0;
71 srb.Lun = 0;
72 srb.OriginalRequest = WdfRequestWdmGetIrp(request);
73 srb.Function = SRB_FUNCTION_IO_CONTROL;
74 srb.DataBuffer = &sic;
76 RtlZeroMemory(&sic, sizeof(SRB_IO_CONTROL));
77 sic.HeaderLength = sizeof(SRB_IO_CONTROL);
78 memcpy(sic.Signature, XENVBD_CONTROL_SIG, 8);
79 sic.Timeout = 60;
80 sic.ControlCode = XENVBD_CONTROL_STOP;
82 WdfRequestWdmFormatUsingStackLocation(request, &stack);
84 WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
85 if (!WdfRequestSend(request, xvfd->wdf_target, &send_options)) {
86 FUNCTION_MSG("Request was _NOT_ sent\n");
87 }
88 status = WdfRequestGetStatus(request);
89 FUNCTION_MSG("Request Status = %08x\n", status);
90 FUNCTION_MSG("SRB Status = %08x\n", srb.SrbStatus);
92 WdfObjectDelete(request);
93 }
95 status = XnWriteInt32(xvdd->handle, XN_BASE_FRONTEND, "state", XenbusStateClosing);
97 FUNCTION_EXIT();
98 }
100 static VOID
101 XenVbd_StartRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend) {
102 PXENVBD_FILTER_DATA xvfd = (PXENVBD_FILTER_DATA)xvdd->xvfd;
103 NTSTATUS status;
104 WDFREQUEST request;
105 WDF_REQUEST_SEND_OPTIONS send_options;
106 IO_STACK_LOCATION stack;
107 SCSI_REQUEST_BLOCK srb;
108 SRB_IO_CONTROL sic;
110 FUNCTION_ENTER();
112 /* send a 'start' down if we are resuming from a suspend */
113 if (suspend) {
114 status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, xvfd->wdf_target, &request);
115 FUNCTION_MSG("WdfRequestCreate = %08x\n", status);
117 RtlZeroMemory(&stack, sizeof(IO_STACK_LOCATION));
118 stack.MajorFunction = IRP_MJ_SCSI;
119 stack.Parameters.Scsi.Srb = &srb;
121 RtlZeroMemory(&srb, SCSI_REQUEST_BLOCK_SIZE);
122 srb.SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE;
123 srb.Length = SCSI_REQUEST_BLOCK_SIZE;
124 srb.PathId = 0;
125 srb.TargetId = 0;
126 srb.Lun = 0;
127 srb.OriginalRequest = WdfRequestWdmGetIrp(request);
128 srb.Function = SRB_FUNCTION_IO_CONTROL;
129 srb.DataBuffer = &sic;
131 RtlZeroMemory(&sic, sizeof(SRB_IO_CONTROL));
132 sic.HeaderLength = sizeof(SRB_IO_CONTROL);
133 memcpy(sic.Signature, XENVBD_CONTROL_SIG, 8);
134 sic.Timeout = 60;
135 sic.ControlCode = XENVBD_CONTROL_START;
137 WdfRequestWdmFormatUsingStackLocation(request, &stack);
139 WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
140 if (!WdfRequestSend(request, xvfd->wdf_target, &send_options)) {
141 FUNCTION_MSG("Request was _NOT_ sent\n");
142 }
143 status = WdfRequestGetStatus(request);
144 FUNCTION_MSG("Request Status = %08x\n", status);
145 FUNCTION_MSG("SRB Status = %08x\n", srb.SrbStatus);
147 WdfObjectDelete(request);
148 }
150 FUNCTION_EXIT();
151 }
153 static VOID
154 XenVbd_SendRequestComplete(WDFREQUEST request, WDFIOTARGET target, PWDF_REQUEST_COMPLETION_PARAMS params, WDFCONTEXT context) {
155 NTSTATUS status;
156 PSCSI_REQUEST_BLOCK srb = context;
158 UNREFERENCED_PARAMETER(target);
159 UNREFERENCED_PARAMETER(params);
160 UNREFERENCED_PARAMETER(context);
162 status = WdfRequestGetStatus(request);
163 if (status != 0 || srb->SrbStatus != SRB_STATUS_SUCCESS) {
164 FUNCTION_MSG("Request Status = %08x, SRB Status = %08x\n", status, srb->SrbStatus);
165 }
166 ExFreePoolWithTag(context, XENVBD_POOL_TAG);
167 WdfObjectDelete(request);
168 }
170 static VOID
171 XenVbd_SendEvent(WDFDEVICE device) {
172 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
173 NTSTATUS status;
174 WDFREQUEST request;
175 WDF_REQUEST_SEND_OPTIONS send_options;
176 IO_STACK_LOCATION stack;
177 PUCHAR buf;
178 PSCSI_REQUEST_BLOCK srb;
179 PSRB_IO_CONTROL sic;
181 status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, xvfd->wdf_target, &request);
182 if (status != STATUS_SUCCESS) {
183 /* this is bad - event will be dropped */
184 return;
185 }
187 buf = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL), XENVBD_POOL_TAG);
188 RtlZeroMemory(buf, sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL));
189 srb = (PSCSI_REQUEST_BLOCK)(buf);
190 sic = (PSRB_IO_CONTROL)(buf + sizeof(SCSI_REQUEST_BLOCK));
192 srb->Length = sizeof(SCSI_REQUEST_BLOCK);
193 srb->SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE;
194 srb->PathId = 0;
195 srb->TargetId = 0;
196 srb->Lun = 0;
197 srb->OriginalRequest = WdfRequestWdmGetIrp(request);
198 srb->Function = SRB_FUNCTION_IO_CONTROL;
199 srb->DataBuffer = sic;
200 srb->DataTransferLength = sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL);
201 srb->TimeOutValue = (ULONG)-1;
203 sic->HeaderLength = sizeof(SRB_IO_CONTROL);
204 memcpy(sic->Signature, XENVBD_CONTROL_SIG, 8);
205 sic->Timeout = (ULONG)-1;
206 sic->ControlCode = XENVBD_CONTROL_EVENT;
208 RtlZeroMemory(&stack, sizeof(IO_STACK_LOCATION));
209 stack.MajorFunction = IRP_MJ_SCSI;
210 stack.MinorFunction = IRP_MN_SCSI_CLASS;
211 stack.Parameters.Scsi.Srb = srb;
213 WdfRequestWdmFormatUsingStackLocation(request, &stack);
214 WdfRequestSetCompletionRoutine(request, XenVbd_SendRequestComplete, buf);
216 WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, 0); //WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE);
217 if (!WdfRequestSend(request, xvfd->wdf_target, &send_options)) {
218 FUNCTION_MSG("Error sending request\n");
219 }
220 }
222 static VOID
223 XenVbd_EvtDpcEvent(WDFDPC dpc) {
224 WDFDEVICE device = WdfDpcGetParentObject(dpc);
226 XenVbd_SendEvent(device);
227 }
229 static VOID
230 XenVbd_HandleEventDIRQL(PVOID context) {
231 PXENVBD_DEVICE_DATA xvdd = (PXENVBD_DEVICE_DATA)context;
232 PXENVBD_FILTER_DATA xvfd = (PXENVBD_FILTER_DATA)xvdd->xvfd;
233 WdfDpcEnqueue(xvfd->dpc);
234 }
236 static NTSTATUS
237 XenVbd_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state) {
238 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
239 NTSTATUS status;
241 UNREFERENCED_PARAMETER(previous_state);
242 // if waking from hibernate then same as suspend... maybe?
243 FUNCTION_ENTER();
244 status = XenVbd_Connect(&xvfd->xvdd, FALSE);
245 FUNCTION_EXIT();
246 return status;
247 }
249 static NTSTATUS
250 XenVbd_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state) {
251 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
252 NTSTATUS status;
253 // if hibernate then same as suspend
254 UNREFERENCED_PARAMETER(target_state);
255 FUNCTION_ENTER();
256 status = XenVbd_Disconnect(&xvfd->xvdd, FALSE);
257 FUNCTION_EXIT();
258 return status;
259 }
261 static NTSTATUS
262 XenVbd_IoCompletion_START_DEVICE(PDEVICE_OBJECT device, PIRP irp, PVOID context) {
263 UNREFERENCED_PARAMETER(device);
264 UNREFERENCED_PARAMETER(irp);
265 FUNCTION_ENTER();
266 ExFreePoolWithTag(context, XENVBD_POOL_TAG);
267 FUNCTION_EXIT();
268 return STATUS_SUCCESS;
269 }
271 static NTSTATUS
272 XenVbd_EvtDeviceWdmIrpPreprocess_START_DEVICE(WDFDEVICE device, PIRP irp) {
273 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
274 PIO_STACK_LOCATION stack;
275 PCM_RESOURCE_LIST crl;
276 PCM_FULL_RESOURCE_DESCRIPTOR cfrd;
277 PCM_PARTIAL_RESOURCE_LIST cprl;
278 PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
280 FUNCTION_ENTER();
282 /*
283 Pass down the xvdd area as a memory resource. This gives xenvbd the data in a known place
284 and also satisifies the scsiport requirement for a memory resource
285 */
286 IoCopyCurrentIrpStackLocationToNext(irp);
287 stack = IoGetNextIrpStackLocation(irp);
289 crl = ExAllocatePoolWithTag(NonPagedPool,
290 FIELD_OFFSET(CM_RESOURCE_LIST, List) +
291 FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
292 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) +
293 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 1, XENVBD_POOL_TAG);
294 if (!crl) {
295 // TODO: Fail this correctly
296 }
297 crl->Count = 1;
298 cfrd = &crl->List[0];
299 cfrd->InterfaceType = PNPBus;
300 cfrd->BusNumber = 0;
301 cprl = &cfrd->PartialResourceList;
302 cprl->Version = 1;
303 cprl->Revision = 1;
304 cprl->Count = 1;
305 prd = &cprl->PartialDescriptors[0];
306 prd->Type = CmResourceTypeMemory;
307 prd->ShareDisposition = CmResourceShareShared;
308 prd->Flags = CM_RESOURCE_MEMORY_READ_WRITE | CM_RESOURCE_MEMORY_CACHEABLE;
309 prd->u.Memory.Start.QuadPart = (ULONG_PTR)&xvfd->xvdd;
310 prd->u.Memory.Length = sizeof(XENVBD_DEVICE_DATA);
311 stack->Parameters.StartDevice.AllocatedResources = crl;
312 stack->Parameters.StartDevice.AllocatedResourcesTranslated = crl;
314 IoSetCompletionRoutine(irp, XenVbd_IoCompletion_START_DEVICE, crl, TRUE, TRUE, TRUE);
316 FUNCTION_EXIT();
318 return WdfDeviceWdmDispatchPreprocessedIrp(device, irp);
319 }
321 static NTSTATUS
322 XenVbd_EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init) {
323 PXENVBD_FILTER_DATA xvfd;
324 NTSTATUS status;
325 WDFDEVICE device;
326 WDF_OBJECT_ATTRIBUTES device_attributes;
327 WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
328 WDF_DPC_CONFIG dpc_config;
329 WDF_OBJECT_ATTRIBUTES oa;
330 UCHAR pnp_minor_functions[] = { IRP_MN_START_DEVICE };
332 UNREFERENCED_PARAMETER(driver);
334 FUNCTION_ENTER();
336 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_UNKNOWN);
338 WdfFdoInitSetFilter(device_init);
340 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
341 pnp_power_callbacks.EvtDeviceD0Entry = XenVbd_EvtDeviceD0Entry;
342 pnp_power_callbacks.EvtDeviceD0Exit = XenVbd_EvtDeviceD0Exit;
343 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
345 status = WdfDeviceInitAssignWdmIrpPreprocessCallback(device_init, XenVbd_EvtDeviceWdmIrpPreprocess_START_DEVICE,
346 IRP_MJ_PNP, pnp_minor_functions, ARRAY_SIZE(pnp_minor_functions));
347 if (!NT_SUCCESS(status)) {
348 return status;
349 }
351 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&device_attributes, XENVBD_FILTER_DATA);
352 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
353 if (!NT_SUCCESS(status)) {
354 FUNCTION_MSG("Error creating device 0x%x\n", status);
355 return status;
356 }
358 xvfd = GetXvfd(device);
359 xvfd->wdf_device = device;
360 xvfd->wdf_target = WdfDeviceGetIoTarget(device);
361 xvfd->xvdd.xvfd = xvfd;
362 xvfd->xvdd.pdo = WdfDeviceWdmGetPhysicalDevice(device);
363 xvfd->xvdd.grant_tag = XENVBD_POOL_TAG;
365 KeInitializeEvent(&xvfd->xvdd.backend_event, SynchronizationEvent, FALSE);
367 WDF_DPC_CONFIG_INIT(&dpc_config, XenVbd_EvtDpcEvent);
368 WDF_OBJECT_ATTRIBUTES_INIT(&oa);
369 oa.ParentObject = device;
370 status = WdfDpcCreate(&dpc_config, &oa, &xvfd->dpc);
372 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFilePaging, TRUE);
373 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileHibernation, TRUE);
374 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileDump, TRUE);
376 FUNCTION_EXIT();
377 return status;
378 }
380 NTSTATUS
381 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
382 NTSTATUS status;
383 WDF_DRIVER_CONFIG config;
384 WDFDRIVER driver;
386 UNREFERENCED_PARAMETER(RegistryPath);
388 FUNCTION_ENTER();
390 WDF_DRIVER_CONFIG_INIT(&config, XenVbd_EvtDeviceAdd);
391 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
392 if (!NT_SUCCESS(status)) {
393 FUNCTION_MSG("WdfDriverCreate failed with status 0x%x\n", status);
394 FUNCTION_EXIT();
395 return status;
396 }
397 FUNCTION_EXIT();
398 return status;
399 }