static VOID close_frontend(struct scsifilt *sf, SUSPEND_TOKEN token) { XENBUS_STATE frontend_state; XENBUS_STATE backend_state; NTSTATUS status; TraceNotice(("target %d: closing frontend...\n", sf->target_id)); // Get initial frontend state status = xenbus_read_state(XBT_NIL, sf->frontend_path, "state", &frontend_state); if (!NT_SUCCESS(status)) frontend_state = null_XENBUS_STATE(); // Wait for the backend to stabilise backend_state = null_XENBUS_STATE(); do { backend_state = XenbusWaitForBackendStateChange(sf->backend_path, backend_state, NULL, token); } while (same_XENBUS_STATE(backend_state, XENBUS_STATE_INITIALISING)); TraceVerbose(("%s: target %d: backend state = %s, frontend state = %s\n", __FUNCTION__, sf->target_id, XenbusStateName(backend_state), XenbusStateName(frontend_state))); frontend_state = XENBUS_STATE_CLOSING; while (!same_XENBUS_STATE(backend_state, XENBUS_STATE_CLOSING) && !same_XENBUS_STATE(backend_state, XENBUS_STATE_CLOSED) && !is_null_XENBUS_STATE(backend_state)) { xenbus_change_state(XBT_NIL, sf->frontend_path, "state", frontend_state); backend_state = XenbusWaitForBackendStateChange(sf->backend_path, backend_state, NULL, token); } TraceVerbose(("%s: target %d: backend state = %s, frontend state = %s\n", __FUNCTION__, sf->target_id, XenbusStateName(backend_state), XenbusStateName(frontend_state))); frontend_state = XENBUS_STATE_CLOSED; while (!same_XENBUS_STATE(backend_state, XENBUS_STATE_CLOSED) && !is_null_XENBUS_STATE(backend_state)) { xenbus_change_state(XBT_NIL, sf->frontend_path, "state", frontend_state); backend_state = XenbusWaitForBackendStateChange(sf->backend_path, backend_state, NULL, token); } TraceVerbose(("%s: target %d: backend state = %s, frontend state = %s\n", __FUNCTION__, sf->target_id, XenbusStateName(backend_state), XenbusStateName(frontend_state))); TraceNotice(("target %d: backend closed\n", sf->target_id)); }
VOID XenLowerDisonnectBackend( PXEN_LOWER XenLower) { SUSPEND_TOKEN token; XENBUS_STATE festate; XENBUS_STATE bestate; if (strlen(XenLower->BackendPath) == 0) { TraceError((__FUNCTION__ ": shutting down an adapter %s which wasn't properly created?\n", XenLower->FrontendPath)); return; } // Give disconnect a go even if by some chance we cannot get a token. token = EvtchnAllocateSuspendToken("xenvusb-disconnect"); // Wait for the backend to stabilise before we close it bestate = null_XENBUS_STATE(); do { bestate = XenbusWaitForBackendStateChange(XenLower->BackendPath, bestate, NULL, null_SUSPEND_TOKEN()); } while (same_XENBUS_STATE(bestate, XENBUS_STATE_INITIALISING)); // Now close the frontend festate = XENBUS_STATE_CLOSING; while (!same_XENBUS_STATE(bestate, XENBUS_STATE_CLOSING) && !same_XENBUS_STATE(bestate, XENBUS_STATE_CLOSED) && !is_null_XENBUS_STATE(bestate)) { xenbus_change_state(XBT_NIL, XenLower->FrontendPath, "state", festate); bestate = XenbusWaitForBackendStateChange(XenLower->BackendPath, bestate, NULL, null_SUSPEND_TOKEN()); } festate = XENBUS_STATE_CLOSED; while (!same_XENBUS_STATE(bestate, XENBUS_STATE_CLOSED) && !is_null_XENBUS_STATE(bestate)) { xenbus_change_state(XBT_NIL, XenLower->FrontendPath, "state", festate); bestate = XenbusWaitForBackendStateChange(XenLower->BackendPath, bestate, NULL, null_SUSPEND_TOKEN()); } // Unhook this here since there will be no reconnecting at this point. if (XenLower->LateSuspendHandler) { EvtchnUnregisterSuspendHandler(XenLower->LateSuspendHandler); XenLower->LateSuspendHandler = NULL; } // Clear the XenLower->BackendPath which sort of indicates shutdown or // not properly initialized. // --XT-- keep backend path, useful on resume to check whether device was // unplugged during suspend // memset(&XenLower->BackendPath[0], 0, XEN_LOWER_MAX_PATH); if (!is_null_SUSPEND_TOKEN(token)) { EvtchnReleaseSuspendToken(token); } }
static NTSTATUS XenLowerConnectBackendInternal( PXEN_LOWER XenLower, SUSPEND_TOKEN Token) { NTSTATUS status = STATUS_SUCCESS; XENBUS_STATE state; xenbus_transaction_t xbt; PCHAR fepath; if (is_null_EVTCHN_PORT(XenLower->EvtchnPort)) { TraceError((__FUNCTION__ ": no event channel port, this routine must be called after event channel initialization\n")); return STATUS_UNSUCCESSFUL; } //---------------------------Backend Wait Ready-------------------------------// // // Wait for backend to get ready for initialization. // status = xenbus_change_state(XBT_NIL, XenLower->FrontendPath, "state", XENBUS_STATE_INITIALISING); if (!NT_SUCCESS(status)) { TraceWarning((__FUNCTION__ ": Failed to change front end state to XENBUS_STATE_INITIALISING(%d) status: 0x%x\n", XENBUS_STATE_INITIALISING, status)); // Go on, best effort, chin up } TraceInfo((__FUNCTION__ ": Front end state set to XENBUS_STATE_INITIALISING(%d)\n", XENBUS_STATE_INITIALISING)); state = null_XENBUS_STATE(); for ( ; ; ) { // Turns out suspend tokens are not even used. state = XenbusWaitForBackendStateChange(XenLower->BackendPath, state, NULL, Token); if (same_XENBUS_STATE(state, XENBUS_STATE_INITWAIT)) { break; } if (same_XENBUS_STATE(state, XENBUS_STATE_CLOSING) || is_null_XENBUS_STATE(state)) { TraceError((__FUNCTION__ ": backend '%s' went away before we could connect to it?\n", XenLower->BackendPath)); status = STATUS_UNSUCCESSFUL; break; } } if (status != STATUS_SUCCESS) { return status; } TraceInfo((__FUNCTION__ ": Back end state went to XENBUS_STATE_INITWAIT(%d)\n", XENBUS_STATE_INITWAIT)); //----------------------------Backend Connect---------------------------------// // // Communicate configuration to backend. // fepath = XenLower->FrontendPath; do { xenbus_transaction_start(&xbt); xenbus_write_grant_ref(xbt, fepath, "ring-ref", XenLower->SringGrantRef); xenbus_write_evtchn_port(xbt, fepath, "event-channel", XenLower->EvtchnPort); xenbus_change_state(xbt, fepath, "state", XENBUS_STATE_CONNECTED); status = xenbus_transaction_end(xbt, 0); } while (status == STATUS_RETRY); if (status != STATUS_SUCCESS) { TraceError((__FUNCTION__ ": failed to configure xenstore frontend values.\n")); return STATUS_UNSUCCESSFUL; } TraceInfo((__FUNCTION__ ": Front end state set to XENBUS_STATE_CONNECTED(%d)\n", XENBUS_STATE_CONNECTED)); // // Wait for backend to accept configuration and complete initialization. // state = null_XENBUS_STATE(); for ( ; ; ) { state = XenbusWaitForBackendStateChange(XenLower->BackendPath, state, NULL, Token); if (is_null_XENBUS_STATE(state) || same_XENBUS_STATE(state, XENBUS_STATE_CLOSING) || same_XENBUS_STATE(state, XENBUS_STATE_CLOSED)) { TraceError((__FUNCTION__ ": Failed to connected '%s' <-> '%s' backend state: %d\n", XenLower->FrontendPath, XenLower->BackendPath, state)); status = STATUS_UNSUCCESSFUL; break; } if (same_XENBUS_STATE(state, XENBUS_STATE_CONNECTED)) { TraceNotice((__FUNCTION__ ": Connected '%s' <-> '%s' \n", XenLower->FrontendPath, XenLower->BackendPath)); TraceInfo((__FUNCTION__ ": Back end final state went to XENBUS_STATE_CONNECTED(%d)\n", XENBUS_STATE_CONNECTED)); break; } } return status; }
/* We've bound the scsifilt instance to a xenvbd instance, and we've disconnected xenvbd from the shared ring. Connect scsifilt. */ NTSTATUS connect_scsifilt_with_token(struct scsifilt *sf, SUSPEND_TOKEN token) { XENBUS_STATE state; blkif_sring_t *ring_shared; NTSTATUS status; KIRQL irql; if (sf->backend_path != NULL) { TraceVerbose(("Releasing old backend path (%p)\n", sf->backend_path)); XmFreeMemory(sf->backend_path); sf->backend_path = NULL; } if (sf->ring_shared != NULL) { TraceVerbose(("Releasing old shared ring (%p)\n", sf->ring_shared)); XmFreeMemory(sf->ring_shared); sf->ring_shared = NULL; sf->ring.sring = NULL; } find_backend_handle(sf); status = STATUS_UNSUCCESSFUL; sf->backend_path = get_backend_path(sf, token); if (sf->backend_path == NULL) goto fail1; sf->target_resume(sf->target_id, token); if (sf->stopped) { sf->target_start(sf->target_id, sf->backend_path, token); sf->stopped = FALSE; } state = XenbusWaitForBackendStateChange(sf->backend_path, null_XENBUS_STATE(), NULL, token); if (!same_XENBUS_STATE(state, XENBUS_STATE_INITWAIT)) goto fail2; probe_backend_capabilities(sf); status = STATUS_NO_MEMORY; ring_shared = XmAllocateZeroedMemory(PAGE_SIZE << sf->ring_order); if (ring_shared == NULL) goto fail3; KeAcquireSpinLock(&sf->ring_lock, &irql); sf->ring_shared = ring_shared; SHARED_RING_INIT(sf->ring_shared); FRONT_RING_INIT(&sf->ring, sf->ring_shared, PAGE_SIZE << sf->ring_order); KeReleaseSpinLock(&sf->ring_lock, irql); grant_ring(sf); status = open_evtchn(sf); if (!NT_SUCCESS(status)) goto fail4; do { xenbus_transaction_t xbt; xenbus_transaction_start(&xbt); xenbus_write_evtchn_port(xbt, sf->frontend_path, "event-channel", sf->evtchn_port); if (sf->single_page) { XM_ASSERT3U(sf->ring_order, ==, 0); TraceNotice(("%s: using single page handshake\n", sf->frontend_path)); /* single page handshake */ xenbus_write_grant_ref(xbt, sf->frontend_path, "ring-ref", sf->ring_gref[0]); } else { int i; TraceNotice(("%s: using multi-page handshake\n", sf->frontend_path)); xenbus_printf(xbt, sf->frontend_path, "ring-page-order", "%u", sf->ring_order); for (i = 0; i < (1 << sf->ring_order); i++) { char buffer[10]; Xmsnprintf(buffer, sizeof(buffer), "ring-ref%1u", i); xenbus_write_grant_ref(xbt, sf->frontend_path, buffer, sf->ring_gref[i]); } } xenbus_printf(xbt, sf->frontend_path, "protocol", "x86_32-abi"); xenbus_write_feature_flag(xbt, sf->frontend_path, "feature-surprise-remove", TRUE); xenbus_write_feature_flag(xbt, sf->frontend_path, "feature-online-resize", TRUE); xenbus_change_state(xbt, sf->frontend_path, "state", XENBUS_STATE_INITIALISED); status = xenbus_transaction_end(xbt, 0); } while (status == STATUS_RETRY);
/* Returns STATUS_SUCCESS on success, STATUS_OBJECT_NAME_NOT_FOUND if we race, or some other STATUS_ on error. */ static NTSTATUS set_fe_state_careful(struct scsifilt *sf, XENBUS_STATE state) { return xenbus_change_state(XBT_NIL, sf->frontend_path, "state", state); }
static NTSTATUS V4vAddDevice(PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo) { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING deviceName; PDEVICE_OBJECT fdo = NULL; PXENV4V_EXTENSION pde = NULL; LONG val; BOOLEAN symlink = FALSE; LARGE_INTEGER seed; WCHAR *szSddl = NULL; UNICODE_STRING sddlString; CHAR *szFpath = NULL; TraceVerbose(("====> '%s'.\n", __FUNCTION__)); // We only allow one instance of this device type. If more than on pdo is created we need val = InterlockedCompareExchange(&g_deviceCreated, 1, 0); if (val != 0) { TraceWarning(("cannot instantiate more that one v4v device node.\n")); return STATUS_UNSUCCESSFUL; } do { // Create our device RtlInitUnicodeString(&deviceName, V4V_DEVICE_NAME); szSddl = g_win5Sddl; RtlInitUnicodeString(&sddlString, szSddl); status = IoCreateDeviceSecure(driverObject, sizeof(XENV4V_EXTENSION), &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &sddlString, (LPCGUID)&GUID_SD_XENV4V_CONTROL_OBJECT, &fdo); if (!NT_SUCCESS(status)) { TraceError(("failed to create device object - error: 0x%x\n", status)); fdo = NULL; break; } pde = (PXENV4V_EXTENSION)fdo->DeviceExtension; RtlZeroMemory(pde, sizeof(XENV4V_EXTENSION)); RtlStringCchCopyW(pde->symbolicLinkText, XENV4V_SYM_NAME_LEN, V4V_SYMBOLIC_NAME); RtlInitUnicodeString(&pde->symbolicLink, pde->symbolicLinkText); // Create our symbolic link status = IoCreateSymbolicLink(&pde->symbolicLink, &deviceName); if (!NT_SUCCESS(status)) { TraceError(("failed to create symbolic - error: 0x%x\n", status)); break; } symlink = TRUE; // Get our xenstore path szFpath = xenbus_find_frontend(pdo); if (szFpath == NULL) { status = STATUS_NO_SUCH_DEVICE; TraceError(("failed to locate XenStore front end path\n")); break; } // Setup the extension pde->magic = XENV4V_MAGIC; pde->pdo = pdo; pde->fdo = fdo; IoInitializeRemoveLock(&pde->removeLock, 'v4vx', 0, 0); pde->frontendPath = szFpath; szFpath = NULL; pde->state = XENV4V_DEV_STOPPED; // wait for start pde->lastPoState = PowerSystemWorking; pde->virqPort = null_EVTCHN_PORT(); KeInitializeDpc(&pde->virqDpc, V4vVirqNotifyDpc, fdo); KeInitializeSpinLock(&pde->virqLock); KeInitializeSpinLock(&pde->dpcLock); KeInitializeTimerEx(&pde->timer, NotificationTimer); KeInitializeDpc(&pde->timerDpc, V4vConnectTimerDpc, fdo); KeInitializeSpinLock(&pde->timerLock); pde->timerCounter = 0; InitializeListHead(&pde->contextList); KeInitializeSpinLock(&pde->contextLock); pde->contextCount = 0; InitializeListHead(&pde->ringList); KeInitializeSpinLock(&pde->ringLock); InitializeListHead(&pde->pendingIrpQueue); pde->pendingIrpCount = 0; KeInitializeSpinLock(&pde->queueLock); IoCsqInitializeEx(&pde->csqObject, V4vCsqInsertIrpEx, V4vCsqRemoveIrp, V4vCsqPeekNextIrp, V4vCsqAcquireLock, V4vCsqReleaseLock, V4vCsqCompleteCanceledIrp); InitializeListHead(&pde->destList); pde->destCount = 0; ExInitializeNPagedLookasideList(&pde->destLookasideList, NULL, NULL, 0, sizeof(XENV4V_DESTINATION), XENV4V_TAG, 0); KeQueryTickCount(&seed); pde->seed = seed.u.LowPart; // Now attach us to the stack pde->ldo = IoAttachDeviceToDeviceStack(fdo, pdo); if (pde->ldo == NULL) { TraceError(("failed to attach device to stack - error: 0x%x\n", status)); status = STATUS_NO_SUCH_DEVICE; break; } // Use direct IO and let the IO manager directly map user buffers; clear the init flag fdo->Flags |= DO_DIRECT_IO; fdo->Flags &= ~DO_DEVICE_INITIALIZING; // Made it here, go to connected state to be consistent xenbus_change_state(XBT_NIL, pde->frontendPath, "state", XENBUS_STATE_CONNECTED); } while (FALSE); if (!NT_SUCCESS(status)) { if (fdo != NULL) { if ((pde != NULL)&&(pde->ldo != NULL)) { IoDetachDevice(pde->ldo); } if (szFpath != NULL) { XmFreeMemory(szFpath); } if (symlink) { IoDeleteSymbolicLink(&pde->symbolicLink); } IoDeleteDevice(fdo); } } TraceVerbose(("<==== '%s'.\n", __FUNCTION__)); return status; }
static NTSTATUS NTAPI V4vDispatchPnP(PDEVICE_OBJECT fdo, PIRP irp) { NTSTATUS status = STATUS_SUCCESS; PIO_STACK_LOCATION isl = IoGetCurrentIrpStackLocation(irp); PXENV4V_EXTENSION pde = V4vGetDeviceExtension(fdo); KEVENT kev; TraceVerbose(("====> '%s'.\n", __FUNCTION__)); TraceVerbose((" =PnP= 0x%x\n", isl->MinorFunction)); status = IoAcquireRemoveLock(&pde->removeLock, irp); if (!NT_SUCCESS(status)) { TraceError(("failed to acquire IO lock - error: 0x%x\n", status)); return V4vSimpleCompleteIrp(irp, status); } switch (isl->MinorFunction) { case IRP_MN_START_DEVICE: KeInitializeEvent(&kev, NotificationEvent, FALSE); // Send the start down and wait for it to complete IoCopyCurrentIrpStackLocationToNext(irp); IoSetCompletionRoutine(irp, V4vStartDeviceIoCompletion, &kev, TRUE, TRUE, TRUE); status = IoCallDriver(pde->ldo, irp); if (status == STATUS_PENDING) { // Wait for everything underneath us to complete TraceVerbose(("Device start waiting for lower device.\n")); KeWaitForSingleObject(&kev, Executive, KernelMode, FALSE, NULL); TraceVerbose(("Device start wait finished.\n")); } status = irp->IoStatus.Status; if (!NT_SUCCESS(status)) { TraceError(("Failed to start lower drivers: %x.\n", status)); IoCompleteRequest(irp, IO_NO_INCREMENT); break; } status = STATUS_SUCCESS; // Connect our interrupt (ec). status = V4vInitializeEventChannel(fdo); if (NT_SUCCESS(status)) { InterlockedExchange(&pde->state, XENV4V_DEV_STARTED); } else { TraceError(("failed to initialize event channel - error: 0x%x\n", status)); } irp->IoStatus.Status = status; IoCompleteRequest(irp, IO_NO_INCREMENT); break; case IRP_MN_STOP_DEVICE: // Stop our device's IO processing V4vStopDevice(fdo, pde); // Pass it down irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(irp); status = IoCallDriver(pde->ldo, irp); break; case IRP_MN_REMOVE_DEVICE: // Stop our device's IO processing V4vStopDevice(fdo, pde); // Cleanup anything here that locks for IO IoReleaseRemoveLockAndWait(&pde->removeLock, irp); // Pass it down first IoSkipCurrentIrpStackLocation(irp); status = IoCallDriver(pde->ldo, irp); // Then detach and cleanup our device xenbus_change_state(XBT_NIL, pde->frontendPath, "state", XENBUS_STATE_CLOSED); IoDetachDevice(pde->ldo); ExDeleteNPagedLookasideList(&pde->destLookasideList); XmFreeMemory(pde->frontendPath); IoDeleteSymbolicLink(&pde->symbolicLink); IoDeleteDevice(fdo); InterlockedAnd(&g_deviceCreated, 0); return status; default: // Pass it down TraceVerbose(("IRP_MJ_PNP MinorFunction %d passed down\n", isl->MinorFunction)); IoSkipCurrentIrpStackLocation(irp); status = IoCallDriver(pde->ldo, irp); }; // Everybody but REMOVE IoReleaseRemoveLock(&pde->removeLock, irp); TraceVerbose(("<==== '%s'.\n", __FUNCTION__)); return status; }