static VOID XenBus_EvtFileCleanup(WDFFILEOBJECT file_object) { PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object); PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfFileObjectGetDevice(file_object)); watch_context_t *watch_context; KIRQL old_irql; PCHAR msg; FUNCTION_ENTER(); KeAcquireSpinLock(&xpdid->lock, &old_irql); while (!IsListEmpty(&xpdid->xenbus.watch_list_head)) { watch_context = (watch_context_t *)RemoveHeadList(&xpdid->xenbus.watch_list_head); KeReleaseSpinLock(&xpdid->lock, old_irql); msg = XenBus_RemWatch(xpdd, XBT_NIL, watch_context->path, XenPci_IoWatch, watch_context); if (msg != NULL) { KdPrint((__DRIVER_NAME " Error freeing watch (%s)\n", msg)); XenPci_FreeMem(msg); } ExFreePoolWithTag(watch_context, XENPCI_POOL_TAG); WdfObjectDereference(file_object); KeAcquireSpinLock(&xpdid->lock, &old_irql); } KeReleaseSpinLock(&xpdid->lock, old_irql); FUNCTION_EXIT(); }
/* Called at PASSIVE_LEVEL(?) Called during restore */ static ULONG XenPci_ReadBackendState(PXENPCI_PDO_DEVICE_DATA xppdd) { PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo); char path[128]; char *value; char *err; ULONG backend_state; RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path); err = XenBus_Read(xpdd, XBT_NIL, path, &value); if (err) { XenPci_FreeMem(err); return XenbusStateUnknown; } else { backend_state = atoi(value); XenPci_FreeMem(value); return backend_state; } }
static NTSTATUS XenPci_GetBackendDetails(WDFDEVICE device) { PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device); PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo); char path[128]; PCHAR res; PCHAR value; FUNCTION_ENTER(); /* Get backend path */ RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/backend", xppdd->path); res = XenBus_Read(xpdd, XBT_NIL, path, &value); if (res) { FUNCTION_MSG("Failed to read backend path\n"); XenPci_FreeMem(res); return STATUS_UNSUCCESSFUL; } RtlStringCbCopyA(xppdd->backend_path, ARRAY_SIZE(xppdd->backend_path), value); XenPci_FreeMem(value); /* Get backend id */ RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/backend-id", xppdd->path); res = XenBus_Read(xpdd, XBT_NIL, path, &value); if (res) { FUNCTION_MSG("Failed to read backend id\n"); XenPci_FreeMem(res); return STATUS_UNSUCCESSFUL; } xppdd->backend_id = (domid_t)atoi(value); XenPci_FreeMem(value); FUNCTION_EXIT(); return STATUS_SUCCESS; }
NTSTATUS XenPci_SuspendPdo(WDFDEVICE device) { PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device); PXENPCI_DEVICE_DATA xpdd = xppdd->xpdd; PCHAR response; CHAR path[128]; if (xppdd->device_callback) { FUNCTION_MSG("Suspending %s\n", xppdd->device); xppdd->device_callback(xppdd->device_callback_context, XN_DEVICE_CALLBACK_SUSPEND, NULL); RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path); response = XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateCallback, xppdd); if (response) { FUNCTION_MSG("XnRemWatch - %s = %s\n", path, response); XenPci_FreeMem(response); } } return STATUS_SUCCESS; }
NTSTATUS XenPci_ResumePdo(WDFDEVICE device) { PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device); PXENPCI_DEVICE_DATA xpdd = xppdd->xpdd; PCHAR response; CHAR path[128]; XenPci_GetBackendDetails(device); if (xppdd->device_callback) { FUNCTION_MSG("Resuming %s\n", xppdd->device); RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path); response = XenBus_AddWatch(xpdd, XBT_NIL, path, XenPci_BackendStateCallback, xppdd); if (response) { FUNCTION_MSG("XnAddWatch - %s = %s\n", path, response); XenPci_FreeMem(response); xppdd->device_callback = NULL; xppdd->device_callback_context = NULL; FUNCTION_EXIT(); return STATUS_UNSUCCESSFUL; } xppdd->device_callback(xppdd->device_callback_context, XN_DEVICE_CALLBACK_RESUME, NULL); } return STATUS_SUCCESS; }
/* If Initialize fails then the watch still gets called but the waits will never be acked... */ static VOID XenScsi_DevWatch(PCHAR path, PVOID DeviceExtension) { PXENSCSI_DEVICE_DATA xsdd = DeviceExtension; CHAR tmp_path[128]; PCHAR msg; PCHAR *devices; PCHAR value; scsi_dev_t *dev; ULONG i; ULONG dev_no; ULONG state; LARGE_INTEGER wait_time; #if DBG ULONG oldpause; #endif UNREFERENCED_PARAMETER(path); /* this can only be called from a watch and so is always serialised */ FUNCTION_ENTER(); #if DBG oldpause = #endif InterlockedExchange(&xsdd->shared_paused, SHARED_PAUSED_PASSIVE_PAUSED); ASSERT(oldpause == SHARED_PAUSED_SCSIPORT_UNPAUSED); while (InterlockedCompareExchange(&xsdd->shared_paused, SHARED_PAUSED_SCSIPORT_PAUSED, SHARED_PAUSED_SCSIPORT_PAUSED) != SHARED_PAUSED_SCSIPORT_PAUSED) { KdPrint((__DRIVER_NAME " Waiting for pause...\n")); wait_time.QuadPart = -100 * 1000 * 10; /* 100ms */ KeDelayExecutionThread(KernelMode, FALSE, &wait_time); } KdPrint((__DRIVER_NAME " Watch triggered on %s\n", path)); RtlStringCbCopyA(tmp_path, ARRAY_SIZE(tmp_path), xsdd->vectors.backend_path); RtlStringCbCatA(tmp_path, ARRAY_SIZE(tmp_path), "/vscsi-devs"); msg = xsdd->vectors.XenBus_List(xsdd->vectors.context, XBT_NIL, tmp_path, &devices); if (msg) { /* this is pretty fatal ... */ KdPrint((__DRIVER_NAME " cannot read - %s\n", msg)); return; } for (dev = (scsi_dev_t *)xsdd->dev_list_head.Flink; dev != (scsi_dev_t *)&xsdd->dev_list_head; dev = (scsi_dev_t *)dev->entry.Flink) { dev->validated = FALSE; } for (i = 0; devices[i]; i++) { if (strncmp(devices[i], "dev-", 4) != 0) { XenPci_FreeMem(devices[i]); break; /* not a dev so we are not interested */ } dev_no = atoi(devices[i] + 4); RtlStringCbCopyA(tmp_path, ARRAY_SIZE(tmp_path), xsdd->vectors.backend_path); RtlStringCbCatA(tmp_path, ARRAY_SIZE(tmp_path), "/vscsi-devs/"); RtlStringCbCatA(tmp_path, ARRAY_SIZE(tmp_path), devices[i]); RtlStringCbCatA(tmp_path, ARRAY_SIZE(tmp_path), "/state"); msg = xsdd->vectors.XenBus_Read(xsdd->vectors.context, XBT_NIL, tmp_path, &value); if (msg) { KdPrint((__DRIVER_NAME " failed to read state for device %d\n", dev_no)); state = 0; } else state = atoi(value); for (dev = (scsi_dev_t *)xsdd->dev_list_head.Flink; dev != (scsi_dev_t *)&xsdd->dev_list_head; dev = (scsi_dev_t * )dev->entry.Flink) { if (dev->dev_no == dev_no) break; } if (dev == (scsi_dev_t *)&xsdd->dev_list_head) { KdPrint((__DRIVER_NAME " new dev %d\n", dev_no)); dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(scsi_dev_t), XENSCSI_POOL_TAG); dev->dev_no = dev_no; dev->state = state; dev->validated = TRUE; RtlStringCbCopyA(tmp_path, ARRAY_SIZE(tmp_path), xsdd->vectors.backend_path); RtlStringCbCatA(tmp_path, ARRAY_SIZE(tmp_path), "/vscsi-devs/"); RtlStringCbCatA(tmp_path, ARRAY_SIZE(tmp_path), devices[i]); RtlStringCbCatA(tmp_path, ARRAY_SIZE(tmp_path), "/v-dev"); msg = xsdd->vectors.XenBus_Read(xsdd->vectors.context, XBT_NIL, tmp_path, &value); if (msg) { KdPrint((__DRIVER_NAME " failed to read v-dev for device %d\n", dev_no)); continue; } else { XenScsi_ParseBackendDevice(dev, value); // should verify that the controller = this } RtlStringCbCopyA(tmp_path, ARRAY_SIZE(tmp_path), xsdd->vectors.path); RtlStringCbCatA(tmp_path, ARRAY_SIZE(tmp_path), "/vscsi-devs/"); RtlStringCbCatA(tmp_path, ARRAY_SIZE(tmp_path), devices[i]); RtlStringCbCatA(tmp_path, ARRAY_SIZE(tmp_path), "/state"); msg = xsdd->vectors.XenBus_Write(xsdd->vectors.context, XBT_NIL, tmp_path, "4"); if (msg) { KdPrint((__DRIVER_NAME " failed to write state %d to %s\n", 4, tmp_path)); continue; } KdPrint((__DRIVER_NAME " setting changes[%d]\n", dev->channel)); xsdd->bus_changes[dev->channel] = 1; InsertTailList(&xsdd->dev_list_head, (PLIST_ENTRY)dev); } else { // need to manage state change // and write frontend state dev->state = state; dev->validated = TRUE; KdPrint((__DRIVER_NAME " existing dev %d state = %d\n", dev_no, dev->state)); } XenPci_FreeMem(devices[i]); } XenPci_FreeMem(devices); #if DBG oldpause = #endif InterlockedExchange(&xsdd->shared_paused, SHARED_PAUSED_PASSIVE_UNPAUSED); ASSERT(oldpause == SHARED_PAUSED_SCSIPORT_PAUSED); while (InterlockedCompareExchange(&xsdd->shared_paused, SHARED_PAUSED_SCSIPORT_UNPAUSED, SHARED_PAUSED_SCSIPORT_UNPAUSED) != SHARED_PAUSED_SCSIPORT_UNPAUSED) { KdPrint((__DRIVER_NAME " Waiting for unpause...\n")); wait_time.QuadPart = -100 * 1000 * 10; /* 100ms */ KeDelayExecutionThread(KernelMode, FALSE, &wait_time); } KdPrint((__DRIVER_NAME " Unpaused\n")); FUNCTION_EXIT(); }