win-pvdrivers

view xenvbd_scsiport/xenvbd.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 fe3af8f4d54b
children 0f40ce5cb467
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
3 Copyright (C) 2007 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 #define INITGUID
22 #include "xenvbd.h"
24 #pragma warning(disable: 4127)
26 /* Not really necessary but keeps PREfast happy */
27 DRIVER_INITIALIZE DriverEntry;
28 static IO_WORKITEM_ROUTINE XenVbd_DisconnectWorkItem;
30 static VOID XenVbd_ProcessSrbList(PXENVBD_DEVICE_DATA xvdd);
31 static BOOLEAN XenVbd_ResetBus(PXENVBD_DEVICE_DATA xvdd, ULONG PathId);
32 static VOID XenVbd_CompleteDisconnect(PXENVBD_DEVICE_DATA xvdd);
34 static BOOLEAN dump_mode = FALSE;
35 #define DUMP_MODE_ERROR_LIMIT 64
36 static ULONG dump_mode_errors = 0;
38 #define StorPortAcquireSpinLock(...) {}
39 #define StorPortReleaseSpinLock(...) {}
41 static ULONG
42 SxxxPortGetSystemAddress(PVOID device_extension, PSCSI_REQUEST_BLOCK srb, PVOID *system_address) {
43 UNREFERENCED_PARAMETER(device_extension);
44 *system_address = (PUCHAR)srb->DataBuffer;
45 return STATUS_SUCCESS;
46 }
48 static PHYSICAL_ADDRESS
49 SxxxPortGetPhysicalAddress(PVOID device_extension, PSCSI_REQUEST_BLOCK srb, PVOID virtual_address, ULONG *length) {
50 UNREFERENCED_PARAMETER(device_extension);
51 UNREFERENCED_PARAMETER(srb);
52 UNREFERENCED_PARAMETER(length);
53 return MmGetPhysicalAddress(virtual_address);
54 }
56 #define SxxxPortNotification(NotificationType, DeviceExtension, ...) XenVbd_Notification##NotificationType(DeviceExtension, __VA_ARGS__)
58 static VOID
59 XenVbd_NotificationRequestComplete(PXENVBD_DEVICE_DATA xvdd, PSCSI_REQUEST_BLOCK srb) {
60 PXENVBD_SCSIPORT_DATA xvsd = (PXENVBD_SCSIPORT_DATA)xvdd->xvsd;
61 srb_list_entry_t *srb_entry = srb->SrbExtension;
62 if (srb_entry->outstanding_requests != 0) {
63 FUNCTION_MSG("srb outstanding_requests = %d\n", srb_entry->outstanding_requests);
64 }
65 xvsd->outstanding--;
66 ScsiPortNotification(RequestComplete, xvsd, srb);
67 }
69 VOID
70 XenVbd_NotificationNextLuRequest(PXENVBD_DEVICE_DATA xvdd, UCHAR PathId, UCHAR TargetId, UCHAR Lun) {
71 ScsiPortNotification(NextLuRequest, xvdd->xvsd, PathId, TargetId, Lun);
72 }
74 #include "..\xenvbd_common\common_miniport.h"
77 /* called in non-dump mode */
78 static ULONG
79 XenVbd_HwScsiFindAdapter(PVOID DeviceExtension, PVOID HwContext, PVOID BusInformation, PCHAR ArgumentString, PPORT_CONFIGURATION_INFORMATION ConfigInfo, PBOOLEAN Again) {
80 //NTSTATUS status;
81 PXENVBD_SCSIPORT_DATA xvsd = (PXENVBD_SCSIPORT_DATA)DeviceExtension;
82 PXENVBD_DEVICE_DATA xvdd;
83 PACCESS_RANGE access_range;
85 UNREFERENCED_PARAMETER(HwContext);
86 UNREFERENCED_PARAMETER(BusInformation);
87 UNREFERENCED_PARAMETER(ArgumentString);
89 FUNCTION_ENTER();
90 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
91 KdPrint((__DRIVER_NAME " xvsd = %p\n", xvsd));
93 if (dump_mode) {
94 if (xvsd->xvdd->device_state != DEVICE_STATE_ACTIVE) {
95 /* if we are not connected to the ring when we start dump mode then there is nothing we can do */
96 FUNCTION_MSG("Cannot connect backend in dump mode - state = %d\n", xvsd->xvdd->device_state);
97 return SP_RETURN_ERROR;
98 }
99 }
100 if (ConfigInfo->NumberOfAccessRanges != 1) {
101 FUNCTION_MSG("NumberOfAccessRanges wrong\n");
102 FUNCTION_EXIT();
103 return SP_RETURN_BAD_CONFIG;
104 }
105 if (XnGetVersion() != 1) {
106 FUNCTION_MSG("Wrong XnGetVersion\n");
107 FUNCTION_EXIT();
108 return SP_RETURN_BAD_CONFIG;
109 }
110 RtlZeroMemory(xvsd, sizeof(XENVBD_SCSIPORT_DATA));
112 access_range = &((*(ConfigInfo->AccessRanges))[0]);
113 xvdd = (PXENVBD_DEVICE_DATA)(ULONG_PTR)access_range->RangeStart.QuadPart;
114 xvsd->xvdd = xvdd;
115 xvdd->xvsd = xvsd;
117 InitializeListHead(&xvdd->srb_list);
118 xvdd->aligned_buffer_in_use = FALSE;
119 /* align the buffer to PAGE_SIZE */
120 xvdd->aligned_buffer = (PVOID)((ULONG_PTR)((PUCHAR)xvsd->aligned_buffer_data + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1));
121 KdPrint((__DRIVER_NAME " aligned_buffer_data = %p\n", xvsd->aligned_buffer_data));
122 KdPrint((__DRIVER_NAME " aligned_buffer = %p\n", xvdd->aligned_buffer));
124 ConfigInfo->MaximumTransferLength = 4 * 1024 * 1024; //BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE;
125 ConfigInfo->NumberOfPhysicalBreaks = ConfigInfo->MaximumTransferLength >> PAGE_SHIFT; //BLKIF_MAX_SEGMENTS_PER_REQUEST - 1;
126 FUNCTION_MSG("ConfigInfo->MaximumTransferLength = %d\n", ConfigInfo->MaximumTransferLength);
127 FUNCTION_MSG("ConfigInfo->NumberOfPhysicalBreaks = %d\n", ConfigInfo->NumberOfPhysicalBreaks);
128 if (!dump_mode) {
129 xvdd->aligned_buffer_size = BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE;
130 } else {
131 xvdd->aligned_buffer_size = DUMP_MODE_UNALIGNED_PAGES * PAGE_SIZE;
132 }
133 //status = XenVbd_Connect(DeviceExtension, FALSE);
135 FUNCTION_MSG("MultipleRequestPerLu = %d\n", ConfigInfo->MultipleRequestPerLu);
136 FUNCTION_MSG("TaggedQueuing = %d\n", ConfigInfo->TaggedQueuing);
137 FUNCTION_MSG("AutoRequestSense = %d\n", ConfigInfo->AutoRequestSense );
138 ConfigInfo->ScatterGather = TRUE;
139 ConfigInfo->Master = TRUE;
140 ConfigInfo->CachesData = FALSE;
141 ConfigInfo->MapBuffers = TRUE;
142 ConfigInfo->AlignmentMask = 0;
143 ConfigInfo->NumberOfBuses = 1;
144 ConfigInfo->InitiatorBusId[0] = 1;
145 ConfigInfo->MaximumNumberOfLogicalUnits = 1;
146 ConfigInfo->MaximumNumberOfTargets = 2;
147 if (ConfigInfo->Dma64BitAddresses == SCSI_DMA64_SYSTEM_SUPPORTED) {
148 ConfigInfo->Dma64BitAddresses = SCSI_DMA64_MINIPORT_SUPPORTED;
149 FUNCTION_MSG("Dma64BitAddresses supported\n");
150 } else {
151 FUNCTION_MSG("Dma64BitAddresses not supported\n");
152 }
153 *Again = FALSE;
155 FUNCTION_EXIT();
157 return SP_RETURN_FOUND;
158 }
160 /* Called at PASSIVE_LEVEL for non-dump mode */
161 static BOOLEAN
162 XenVbd_HwScsiInitialize(PVOID DeviceExtension) {
163 PXENVBD_SCSIPORT_DATA xvsd = (PXENVBD_SCSIPORT_DATA)DeviceExtension;
164 PXENVBD_DEVICE_DATA xvdd = (PXENVBD_DEVICE_DATA)xvsd->xvdd;
165 ULONG i;
167 FUNCTION_ENTER();
168 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
169 KdPrint((__DRIVER_NAME " dump_mode = %d\n", dump_mode));
171 xvdd->shadow_free = 0;
172 memset(xvdd->shadows, 0, sizeof(blkif_shadow_t) * SHADOW_ENTRIES);
173 for (i = 0; i < SHADOW_ENTRIES; i++) {
174 xvdd->shadows[i].req.id = i;
175 /* make sure leftover real requests's are never confused with dump mode requests */
176 if (dump_mode)
177 xvdd->shadows[i].req.id |= SHADOW_ID_DUMP_FLAG;
178 put_shadow_on_freelist(xvdd, &xvdd->shadows[i]);
179 }
181 if (!dump_mode) {
182 /* nothing */
183 } else {
184 xvdd->grant_tag = (ULONG)'DUMP';
185 }
187 FUNCTION_EXIT();
189 return TRUE;
190 }
192 /* this is only used during hiber and dump */
193 static BOOLEAN
194 XenVbd_HwScsiInterrupt(PVOID DeviceExtension)
195 {
196 PXENVBD_SCSIPORT_DATA xvsd = DeviceExtension;
197 XenVbd_HandleEvent(xvsd->xvdd);
198 //SxxxPortNotification(NextLuRequest, xvdd, 0, 0, 0);
199 return TRUE;
200 }
202 static BOOLEAN
203 XenVbd_HwScsiResetBus(PVOID DeviceExtension, ULONG PathId)
204 {
205 PXENVBD_SCSIPORT_DATA xvsd = DeviceExtension;
206 return XenVbd_ResetBus(xvsd->xvdd, PathId);
207 }
209 static VOID
210 XenVbd_CompleteDisconnect(PXENVBD_DEVICE_DATA xvdd) {
211 PXENVBD_SCSIPORT_DATA xvsd = (PXENVBD_SCSIPORT_DATA)xvdd->xvsd;
212 PSCSI_REQUEST_BLOCK srb;
214 if (xvsd->stop_srb) {
215 srb = xvsd->stop_srb;
216 xvsd->stop_srb = NULL;
217 ScsiPortNotification(RequestComplete, xvsd, srb);
218 }
219 }
221 static BOOLEAN
222 XenVbd_HwScsiStartIo(PVOID DeviceExtension, PSCSI_REQUEST_BLOCK srb) {
223 PXENVBD_SCSIPORT_DATA xvsd = DeviceExtension;
224 PXENVBD_DEVICE_DATA xvdd = (PXENVBD_DEVICE_DATA)xvsd->xvdd;
225 PSRB_IO_CONTROL sic;
227 if ((LONG)xvsd->outstanding < 0) {
228 FUNCTION_MSG("HwScsiStartIo outstanding = %d\n", xvsd->outstanding);
229 }
230 if (srb->PathId != 0 || srb->TargetId != 0 || srb->Lun != 0) {
231 FUNCTION_MSG("HwScsiStartIo (Out of bounds - PathId = %d, TargetId = %d, Lun = %d)\n", srb->PathId, srb->TargetId, srb->Lun);
232 srb->SrbStatus = SRB_STATUS_NO_DEVICE;
233 ScsiPortNotification(RequestComplete, xvsd, srb);
234 } else if (srb->Function == SRB_FUNCTION_IO_CONTROL && memcmp(((PSRB_IO_CONTROL)srb->DataBuffer)->Signature, XENVBD_CONTROL_SIG, 8) == 0) {
235 sic = srb->DataBuffer;
236 switch(sic->ControlCode) {
237 case XENVBD_CONTROL_EVENT:
238 srb->SrbStatus = SRB_STATUS_SUCCESS;
239 ScsiPortNotification(RequestComplete, xvsd, srb);
240 break;
241 case XENVBD_CONTROL_STOP:
242 if (xvdd->shadow_free == SHADOW_ENTRIES) {
243 srb->SrbStatus = SRB_STATUS_SUCCESS;
244 ScsiPortNotification(RequestComplete, xvsd, srb);
245 FUNCTION_MSG("CONTROL_STOP done\n");
246 } else {
247 xvsd->stop_srb = srb;
248 FUNCTION_MSG("CONTROL_STOP pended\n");
249 }
250 break;
251 case XENVBD_CONTROL_START:
252 // we might need to reload a few things here...
253 ScsiPortNotification(RequestComplete, xvsd, srb);
254 break;
255 default:
256 FUNCTION_MSG("XENVBD_CONTROL_%d\n", sic->ControlCode);
257 srb->SrbStatus = SRB_STATUS_ERROR;
258 ScsiPortNotification(RequestComplete, xvsd, srb);
259 break;
260 }
261 } else if (xvdd->device_state == DEVICE_STATE_INACTIVE) {
262 FUNCTION_MSG("HwScsiStartIo Inactive Device (in StartIo)\n");
263 srb->SrbStatus = SRB_STATUS_NO_DEVICE;
264 ScsiPortNotification(RequestComplete, xvsd, srb);
265 } else {
266 xvsd->outstanding++;
267 XenVbd_PutSrbOnList(xvdd, srb);
268 }
269 /* HandleEvent also puts queued SRB's on the ring */
270 XenVbd_HandleEvent(xvdd);
271 /* need 2 spare slots - 1 for EVENT and 1 for STOP/START */
272 if (xvsd->outstanding < 30) {
273 ScsiPortNotification(NextLuRequest, xvsd, 0, 0, 0);
274 } else {
275 ScsiPortNotification(NextRequest, xvsd);
276 }
277 return TRUE;
278 }
280 static SCSI_ADAPTER_CONTROL_STATUS
281 XenVbd_HwScsiAdapterControl(PVOID DeviceExtension, SCSI_ADAPTER_CONTROL_TYPE ControlType, PVOID Parameters)
282 {
283 PXENVBD_SCSIPORT_DATA xvsd = DeviceExtension;
284 PXENVBD_DEVICE_DATA xvdd = (PXENVBD_DEVICE_DATA)xvsd->xvdd;
285 SCSI_ADAPTER_CONTROL_STATUS Status = ScsiAdapterControlSuccess;
286 PSCSI_SUPPORTED_CONTROL_TYPE_LIST SupportedControlTypeList;
288 FUNCTION_ENTER();
289 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
290 KdPrint((__DRIVER_NAME " xvsd = %p\n", xvsd));
292 switch (ControlType)
293 {
294 case ScsiQuerySupportedControlTypes:
295 SupportedControlTypeList = (PSCSI_SUPPORTED_CONTROL_TYPE_LIST)Parameters;
296 KdPrint((__DRIVER_NAME " ScsiQuerySupportedControlTypes (Max = %d)\n", SupportedControlTypeList->MaxControlType));
297 SupportedControlTypeList->SupportedTypeList[ScsiQuerySupportedControlTypes] = TRUE;
298 SupportedControlTypeList->SupportedTypeList[ScsiStopAdapter] = TRUE;
299 SupportedControlTypeList->SupportedTypeList[ScsiRestartAdapter] = TRUE;
300 break;
301 case ScsiStopAdapter:
302 KdPrint((__DRIVER_NAME " ScsiStopAdapter\n"));
303 if (xvdd->device_state == DEVICE_STATE_INACTIVE) {
304 KdPrint((__DRIVER_NAME " inactive - nothing to do\n"));
305 break;
306 }
307 NT_ASSERT(IsListEmpty(&xvdd->srb_list));
308 NT_ASSERT(xvdd->shadow_free == SHADOW_ENTRIES);
309 break;
310 case ScsiRestartAdapter:
311 KdPrint((__DRIVER_NAME " ScsiRestartAdapter\n"));
312 if (xvdd->device_state == DEVICE_STATE_INACTIVE) {
313 KdPrint((__DRIVER_NAME " inactive - nothing to do\n"));
314 break;
315 }
316 /* increase the tag every time we stop/start to track where the gref's came from */
317 xvdd->grant_tag++;
318 break;
319 case ScsiSetBootConfig:
320 KdPrint((__DRIVER_NAME " ScsiSetBootConfig\n"));
321 break;
322 case ScsiSetRunningConfig:
323 KdPrint((__DRIVER_NAME " ScsiSetRunningConfig\n"));
324 break;
325 default:
326 KdPrint((__DRIVER_NAME " UNKNOWN\n"));
327 break;
328 }
330 FUNCTION_EXIT();
332 return Status;
333 }
335 NTSTATUS
336 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
337 ULONG status;
338 HW_INITIALIZATION_DATA HwInitializationData;
340 /* RegistryPath == NULL when we are invoked as a crash dump driver */
341 if (!RegistryPath) {
342 KdPrint((__DRIVER_NAME " IRQL = %d (if you can read this we aren't in dump mode)\n", KeGetCurrentIrql()));
343 dump_mode = TRUE;
344 }
346 FUNCTION_ENTER();
347 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
348 KdPrint((__DRIVER_NAME " DriverObject = %p, RegistryPath = %p\n", DriverObject, RegistryPath));
350 RtlZeroMemory(&HwInitializationData, sizeof(HW_INITIALIZATION_DATA));
351 HwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
352 HwInitializationData.AdapterInterfaceType = PNPBus; /* not Internal */
353 HwInitializationData.SrbExtensionSize = sizeof(srb_list_entry_t);
354 HwInitializationData.NumberOfAccessRanges = 1;
355 HwInitializationData.MapBuffers = TRUE;
356 HwInitializationData.NeedPhysicalAddresses = FALSE;
357 HwInitializationData.TaggedQueuing = TRUE;
358 HwInitializationData.AutoRequestSense = TRUE;
359 HwInitializationData.MultipleRequestPerLu = TRUE;
360 HwInitializationData.ReceiveEvent = FALSE;
361 HwInitializationData.HwInitialize = XenVbd_HwScsiInitialize;
362 HwInitializationData.HwStartIo = XenVbd_HwScsiStartIo;
363 HwInitializationData.HwFindAdapter = XenVbd_HwScsiFindAdapter;
364 HwInitializationData.HwResetBus = XenVbd_HwScsiResetBus;
365 HwInitializationData.HwAdapterControl = XenVbd_HwScsiAdapterControl;
366 if (!dump_mode) {
367 HwInitializationData.DeviceExtensionSize = FIELD_OFFSET(XENVBD_SCSIPORT_DATA, aligned_buffer_data) + UNALIGNED_BUFFER_DATA_SIZE;
368 } else {
369 HwInitializationData.HwInterrupt = XenVbd_HwScsiInterrupt;
370 HwInitializationData.DeviceExtensionSize = FIELD_OFFSET(XENVBD_SCSIPORT_DATA, aligned_buffer_data) + UNALIGNED_BUFFER_DATA_SIZE_DUMP_MODE;
371 }
372 status = ScsiPortInitialize(DriverObject, RegistryPath, &HwInitializationData, NULL);
374 if(!NT_SUCCESS(status)) {
375 FUNCTION_MSG("ScsiPortInitialize failed with status 0x%08x\n", status);
376 }
378 FUNCTION_EXIT();
380 return status;
381 }