win-pvdrivers

view xenvbd_common/common_xen.h @ 1086:3d4d85c41fc6

Added tag 1.0.1085 for changeset 896402519f15
author James Harper <james.harper@bendigoit.com.au>
date Thu Dec 12 20:06:12 2013 +1100 (2013-12-12)
parents e86ea7c3d8a4
children
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 static NTSTATUS
21 XenVbd_Connect(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend) {
22 BOOLEAN qemu_hide_filter = FALSE;
23 ULONG qemu_hide_flags_value = 0;
24 PCHAR device_type;
25 //BOOLEAN active = FALSE;
26 NTSTATUS status;
27 PCHAR mode;
28 PCHAR uuid;
29 PFN_NUMBER pfn;
31 FUNCTION_ENTER();
33 if (xvdd->device_state != DEVICE_STATE_DISCONNECTED) {
34 FUNCTION_MSG("state not DEVICE_STATE_DISCONNECTED, is %d instead\n", xvdd->device_state);
35 FUNCTION_EXIT();
36 return STATUS_SUCCESS;
37 }
38 if (!suspend) {
39 xvdd->backend_state = XenbusStateUnknown;
40 if ((xvdd->handle = XnOpenDevice(xvdd->pdo, XenVbd_DeviceCallback, xvdd)) == NULL) {
41 FUNCTION_MSG("Failed to open\n");
42 return STATUS_UNSUCCESSFUL;
43 }
44 }
45 xvdd->sring = (blkif_sring_t *)ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENVBD_POOL_TAG);
46 if (!xvdd->sring) {
47 FUNCTION_MSG("Failed to allocate sring\n");
48 return STATUS_UNSUCCESSFUL;
49 }
50 pfn = (PFN_NUMBER)(MmGetPhysicalAddress(xvdd->sring).QuadPart >> PAGE_SHIFT);
51 xvdd->sring_gref = XnGrantAccess(xvdd->handle, (ULONG)pfn, FALSE, INVALID_GRANT_REF, xvdd->grant_tag);
52 SHARED_RING_INIT(xvdd->sring);
53 FRONT_RING_INIT(&xvdd->ring, xvdd->sring, PAGE_SIZE);
55 while (xvdd->backend_state != XenbusStateInitialising &&
56 xvdd->backend_state != XenbusStateInitWait &&
57 xvdd->backend_state != XenbusStateInitialised &&
58 xvdd->backend_state != XenbusStateConnected) {
59 FUNCTION_MSG("waiting for XenbusStateInitXxx/XenbusStateConnected, backend_state = %d\n", xvdd->backend_state);
60 KeWaitForSingleObject(&xvdd->backend_event, Executive, KernelMode, FALSE, NULL);
61 }
62 XnGetValue(xvdd->handle, XN_VALUE_TYPE_QEMU_HIDE_FLAGS, &qemu_hide_flags_value);
63 XnGetValue(xvdd->handle, XN_VALUE_TYPE_QEMU_FILTER, &qemu_hide_filter);
64 status = XnReadString(xvdd->handle, XN_BASE_FRONTEND, "device-type", &device_type);
65 if (strcmp(device_type, "disk") == 0) {
66 FUNCTION_MSG("device-type = Disk\n");
67 xvdd->device_type = XENVBD_DEVICETYPE_DISK;
68 } else if (strcmp(device_type, "cdrom") == 0) {
69 FUNCTION_MSG("device-type = CDROM\n");
70 xvdd->device_type = XENVBD_DEVICETYPE_CDROM;
71 } else {
72 FUNCTION_MSG("device-type = %s (This probably won't work!)\n", device_type);
73 xvdd->device_type = XENVBD_DEVICETYPE_UNKNOWN;
74 }
75 XnFreeMem(xvdd->handle, device_type);
76 if (!(((qemu_hide_flags_value & QEMU_UNPLUG_ALL_IDE_DISKS) && xvdd->device_type != XENVBD_DEVICETYPE_CDROM) || qemu_hide_filter)) {
77 /* we never set backend state active if we are inactive */
78 FUNCTION_MSG("Inactive\n");
79 XnCloseDevice(xvdd->handle);
80 xvdd->device_state = DEVICE_STATE_INACTIVE;
81 return STATUS_SUCCESS;
82 }
83 status = XnBindEvent(xvdd->handle, &xvdd->event_channel, XenVbd_HandleEventDIRQL, xvdd);
84 status = XnWriteInt32(xvdd->handle, XN_BASE_FRONTEND, "event-channel", xvdd->event_channel);
85 status = XnWriteInt32(xvdd->handle, XN_BASE_FRONTEND, "ring-ref", xvdd->sring_gref);
86 status = XnWriteString(xvdd->handle, XN_BASE_FRONTEND, "protocol", ABI_PROTOCOL);
87 status = XnWriteInt32(xvdd->handle, XN_BASE_FRONTEND, "state", XenbusStateInitialised);
89 while (xvdd->backend_state != XenbusStateConnected) {
90 FUNCTION_MSG("waiting for XenbusStateConnected, backend_state = %d\n", xvdd->backend_state);
91 KeWaitForSingleObject(&xvdd->backend_event, Executive, KernelMode, FALSE, NULL);
92 }
94 // TODO: some of this stuff should be read on first connect only, then only verified on resume
95 xvdd->new_total_sectors = (ULONGLONG)-1L;
96 status = XnReadInt64(xvdd->handle, XN_BASE_BACKEND, "sectors", &xvdd->total_sectors);
97 status = XnReadInt32(xvdd->handle, XN_BASE_BACKEND, "sector-size", &xvdd->hw_bytes_per_sector);
98 if (xvdd->device_type == XENVBD_DEVICETYPE_CDROM) {
99 /* CD/DVD drives must have bytes_per_sector = 2048. */
100 xvdd->bytes_per_sector = 2048;
101 xvdd->hw_bytes_per_sector = 2048;
102 } else {
103 xvdd->bytes_per_sector = 512;
104 }
105 /* for some reason total_sectors is measured in 512 byte sectors always, so correct this to be in bytes_per_sectors */
106 xvdd->total_sectors /= xvdd->bytes_per_sector / 512;
107 status = XnReadInt32(xvdd->handle, XN_BASE_BACKEND, "feature-barrier", &xvdd->feature_barrier);
108 status = XnReadInt32(xvdd->handle, XN_BASE_BACKEND, "feature-discard", &xvdd->feature_discard);
109 status = XnReadInt32(xvdd->handle, XN_BASE_BACKEND, "feature-flush-cache", &xvdd->feature_flush_cache);
110 status = XnReadString(xvdd->handle, XN_BASE_BACKEND, "mode", &mode);
111 if (strncmp(mode, "r", 1) == 0) {
112 FUNCTION_MSG("mode = r\n");
113 xvdd->device_mode = XENVBD_DEVICEMODE_READ;
114 } else if (strncmp(mode, "w", 1) == 0) {
115 FUNCTION_MSG("mode = w\n");
116 xvdd->device_mode = XENVBD_DEVICEMODE_WRITE;
117 } else {
118 FUNCTION_MSG("mode = unknown\n");
119 xvdd->device_mode = XENVBD_DEVICEMODE_UNKNOWN;
120 }
121 XnFreeMem(xvdd->handle, mode);
123 // read device-type
124 status = XnReadString(xvdd->handle, XN_BASE_FRONTEND, "device-type", &device_type);
125 if (strcmp(device_type, "disk") == 0) {
126 FUNCTION_MSG("device-type = Disk\n");
127 xvdd->device_type = XENVBD_DEVICETYPE_DISK;
128 } else if (strcmp(device_type, "cdrom") == 0) {
129 FUNCTION_MSG("device-type = CDROM\n");
130 xvdd->device_type = XENVBD_DEVICETYPE_CDROM;
131 } else {
132 FUNCTION_MSG("device-type = %s (This probably won't work!)\n", device_type);
133 xvdd->device_type = XENVBD_DEVICETYPE_UNKNOWN;
134 }
136 status = XnReadString(xvdd->handle, XN_BASE_FRONTEND, "device-type", &uuid);
137 if (status == STATUS_SUCCESS) {
138 RtlStringCbCopyA(xvdd->serial_number, ARRAY_SIZE(xvdd->serial_number), uuid);
139 XnFreeMem(xvdd->handle, uuid);
140 } else {
141 RtlStringCbCopyA(xvdd->serial_number, ARRAY_SIZE(xvdd->serial_number), " ");
142 }
144 XnFreeMem(xvdd->handle, device_type);
145 status = XnWriteInt32(xvdd->handle, XN_BASE_FRONTEND, "state", XenbusStateConnected);
147 if (xvdd->device_type == XENVBD_DEVICETYPE_UNKNOWN
148 || xvdd->sring == NULL
149 || xvdd->event_channel == 0
150 || xvdd->total_sectors == 0
151 || xvdd->hw_bytes_per_sector == 0) {
152 FUNCTION_MSG("Missing settings\n");
153 // TODO: fail how?
154 }
156 xvdd->device_state = DEVICE_STATE_ACTIVE;
157 XenVbd_StartRing(xvdd, suspend);
158 FUNCTION_EXIT();
159 return STATUS_SUCCESS;
160 }
162 static NTSTATUS
163 XenVbd_Disconnect(PVOID DeviceExtension, BOOLEAN suspend) {
164 NTSTATUS status;
165 PXENVBD_DEVICE_DATA xvdd = (PXENVBD_DEVICE_DATA)DeviceExtension;
167 if (xvdd->device_state == DEVICE_STATE_INACTIVE) {
168 /* state stays INACTIVE */
169 return STATUS_SUCCESS;
170 }
172 if (xvdd->device_state != DEVICE_STATE_ACTIVE) {
173 FUNCTION_MSG("state not DEVICE_STATE_ACTIVE, is %d instead\n", xvdd->device_state);
174 FUNCTION_EXIT();
175 return STATUS_SUCCESS;
176 }
178 /* StopRing must set XenbusStateClosing when ring is paused */
179 XenVbd_StopRing(xvdd, suspend);
181 while (xvdd->backend_state != XenbusStateClosing) {
182 FUNCTION_MSG("waiting for XenbusStateClosing, backend_state = %d\n", xvdd->backend_state);
183 KeWaitForSingleObject(&xvdd->backend_event, Executive, KernelMode, FALSE, NULL);
184 }
185 status = XnWriteInt32(xvdd->handle, XN_BASE_FRONTEND, "state", XenbusStateClosed);
186 while (xvdd->backend_state != XenbusStateClosed) {
187 FUNCTION_MSG("waiting for XenbusStateClosed, backend_state = %d\n", xvdd->backend_state);
188 KeWaitForSingleObject(&xvdd->backend_event, Executive, KernelMode, FALSE, NULL);
189 }
190 XnUnbindEvent(xvdd->handle, xvdd->event_channel);
191 XnEndAccess(xvdd->handle, xvdd->sring_gref, FALSE, xvdd->grant_tag);
192 ExFreePoolWithTag(xvdd->sring, XENVBD_POOL_TAG);
194 if (!suspend) {
195 XnCloseDevice(xvdd->handle);
196 }
197 xvdd->device_state = DEVICE_STATE_DISCONNECTED;
198 return STATUS_SUCCESS;
199 }
202 static VOID
203 XenVbd_DeviceCallback(PVOID context, ULONG callback_type, PVOID value) {
204 PXENVBD_DEVICE_DATA xvdd = (PXENVBD_DEVICE_DATA)context;
205 ULONG state;
207 FUNCTION_ENTER();
209 switch (callback_type) {
210 case XN_DEVICE_CALLBACK_BACKEND_STATE:
211 state = (ULONG)(ULONG_PTR)value;
212 if (state == xvdd->backend_state) {
213 FUNCTION_MSG("same state %d\n", state);
214 /* could be rewriting same state because of size change */
215 if (xvdd->backend_state == XenbusStateConnected) {
216 /* just set the new value - it will be noticed sooner or later */
217 XnReadInt64(xvdd->handle, XN_BASE_BACKEND, "sectors", &xvdd->new_total_sectors);
218 }
219 FUNCTION_EXIT();
220 }
221 FUNCTION_MSG("XenBusState = %d -> %d\n", xvdd->backend_state, state);
222 xvdd->backend_state = state;
223 KeMemoryBarrier();
224 KeSetEvent(&xvdd->backend_event, 0, FALSE);
225 break;
226 case XN_DEVICE_CALLBACK_SUSPEND:
227 FUNCTION_MSG("XN_DEVICE_CALLBACK_SUSPEND\n");
228 XenVbd_Disconnect(xvdd, TRUE);
229 break;
230 case XN_DEVICE_CALLBACK_RESUME:
231 FUNCTION_MSG("XN_DEVICE_CALLBACK_RESUME\n");
232 XenVbd_Connect(xvdd, TRUE);
233 break;
234 }
235 FUNCTION_EXIT();
236 }