win-pvdrivers

view xenpci/xenbus.c @ 283:3c65d6c6453f

Fixed a sense problem with xenscsi. scsi passthrough now working properly.
author James Harper <james.harper@bendigoit.com.au>
date Tue May 27 22:46:06 2008 +1000 (2008-05-27)
parents 685399b9adb0
children a5d5a0376f96
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 #include "xenpci.h"
21 #include "io/xs_wire.h"
22 #include <stdlib.h>
24 #pragma warning( disable : 4204 )
25 #pragma warning( disable : 4221 )
27 struct write_req {
28 const void *data;
29 unsigned len;
30 };
32 static void
33 XenBus_ReadThreadProc(PVOID StartContext);
34 static void
35 XenBus_WatchThreadProc(PVOID StartContext);
36 static BOOLEAN
37 XenBus_Interrupt(PKINTERRUPT Interrupt, PVOID ServiceContext);
39 static int allocate_xenbus_id(PXENPCI_DEVICE_DATA xpdd)
40 {
41 static int probe;
42 int o_probe;
44 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
46 for (;;)
47 {
48 // spin_lock(&req_lock);
49 if (xpdd->nr_live_reqs < NR_XB_REQS)
50 break;
51 // spin_unlock(&req_lock);
52 // wait_event(req_wq, (nr_live_reqs < NR_REQS));
53 }
55 o_probe = probe;
57 for (;;)
58 {
59 if (!xpdd->req_info[o_probe].In_Use)
60 break;
61 o_probe = (o_probe + 1) % NR_XB_REQS;
62 // BUG_ON(o_probe == probe);
63 }
64 xpdd->nr_live_reqs++;
65 xpdd->req_info[o_probe].In_Use = 1;
66 probe = (o_probe + 1) % NR_XB_REQS;
67 //spin_unlock(&req_lock);
68 //init_waitqueue_head(&req_info[o_probe].waitq);
69 KeInitializeEvent(&xpdd->req_info[o_probe].WaitEvent, SynchronizationEvent, FALSE);
71 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
73 return o_probe;
74 }
76 static void release_xenbus_id(PXENPCI_DEVICE_DATA xpdd, int id)
77 {
78 // BUG_ON(!req_info[id].in_use);
79 // spin_lock(&req_lock);
80 xpdd->req_info[id].In_Use = 0;
81 xpdd->nr_live_reqs--;
82 xpdd->req_info[id].In_Use = 0;
83 // if (nr_live_reqs == NR_REQS - 1)
84 // wake_up(&req_wq);
85 // spin_unlock(&req_lock);
86 }
88 // This routine free's the rep structure if there was an error!!!
89 static char *errmsg(struct xsd_sockmsg *rep)
90 {
91 char *res;
93 if (!rep) {
94 char msg[] = "No reply";
95 size_t len = strlen(msg) + 1;
96 return memcpy(ExAllocatePoolWithTag(NonPagedPool, len, XENPCI_POOL_TAG), msg, len);
97 }
98 if (rep->type != XS_ERROR)
99 return NULL;
100 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
101 memcpy(res, rep + 1, rep->len);
102 res[rep->len] = 0;
103 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
104 return res;
105 }
107 static void memcpy_from_ring(const void *Ring,
108 void *Dest,
109 int off,
110 int len)
111 {
112 int c1, c2;
113 const char *ring = Ring;
114 char *dest = Dest;
115 c1 = min(len, XENSTORE_RING_SIZE - off);
116 c2 = len - c1;
117 memcpy(dest, ring + off, c1);
118 memcpy(dest + c1, ring, c2);
119 }
121 static void xb_write(
122 PXENPCI_DEVICE_DATA xpdd,
123 int type,
124 int req_id,
125 xenbus_transaction_t trans_id,
126 const struct write_req *req,
127 int nr_reqs)
128 {
129 XENSTORE_RING_IDX prod;
130 int r;
131 size_t len = 0;
132 const struct write_req *cur_req;
133 size_t req_off;
134 size_t total_off;
135 size_t this_chunk;
136 struct xsd_sockmsg m = {type, req_id, trans_id };
137 struct write_req header_req = { &m, sizeof(m) };
139 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
141 for (r = 0; r < nr_reqs; r++)
142 len += (size_t)req[r].len;
143 m.len = (ULONG)len;
144 len += sizeof(m);
146 cur_req = &header_req;
148 // BUG_ON(len > XENSTORE_RING_SIZE);
149 /* Wait for the ring to drain to the point where we can send the
150 message. */
151 prod = xpdd->xen_store_interface->req_prod;
153 //KdPrint((__DRIVER_NAME " prod = %08x\n", prod));
155 if (prod + len - xpdd->xen_store_interface->req_cons > XENSTORE_RING_SIZE)
156 {
157 /* Wait for there to be space on the ring */
158 //KdPrint((__DRIVER_NAME " prod %d, len %d, cons %d, size %d; waiting.\n", prod, len, xen_store_interface->req_cons, XENSTORE_RING_SIZE));
159 // wait_event(xb_waitq, xen_store_interface->req_prod + len - xen_store_interface->req_cons <= XENSTORE_RING_SIZE);
160 //KdPrint((__DRIVER_NAME " Back from wait.\n"));
161 prod = xpdd->xen_store_interface->req_prod;
162 }
164 /* We're now guaranteed to be able to send the message without
165 overflowing the ring. Do so. */
167 total_off = 0;
168 req_off = 0;
170 while (total_off < len)
171 {
172 this_chunk = min(cur_req->len - req_off,XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
173 memcpy((char *)xpdd->xen_store_interface->req + MASK_XENSTORE_IDX(prod), (char *)cur_req->data + req_off, this_chunk);
174 prod += (XENSTORE_RING_IDX)this_chunk;
175 req_off += this_chunk;
176 total_off += this_chunk;
177 if (req_off == cur_req->len)
178 {
179 req_off = 0;
180 if (cur_req == &header_req)
181 cur_req = req;
182 else
183 cur_req++;
184 }
185 }
187 //KdPrint((__DRIVER_NAME " Complete main loop of xb_write.\n"));
189 // BUG_ON(req_off != 0);
190 // BUG_ON(total_off != len);
191 // BUG_ON(prod > xen_store_interface->req_cons + XENSTORE_RING_SIZE);
193 /* Remote must see entire message before updating indexes */
194 //_WriteBarrier();
195 KeMemoryBarrier();
197 xpdd->xen_store_interface->req_prod += (XENSTORE_RING_IDX)len;
199 //KdPrint((__DRIVER_NAME " prod = %08x\n", xen_store_interface->req_prod));
201 /* Send evtchn to notify remote */
202 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn);
204 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
205 }
207 static struct xsd_sockmsg *
208 xenbus_msg_reply(
209 PXENPCI_DEVICE_DATA xpdd,
210 int type,
211 xenbus_transaction_t trans,
212 struct write_req *io,
213 int nr_reqs)
214 {
215 int id;
217 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
219 id = allocate_xenbus_id(xpdd);
221 xb_write(xpdd, type, id, trans, io, nr_reqs);
223 KeWaitForSingleObject(&xpdd->req_info[id].WaitEvent, Executive, KernelMode, FALSE, NULL);
225 release_xenbus_id(xpdd, id);
227 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
229 return xpdd->req_info[id].Reply;
230 }
232 char *
233 XenBus_Read(
234 PVOID Context,
235 xenbus_transaction_t xbt,
236 const char *path,
237 char **value)
238 {
239 PXENPCI_DEVICE_DATA xpdd = Context;
240 struct write_req req[] = { {path, (ULONG)strlen(path) + 1} };
241 struct xsd_sockmsg *rep;
242 char *res;
243 char *msg;
245 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
247 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
249 rep = xenbus_msg_reply(xpdd, XS_READ, xbt, req, ARRAY_SIZE(req));
250 msg = errmsg(rep);
251 if (msg) {
252 *value = NULL;
253 return msg;
254 }
255 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
256 memcpy(res, rep + 1, rep->len);
257 res[rep->len] = 0;
258 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
259 *value = res;
261 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
263 return NULL;
264 }
266 char *
267 XenBus_Write(
268 PVOID Context,
269 xenbus_transaction_t xbt,
270 const char *path,
271 const char *value)
272 {
273 PXENPCI_DEVICE_DATA xpdd = Context;
274 struct write_req req[] = {
275 {path, (ULONG)strlen(path) + 1},
276 {value, (ULONG)strlen(value) + 1},
277 // {path, (ULONG)strlen(path)},
278 // {value, (ULONG)strlen(value)},
279 };
280 struct xsd_sockmsg *rep;
281 char *msg;
283 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
285 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
287 rep = xenbus_msg_reply(xpdd, XS_WRITE, xbt, req, ARRAY_SIZE(req));
288 msg = errmsg(rep);
289 if (msg)
290 return msg;
291 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
293 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
295 return NULL;
296 }
298 NTSTATUS
299 XenBus_Init(PXENPCI_DEVICE_DATA xpdd)
300 {
301 PHYSICAL_ADDRESS pa_xen_store_interface;
302 xen_ulong_t xen_store_mfn;
303 NTSTATUS Status;
304 int i;
306 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
308 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
310 KeInitializeSpinLock(&xpdd->WatchLock);
312 xpdd->xen_store_evtchn = (evtchn_port_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_EVTCHN);
314 xen_store_mfn = (xen_ulong_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_PFN);
315 pa_xen_store_interface.QuadPart = xen_store_mfn << PAGE_SHIFT;
316 xpdd->xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmNonCached);
318 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
319 {
320 xpdd->XenBus_WatchEntries[i].Active = 0;
321 xpdd->XenBus_WatchEntries[i].Running = 0;
322 KeInitializeEvent(&xpdd->XenBus_WatchEntries[i].CompleteEvent, SynchronizationEvent, FALSE);
323 }
325 KeInitializeEvent(&xpdd->XenBus_ReadThreadEvent, SynchronizationEvent, FALSE);
326 KeInitializeEvent(&xpdd->XenBus_WatchThreadEvent, SynchronizationEvent, FALSE);
327 xpdd->XenBus_ShuttingDown = FALSE;
329 Status = PsCreateSystemThread(&xpdd->XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_ReadThreadProc, xpdd);
330 if (!NT_SUCCESS(Status))
331 {
332 KdPrint((__DRIVER_NAME " Could not start read thread\n"));
333 return STATUS_UNSUCCESSFUL;
334 }
336 Status = PsCreateSystemThread(&xpdd->XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_WatchThreadProc, xpdd);
337 if (!NT_SUCCESS(Status))
338 {
339 KdPrint((__DRIVER_NAME " Could not start watch thread\n"));
340 return STATUS_UNSUCCESSFUL;
341 }
343 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Interrupt, xpdd);
345 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
347 return STATUS_SUCCESS;
348 }
350 NTSTATUS
351 XenBus_Stop(PXENPCI_DEVICE_DATA xpdd)
352 {
353 int i;
355 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
357 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
358 {
359 if (xpdd->XenBus_WatchEntries[i].Active)
360 XenBus_RemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path,
361 xpdd->XenBus_WatchEntries[i].ServiceRoutine,
362 xpdd->XenBus_WatchEntries[i].ServiceContext);
363 }
365 EvtChn_Unbind(xpdd, xpdd->xen_store_evtchn);
367 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
369 return STATUS_SUCCESS;
370 }
372 NTSTATUS
373 XenBus_Close(PXENPCI_DEVICE_DATA xpdd)
374 {
375 //KWAIT_BLOCK WaitBlockArray[2];
376 PVOID WaitArray[2];
378 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
380 xpdd->XenBus_ShuttingDown = TRUE;
382 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, 1, FALSE);
383 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, 1, FALSE);
384 ObReferenceObjectByHandle(xpdd->XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &WaitArray[0], NULL);
385 ObReferenceObjectByHandle(xpdd->XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &WaitArray[1], NULL);
386 KeWaitForSingleObject(WaitArray[0], Executive, KernelMode, FALSE, NULL);
387 KeWaitForSingleObject(WaitArray[1], Executive, KernelMode, FALSE, NULL);
388 xpdd->XenBus_ShuttingDown = FALSE;
390 ZwClose(xpdd->XenBus_WatchThreadHandle);
391 ZwClose(xpdd->XenBus_ReadThreadHandle);
393 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
395 return STATUS_SUCCESS;
396 }
398 char *
399 XenBus_List(
400 PVOID Context,
401 xenbus_transaction_t xbt,
402 const char *pre,
403 char ***contents)
404 {
405 PXENPCI_DEVICE_DATA xpdd = Context;
406 struct xsd_sockmsg *reply, *repmsg;
407 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
408 ULONG nr_elems, x, i;
409 char **res;
410 char *msg;
412 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
414 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
416 repmsg = xenbus_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
417 msg = errmsg(repmsg);
418 if (msg)
419 {
420 *contents = NULL;
421 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
422 return msg;
423 }
424 reply = repmsg + 1;
425 for (x = nr_elems = 0; x < repmsg->len; x++)
426 {
427 nr_elems += (((char *)reply)[x] == 0);
428 }
429 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
430 XENPCI_POOL_TAG);
431 for (x = i = 0; i < nr_elems; i++)
432 {
433 int l = (int)strlen((char *)reply + x);
434 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
435 memcpy(res[i], (char *)reply + x, l + 1);
436 x += l + 1;
437 }
438 res[i] = NULL;
439 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
440 *contents = res;
441 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
442 return NULL;
443 }
445 static void
446 XenBus_ReadThreadProc(PVOID StartContext)
447 {
448 int NewWriteIndex;
449 struct xsd_sockmsg msg;
450 char *payload;
451 char *path, *token;
452 PXENPCI_DEVICE_DATA xpdd = StartContext;
454 for(;;)
455 {
456 KeWaitForSingleObject(&xpdd->XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
457 if (xpdd->XenBus_ShuttingDown)
458 {
459 KdPrint((__DRIVER_NAME " Shutdown detected in ReadThreadProc\n"));
460 PsTerminateSystemThread(0);
461 }
462 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
463 {
464 //KdPrint((__DRIVER_NAME " a - Rsp_cons %d, rsp_prod %d.\n", xen_store_interface->rsp_cons, xen_store_interface->rsp_prod));
465 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg))
466 {
467 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
468 break;
469 }
470 //_ReadBarrier();
471 KeMemoryBarrier();
472 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
473 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(msg));
474 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg) + msg.len)
475 {
476 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
477 break;
478 }
480 if (msg.type != XS_WATCH_EVENT)
481 {
482 xpdd->req_info[msg.req_id].Reply = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
483 memcpy_from_ring(xpdd->xen_store_interface->rsp,
484 xpdd->req_info[msg.req_id].Reply,
485 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
486 msg.len + sizeof(msg));
487 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
488 KeSetEvent(&xpdd->req_info[msg.req_id].WaitEvent, 1, FALSE);
489 }
490 else // a watch: add to watch ring and signal watch thread
491 {
492 payload = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
493 memcpy_from_ring(xpdd->xen_store_interface->rsp, payload,
494 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), msg.len + sizeof(msg));
495 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
496 path = payload + sizeof(msg);
497 token = path + strlen(path) + 1;
499 NewWriteIndex = (xpdd->XenBus_WatchRingWriteIndex + 1) & 127;
500 if (NewWriteIndex != xpdd->XenBus_WatchRingReadIndex)
501 {
502 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Path, path, 128);
503 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Token, token, 10);
504 xpdd->XenBus_WatchRingWriteIndex = NewWriteIndex;
505 }
506 else
507 {
508 KdPrint((__DRIVER_NAME " +++ Queue full Path = %s Token = %s\n", path, token));
509 // drop the message on the floor
510 continue;
511 }
513 ExFreePoolWithTag(payload, XENPCI_POOL_TAG);
514 //KdPrint((__DRIVER_NAME " +++ Watch Path = %s Token = %s\n", path, token));
515 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, 1, FALSE);
516 }
517 }
518 }
519 }
521 static void
522 XenBus_WatchThreadProc(PVOID StartContext)
523 {
524 int index;
525 PXENBUS_WATCH_ENTRY entry;
526 PXENPCI_DEVICE_DATA xpdd = StartContext;
527 KIRQL OldIrql;
529 for(;;)
530 {
531 KeWaitForSingleObject(&xpdd->XenBus_WatchThreadEvent, Executive, KernelMode, FALSE, NULL);
532 if (xpdd->XenBus_ShuttingDown)
533 {
534 KdPrint((__DRIVER_NAME " Shutdown detected in WatchThreadProc\n"));
535 PsTerminateSystemThread(0);
536 }
537 while (xpdd->XenBus_WatchRingReadIndex != xpdd->XenBus_WatchRingWriteIndex)
538 {
539 xpdd->XenBus_WatchRingReadIndex =
540 (xpdd->XenBus_WatchRingReadIndex + 1) % WATCH_RING_SIZE;
541 index = atoi(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Token);
543 entry = &xpdd->XenBus_WatchEntries[index];
544 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
545 if (!entry->Active || !entry->ServiceRoutine)
546 {
547 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
548 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
549 continue;
550 }
551 if (entry->RemovePending)
552 {
553 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
554 KdPrint((__DRIVER_NAME " Not calling watch - remove is pending\n"));
555 continue;
556 }
557 entry->Running = 1;
558 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
559 entry->Count++;
560 entry->ServiceRoutine(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path, entry->ServiceContext);
561 entry->Running = 0;
562 KeSetEvent(&entry->CompleteEvent, 1, FALSE);
563 }
564 }
565 }
567 static char *
568 XenBus_SendAddWatch(
569 PVOID Context,
570 xenbus_transaction_t xbt,
571 const char *Path,
572 int slot)
573 {
574 PXENPCI_DEVICE_DATA xpdd = Context;
575 struct xsd_sockmsg *rep;
576 char *msg;
577 char Token[20];
578 struct write_req req[2];
580 req[0].data = Path;
581 req[0].len = (ULONG)strlen(Path) + 1;
583 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot);
584 req[1].data = Token;
585 req[1].len = (ULONG)strlen(Token) + 1;
587 rep = xenbus_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
588 msg = errmsg(rep);
589 if (!msg)
590 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
592 return msg;
593 }
595 VOID
596 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd)
597 {
598 int i;
600 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
601 if (xpdd->XenBus_WatchEntries[i].Active)
602 XenBus_SendAddWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
603 }
605 char *
606 XenBus_AddWatch(
607 PVOID Context,
608 xenbus_transaction_t xbt,
609 const char *Path,
610 PXENBUS_WATCH_CALLBACK ServiceRoutine,
611 PVOID ServiceContext)
612 {
613 PXENPCI_DEVICE_DATA xpdd = Context;
614 char *msg;
615 int i;
616 PXENBUS_WATCH_ENTRY w_entry;
617 KIRQL OldIrql;
619 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
621 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
623 ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path));
625 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
627 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
628 if (xpdd->XenBus_WatchEntries[i].Active == 0)
629 break;
631 if (i == MAX_WATCH_ENTRIES)
632 {
633 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
634 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
635 return NULL;
636 }
638 /* must init watchentry before starting watch */
640 w_entry = &xpdd->XenBus_WatchEntries[i];
641 strncpy(w_entry->Path, Path, ARRAY_SIZE(w_entry->Path));
642 w_entry->ServiceRoutine = ServiceRoutine;
643 w_entry->ServiceContext = ServiceContext;
644 w_entry->Count = 0;
645 w_entry->Active = 1;
647 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
649 msg = XenBus_SendAddWatch(xpdd, xbt, Path, i);
651 if (msg)
652 {
653 xpdd->XenBus_WatchEntries[i].Active = 0;
654 KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch (%s)\n", msg));
655 return msg;
656 }
658 KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch\n"));
660 return NULL;
661 }
663 char *
664 XenBus_RemWatch(
665 PVOID Context,
666 xenbus_transaction_t xbt,
667 const char *Path,
668 PXENBUS_WATCH_CALLBACK ServiceRoutine,
669 PVOID ServiceContext)
670 {
671 PXENPCI_DEVICE_DATA xpdd = Context;
672 struct xsd_sockmsg *rep;
673 char *msg;
674 int i;
675 char Token[20];
676 struct write_req req[2];
677 KIRQL OldIrql;
679 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
680 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
682 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
684 // check that Path < 128 chars
686 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
687 if (xpdd->XenBus_WatchEntries[i].Active == 1
688 && strcmp(xpdd->XenBus_WatchEntries[i].Path, Path) == 0
689 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
690 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
691 break;
692 }
694 if (i == MAX_WATCH_ENTRIES)
695 {
696 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
697 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
698 return NULL;
699 }
701 if (xpdd->XenBus_WatchEntries[i].RemovePending)
702 {
703 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
704 KdPrint((__DRIVER_NAME " Remove already pending - can't remove\n"));
705 return NULL;
706 }
707 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
709 while (xpdd->XenBus_WatchEntries[i].Running)
710 KeWaitForSingleObject(&xpdd->XenBus_WatchEntries[i].CompleteEvent, Executive, KernelMode, FALSE, NULL);
712 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
714 xpdd->XenBus_WatchEntries[i].Active = 0;
715 xpdd->XenBus_WatchEntries[i].RemovePending = 0;
716 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
718 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
720 req[0].data = Path;
721 req[0].len = (ULONG)strlen(Path) + 1;
723 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", i);
724 req[1].data = Token;
725 req[1].len = (ULONG)strlen(Token) + 1;
727 rep = xenbus_msg_reply(xpdd, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
729 msg = errmsg(rep);
730 if (msg)
731 {
732 return msg;
733 }
735 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
737 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
739 return NULL;
740 }
743 char *
744 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
745 {
746 PXENPCI_DEVICE_DATA xpdd = Context;
747 /* xenstored becomes angry if you send a length 0 message, so just
748 shove a nul terminator on the end */
749 struct write_req req = { "", 1};
750 struct xsd_sockmsg *rep;
751 char *err;
753 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
754 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
756 rep = xenbus_msg_reply(xpdd, XS_TRANSACTION_START, 0, &req, 1);
757 err = errmsg(rep);
758 if (err)
759 return err;
760 *xbt = atoi((char *)(rep + 1));
761 //sscanf((char *)(rep + 1), "%u", xbt);
762 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
764 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
766 return NULL;
767 }
769 char *
770 XenBus_EndTransaction(
771 PVOID Context,
772 xenbus_transaction_t t,
773 int abort,
774 int *retry)
775 {
776 PXENPCI_DEVICE_DATA xpdd = Context;
777 struct xsd_sockmsg *rep;
778 struct write_req req;
779 char *err;
781 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
783 *retry = 0;
785 req.data = abort ? "F" : "T";
786 req.len = 2;
787 rep = xenbus_msg_reply(xpdd, XS_TRANSACTION_END, t, &req, 1);
788 err = errmsg(rep);
789 if (err) {
790 if (!strcmp(err, "EAGAIN")) {
791 *retry = 1;
792 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
793 return NULL;
794 } else {
795 return err;
796 }
797 }
798 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
800 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
802 return NULL;
803 }
805 static BOOLEAN
806 XenBus_Interrupt(PKINTERRUPT Interrupt, PVOID ServiceContext)
807 {
808 PXENPCI_DEVICE_DATA xpdd = ServiceContext;
810 UNREFERENCED_PARAMETER(Interrupt);
812 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
814 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, 1, FALSE);
816 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
818 return TRUE;
819 }
821 char *
822 XenBus_Printf(
823 PVOID Context,
824 xenbus_transaction_t xbt,
825 const char *path,
826 const char *fmt,
827 ...)
828 {
829 PXENPCI_DEVICE_DATA xpdd = Context;
830 va_list ap;
831 char buf[512];
832 char *retval;
834 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
835 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
837 va_start(ap, fmt);
838 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
839 va_end(ap);
840 retval = XenBus_Write(xpdd, xbt, path, buf);
842 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
844 return retval;
845 }