static NTSTATUS LfsFiltCloseControl ( IN HANDLE ControlFileHandle, IN PFILE_OBJECT ControlFileObject ) { NTSTATUS status; if(ControlFileObject) ObDereferenceObject(ControlFileObject); if(!ControlFileHandle) return STATUS_SUCCESS; status = ZwClose (ControlFileHandle); if (!NT_SUCCESS(status)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("FAILURE, NtClose returned status code=%x\n", status)); } else { Bus_KdPrint_Def(BUS_DBG_SS_TRACE, ("SUCCESS.\n")); } return status; }
// // Plug in a device on NDAS bus in KernelMode. // NTSTATUS LSBus_PlugInLSBUSDevice( PFDO_DEVICE_DATA FdoData, PBUSENUM_PLUGIN_HARDWARE_EX2 PlugIn ){ HANDLE DisconEvent; HANDLE AlarmEvent; NTSTATUS status; // // Create events // status = ZwCreateEvent( &DisconEvent, GENERIC_READ, NULL, NotificationEvent, FALSE ); if(!NT_SUCCESS(status)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("PlugInLSBUSDevice: ZwCreateEvent() failed. Disconnection event.\n")); return status; } status = ZwCreateEvent( &AlarmEvent, GENERIC_READ, NULL, NotificationEvent, FALSE ); if(!NT_SUCCESS(status)) { ZwClose(DisconEvent); Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("PlugInLSBUSDevice: ExAllocatePoolWithTag() failed. AlarmEvent\n")); return status; } // // Set up BUSENUM_PLUGIN_HARDWARE_EX2 structure. // PlugIn->phAlarmEvent = &AlarmEvent; PlugIn->phEvent = &DisconEvent; status = Bus_PlugInDeviceEx2(PlugIn, PlugIn->Size, FdoData, KernelMode, TRUE); // // Close handle to decrease one reference from events. // ZwClose(AlarmEvent); ZwClose(DisconEvent); return status; }
NTSTATUS DriverEntry ( __in PDRIVER_OBJECT DriverObject, __in PUNICODE_STRING RegistryPath ) /*++ Routine Description: Initialize the driver dispatch table. Arguments: DriverObject - pointer to the driver object RegistryPath - pointer to a unicode string representing the path, to driver-specific key in the registry. Return Value: NT Status Code --*/ { Bus_KdPrint_Def (BUS_DBG_SS_TRACE, ("Driver Entry \n")); // // Save the RegistryPath for WMI. // Globals.RegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL); Globals.RegistryPath.Length = RegistryPath->Length; Globals.RegistryPath.Buffer = ExAllocatePoolWithTag( PagedPool, Globals.RegistryPath.MaximumLength, BUSENUM_POOL_TAG ); if (!Globals.RegistryPath.Buffer) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyUnicodeString(&Globals.RegistryPath, RegistryPath); // // Set entry points into the driver // DriverObject->MajorFunction [IRP_MJ_CREATE] = DriverObject->MajorFunction [IRP_MJ_CLOSE] = Bus_CreateClose; DriverObject->MajorFunction [IRP_MJ_PNP] = Bus_PnP; DriverObject->MajorFunction [IRP_MJ_POWER] = Bus_Power; DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = Bus_IoCtl; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = Bus_SystemControl; DriverObject->DriverUnload = Bus_DriverUnload; DriverObject->DriverExtension->AddDevice = Bus_AddDevice; return STATUS_SUCCESS; }
NTSTATUS LSBus_OpenLanscsiAdapter( IN PPDO_LANSCSI_DEVICE_DATA LanscsiAdapter, IN ULONG MaxBlocks, IN PKEVENT DisconEventToService, IN PKEVENT AlarmEventToService ) { Bus_KdPrint_Def(BUS_DBG_SS_TRACE, ("Entered.\n")); ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); RtlZeroMemory( LanscsiAdapter, sizeof(PDO_LANSCSI_DEVICE_DATA) ); KeInitializeSpinLock(&LanscsiAdapter->LSDevDataSpinLock); LanscsiAdapter->MaxBlocksPerRequest = MaxBlocks; LanscsiAdapter->DisconEventToService = DisconEventToService; LanscsiAdapter->AlarmEventToService = AlarmEventToService; // // initialize private fields. // KeInitializeEvent( &LanscsiAdapter->AddTargetEvent, NotificationEvent, FALSE ); return STATUS_SUCCESS; }
NTSTATUS LSBus_CloseLanscsiAdapter( IN PPDO_LANSCSI_DEVICE_DATA LanscsiAdapter ) { ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); Bus_KdPrint_Def(BUS_DBG_SS_TRACE, ("Entered.\n")); // // Dereference objects. // ObDereferenceObject(LanscsiAdapter->DisconEventToService); if(LanscsiAdapter->AlarmEventToService) ObDereferenceObject(LanscsiAdapter->AlarmEventToService); // // Free allocated memory. // if(LanscsiAdapter->AddDevInfo) ExFreePool(LanscsiAdapter->AddDevInfo); return STATUS_SUCCESS; }
NTSTATUS VerifyAddTargetData( IN PNDASBUS_ADD_TARGET_DATA AddTargetData ){ switch(AddTargetData->ucTargetType) { case NDASSCSI_TYPE_DISK_NORMAL: case NDASSCSI_TYPE_DVD: case NDASSCSI_TYPE_VDVD: case NDASSCSI_TYPE_MO: { if(AddTargetData->ulNumberOfUnitDiskList != 1) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("NORMAL/ODD: Too many Unit devices\n")); return STATUS_TOO_MANY_NODES; } break; } case NDASSCSI_TYPE_DISK_RAID0: case NDASSCSI_TYPE_DISK_RAID1R2: case NDASSCSI_TYPE_DISK_RAID4R2: case NDASSCSI_TYPE_DISK_RAID1R3: case NDASSCSI_TYPE_DISK_RAID4R3: case NDASSCSI_TYPE_DISK_RAID5: case NDASSCSI_TYPE_DISK_MIRROR: case NDASSCSI_TYPE_DISK_AGGREGATION: { if(AddTargetData->ulNumberOfUnitDiskList <= 1) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("RAID: Too few Unit devices\n")); return STATUS_INVALID_PARAMETER; } break; } case NDASSCSI_TYPE_AOD: { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("AOD: Not supported\n")); return STATUS_NOT_SUPPORTED; } default: Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Invalid target type.\n")); return STATUS_OBJECT_TYPE_MISMATCH; } return STATUS_SUCCESS; }
NTSTATUS LSBus_WaitUntilLanscsiMiniportStop( IN PPDO_LANSCSI_DEVICE_DATA LanscsiAdapter ) { LARGE_INTEGER Interval; LONG WaitCnt; NTSTATUS ntStatus; KIRQL oldIrql; ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); Bus_KdPrint_Def(BUS_DBG_SS_TRACE, ("Entered.\n")); // // Wait for Lanscsiminiport. // ntStatus = STATUS_SUCCESS; Interval.QuadPart = - NANO100_PER_SEC / 2; // 0.5 seconds. WaitCnt = 0; while(1) { KeAcquireSpinLock(&LanscsiAdapter->LSDevDataSpinLock, &oldIrql); if(ADAPTERINFO_ISSTATUS(LanscsiAdapter->AdapterStatus, ADAPTERINFO_STATUS_STOPPED)) { KeReleaseSpinLock(&LanscsiAdapter->LSDevDataSpinLock, oldIrql); break; } KeReleaseSpinLock(&LanscsiAdapter->LSDevDataSpinLock, oldIrql); Bus_KdPrint_Def(BUS_DBG_SS_INFO, ("Wait for Lanscsiminiport!!\n")); WaitCnt ++; KeDelayExecutionThread(KernelMode, TRUE,&Interval); if(WaitCnt >= LSBUS_LANSCSIMINIPORT_STOP_TIMEOUT) { Bus_KdPrint_Def(BUS_DBG_SS_INFO, ("TimeOut!!!\n")); ntStatus = STATUS_TIMEOUT; break; } } return ntStatus; }
static NTSTATUS LfsFiltIoControl( IN HANDLE ControlFileHandle, IN PFILE_OBJECT ControlFileObject, IN ULONG IoControlCode, IN PVOID InputBuffer OPTIONAL, IN ULONG InputBufferLength, OUT PVOID OutputBuffer OPTIONAL, IN ULONG OutputBufferLength ) { NTSTATUS ntStatus; PDEVICE_OBJECT deviceObject; PIRP irp; KEVENT event; IO_STATUS_BLOCK ioStatus; UNREFERENCED_PARAMETER(ControlFileHandle); Bus_KdPrint_Def(BUS_DBG_SS_TRACE, ("Entered\n")); deviceObject = IoGetRelatedDeviceObject(ControlFileObject); KeInitializeEvent(&event, NotificationEvent, FALSE); irp = IoBuildDeviceIoControlRequest( IoControlCode, deviceObject, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, FALSE, &event, &ioStatus ); if (irp == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } ntStatus = IoCallDriver(deviceObject, irp); if (ntStatus == STATUS_PENDING) { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); ntStatus = ioStatus.Status; } return ntStatus; }
VOID Bus_DriverUnload ( IN PDRIVER_OBJECT DriverObject ) /*++ Routine Description: Clean up everything we did in driver entry. Arguments: DriverObject - pointer to this driverObject. Return Value: --*/ { PAGED_CODE (); Bus_KdPrint_Def (BUS_DBG_SS_TRACE, ("Unload\n")); // // All the device objects should be gone. // ASSERT (NULL == DriverObject->DeviceObject); UNREFERENCED_PARAMETER(DriverObject); // // Here we free all the resources allocated in the DriverEntry // if(Globals.RegistryPath.Buffer) ExFreePool(Globals.RegistryPath.Buffer); return; }
VOID Bus_InterfaceDereference ( IN PVOID Context ) /*++ Routine Description: This routine decrements the refcount. We check this refcount during query_remove decide whether to allow the remove or not. Arguments: Context pointer to PDO device extension Return Value: --*/ { Bus_KdPrint_Def(BUS_DBG_PNP_INFO, ("Entered\n")); InterlockedDecrement(&((PPDO_DEVICE_DATA)Context)->ToasterInterfaceRefCount); }
NTSTATUS Bus_AddDevice( __in PDRIVER_OBJECT DriverObject, __in PDEVICE_OBJECT PhysicalDeviceObject ) /*++ Routine Description. Our Toaster bus has been found. Attach our FDO to it. Allocate any required resources. Set things up. And be prepared for the ``start device'' Arguments: DriverObject - pointer to driver object. PhysicalDeviceObject - Device object representing the bus to which we will attach a new FDO. --*/ { NTSTATUS status; PDEVICE_OBJECT deviceObject = NULL; PFDO_DEVICE_DATA deviceData = NULL; PWCHAR deviceName = NULL; ULONG nameLength; PKTIMER timer; PKDPC dpc; PAGED_CODE (); Bus_KdPrint_Def (BUS_DBG_SS_TRACE, ("Add Device: 0x%p\n", PhysicalDeviceObject)); status = IoCreateDevice ( DriverObject, // our driver object sizeof (FDO_DEVICE_DATA), // device object extension size NULL, // FDOs do not have names FILE_DEVICE_BUS_EXTENDER, // We are a bus FILE_DEVICE_SECURE_OPEN, // TRUE, // our FDO is exclusive &deviceObject); // The device object created if (!NT_SUCCESS (status)) { goto End; } deviceData = (PFDO_DEVICE_DATA) deviceObject->DeviceExtension; RtlZeroMemory (deviceData, sizeof (FDO_DEVICE_DATA)); // // Set the initial state of the FDO // INITIALIZE_PNP_STATE(deviceData); deviceData->DebugLevel = BusEnumDebugLevel; deviceData->IsFDO = TRUE; deviceData->Self = deviceObject; ExInitializeFastMutex (&deviceData->Mutex); InitializeListHead (&deviceData->ListOfPDOs); // Set the PDO for use with PlugPlay functions deviceData->UnderlyingPDO = PhysicalDeviceObject; // // Set the initial powerstate of the FDO // deviceData->DevicePowerState = PowerDeviceUnspecified; deviceData->SystemPowerState = PowerSystemWorking; // // Biased to 1. Transition to zero during remove device // means IO is finished. Transition to 1 means the device // can be stopped. // deviceData->OutstandingIO = 1; // // Initialize the remove event to Not-Signaled. This event // will be set when the OutstandingIO will become 0. // KeInitializeEvent(&deviceData->RemoveEvent, SynchronizationEvent, FALSE); // // Initialize the stop event to Signaled: // there are no Irps that prevent the device from being // stopped. This event will be set when the OutstandingIO // will become 0. // KeInitializeEvent(&deviceData->StopEvent, SynchronizationEvent, TRUE); deviceObject->Flags |= DO_POWER_PAGABLE|DO_BUFFERED_IO; // // Tell the Plug & Play system that this device will need a // device interface. // status = IoRegisterDeviceInterface ( PhysicalDeviceObject, (LPGUID) &GUID_DEVINTERFACE_BUSENUM_TOASTER, NULL, &deviceData->InterfaceName); if (!NT_SUCCESS (status)) { Bus_KdPrint (deviceData, BUS_DBG_SS_ERROR, ("AddDevice: IoRegisterDeviceInterface failed (%x)", status)); goto End; } // // Attach our FDO to the device stack. // The return value of IoAttachDeviceToDeviceStack is the top of the // attachment chain. This is where all the IRPs should be routed. // deviceData->NextLowerDriver = IoAttachDeviceToDeviceStack ( deviceObject, PhysicalDeviceObject); if (NULL == deviceData->NextLowerDriver) { status = STATUS_NO_SUCH_DEVICE; goto End; } #if DBG // // We will demonstrate here the step to retrieve the name of the PDO // status = IoGetDeviceProperty (PhysicalDeviceObject, DevicePropertyPhysicalDeviceObjectName, 0, NULL, &nameLength); if (status != STATUS_BUFFER_TOO_SMALL) { Bus_KdPrint (deviceData, BUS_DBG_SS_ERROR, ("AddDevice:IoGDP failed (0x%x)\n", status)); goto End; } deviceName = ExAllocatePoolWithTag (NonPagedPool, nameLength, BUSENUM_POOL_TAG); if (NULL == deviceName) { Bus_KdPrint (deviceData, BUS_DBG_SS_ERROR, ("AddDevice: no memory to alloc for deviceName(0x%x)\n", nameLength)); status = STATUS_INSUFFICIENT_RESOURCES; goto End; } status = IoGetDeviceProperty (PhysicalDeviceObject, DevicePropertyPhysicalDeviceObjectName, nameLength, deviceName, &nameLength); if (!NT_SUCCESS (status)) { Bus_KdPrint (deviceData, BUS_DBG_SS_ERROR, ("AddDevice:IoGDP(2) failed (0x%x)", status)); goto End; } Bus_KdPrint (deviceData, BUS_DBG_SS_TRACE, ("AddDevice: %p to %p->%p (%ws) \n", deviceObject, deviceData->NextLowerDriver, PhysicalDeviceObject, deviceName)); #endif // // We are done with initializing, so let's indicate that and return. // This should be the final step in the AddDevice process. // deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; End: if (deviceName){ ExFreePool(deviceName); } if (!NT_SUCCESS(status) && deviceObject){ if (deviceData && deviceData->NextLowerDriver){ IoDetachDevice (deviceData->NextLowerDriver); } IoDeleteDevice (deviceObject); } return status; }
// // Query information on LanscsiBus // NTSTATUS LSBus_QueryInformation( PFDO_DEVICE_DATA FdoData, PBUSENUM_QUERY_INFORMATION Query, PBUSENUM_INFORMATION Information, LONG OutBufferLength, PLONG OutBufferLenNeeded ) { NTSTATUS ntStatus; PLIST_ENTRY entry; PPDO_DEVICE_DATA PdoData; ntStatus = STATUS_SUCCESS; *OutBufferLenNeeded = OutBufferLength; PdoData = NULL; // // Acquire the mutex to prevent PdoData ( Device Extension ) to disappear. // KeEnterCriticalRegion(); ExAcquireFastMutex (&FdoData->Mutex); switch(Query->InfoClass) { case INFORMATION_NUMOFPDOS: { ULONG NumOfPDOs; NumOfPDOs = 0; for (entry = FdoData->ListOfPDOs.Flink; entry != &FdoData->ListOfPDOs; entry = entry->Flink) { NumOfPDOs ++; } Information->NumberOfPDOs = NumOfPDOs; break; } case INFORMATION_PDO: { KIRQL oldIrql; for (entry = FdoData->ListOfPDOs.Flink; entry != &FdoData->ListOfPDOs; entry = entry->Flink) { PdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); if(Query->SlotNo == PdoData->SlotNo) { ObReferenceObject(PdoData->Self); break; } PdoData = NULL; } if(PdoData) { KeAcquireSpinLock(&PdoData->LanscsiAdapterPDO.LSDevDataSpinLock, &oldIrql); Bus_KdPrint_Def(BUS_DBG_SS_TRACE, ("Status:%08lx DAcc:%08lx GAcc:%08lx\n", PdoData->LanscsiAdapterPDO.AdapterStatus, PdoData->LanscsiAdapterPDO.DesiredAccess, PdoData->LanscsiAdapterPDO.GrantedAccess )); Information->PdoInfo.AdapterStatus = PdoData->LanscsiAdapterPDO.AdapterStatus; Information->PdoInfo.DesiredAccess = PdoData->LanscsiAdapterPDO.DesiredAccess; Information->PdoInfo.GrantedAccess = PdoData->LanscsiAdapterPDO.GrantedAccess; KeReleaseSpinLock(&PdoData->LanscsiAdapterPDO.LSDevDataSpinLock, oldIrql); ObDereferenceObject(PdoData->Self); } else { Bus_KdPrint_Def(BUS_DBG_SS_NOISE, ("No PDO for SlotNo %d!\n", Query->SlotNo)); ntStatus = STATUS_NO_SUCH_DEVICE; } break; } case INFORMATION_PDOENUM: { LARGE_INTEGER TimeOut; ULONG resultLength; DEVICE_INSTALL_STATE deviceInstallState; for (entry = FdoData->ListOfPDOs.Flink; entry != &FdoData->ListOfPDOs; entry = entry->Flink) { PdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); if(Query->SlotNo == PdoData->SlotNo) { ObReferenceObject(PdoData->Self); break; } PdoData = NULL; } ExReleaseFastMutex (&FdoData->Mutex); KeLeaveCriticalRegion(); if(!PdoData) { KeEnterCriticalRegion(); ExAcquireFastMutex (&FdoData->Mutex); ntStatus = STATUS_NO_SUCH_DEVICE; break; } // // Wait until LDServ sends AddTargetData. // Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("waiting for AddTargetEvent.\n")); TimeOut.QuadPart = -10 * 1000 * 1000 * 120; // 120 seconds ntStatus = KeWaitForSingleObject( &PdoData->LanscsiAdapterPDO.AddTargetEvent, Executive, KernelMode, FALSE, &TimeOut ); if(ntStatus != STATUS_SUCCESS) { KeEnterCriticalRegion(); ExAcquireFastMutex (&FdoData->Mutex); Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("failed to wait for AddTargetEvent.\n")); ntStatus = STATUS_NO_SUCH_DEVICE; ObDereferenceObject(PdoData->Self); break; } Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Completed to wait for AddTargetEvent.\n")); if(PdoData) { if(PdoData->LanscsiAdapterPDO.Flags & LSDEVDATA_FLAG_LURDESC) { // // A LUR descriptor is set. // if(PdoData->LanscsiAdapterPDO.AddDevInfo == NULL) { KeEnterCriticalRegion(); ExAcquireFastMutex (&FdoData->Mutex); ntStatus = STATUS_NO_SUCH_DEVICE; ObDereferenceObject(PdoData->Self); break; } *OutBufferLenNeeded = FIELD_OFFSET(BUSENUM_INFORMATION, PdoEnumInfo) + FIELD_OFFSET(BUSENUM_INFORMATION_PDOENUM, AddDevInfo) + PdoData->LanscsiAdapterPDO.AddDevInfoLength; if(OutBufferLength < *OutBufferLenNeeded) { ntStatus = STATUS_BUFFER_TOO_SMALL; } else { RtlCopyMemory( &Information->PdoEnumInfo.AddDevInfo, PdoData->LanscsiAdapterPDO.AddDevInfo, PdoData->LanscsiAdapterPDO.AddDevInfoLength ); Information->PdoEnumInfo.Flags = PDOENUM_FLAG_LURDESC; Information->PdoEnumInfo.DisconEventToService = PdoData->LanscsiAdapterPDO.DisconEventToService; Information->PdoEnumInfo.AlarmEventToService = PdoData->LanscsiAdapterPDO.AlarmEventToService; Information->PdoEnumInfo.MaxBlocksPerRequest = PdoData->LanscsiAdapterPDO.MaxBlocksPerRequest; // // Check to see if this is the first enumeration. // ntStatus = DrGetDeviceProperty( PdoData->Self, DevicePropertyInstallState, sizeof(deviceInstallState), &deviceInstallState, &resultLength, (Globals.MajorVersion == 5) && (Globals.MinorVersion == 0) ); if(NT_SUCCESS(ntStatus)) { if(deviceInstallState != InstallStateInstalled) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("First time installation. Do not enumerate a device.\n")); Information->PdoEnumInfo.Flags |= PDOENUM_FLAG_DRV_NOT_INSTALLED; } } } } else { // // ADD_TARGET_DATA is set. // PLANSCSI_ADD_TARGET_DATA AddTargetData; LONG AddTargetLenNeeded; LONG InfoBuffLenNeeded; AddTargetData = PdoData->LanscsiAdapterPDO.AddDevInfo; if(AddTargetData == NULL) { KeEnterCriticalRegion(); ExAcquireFastMutex (&FdoData->Mutex); ntStatus = STATUS_NO_SUCH_DEVICE; ObDereferenceObject(PdoData->Self); break; } // // calculate the length needed. // AddTargetLenNeeded = sizeof(LANSCSI_ADD_TARGET_DATA) + (AddTargetData->ulNumberOfUnitDiskList-1)*sizeof(LSBUS_UNITDISK); InfoBuffLenNeeded = sizeof(BUSENUM_INFORMATION) - sizeof(BYTE) + (AddTargetLenNeeded); *OutBufferLenNeeded = InfoBuffLenNeeded; if(OutBufferLength < InfoBuffLenNeeded) { ntStatus = STATUS_BUFFER_TOO_SMALL; } else { RtlCopyMemory(&Information->PdoEnumInfo.AddDevInfo, AddTargetData, AddTargetLenNeeded); Information->PdoEnumInfo.Flags = 0; Information->PdoEnumInfo.DisconEventToService = PdoData->LanscsiAdapterPDO.DisconEventToService; Information->PdoEnumInfo.AlarmEventToService = PdoData->LanscsiAdapterPDO.AlarmEventToService; Information->PdoEnumInfo.MaxBlocksPerRequest = PdoData->LanscsiAdapterPDO.MaxBlocksPerRequest; // // Check to see if this is the first enumeration. // ntStatus = DrGetDeviceProperty( PdoData->Self, DevicePropertyInstallState, sizeof(deviceInstallState), &deviceInstallState, &resultLength, (Globals.MajorVersion == 5) && (Globals.MinorVersion == 0) ); if(NT_SUCCESS(ntStatus)) { if(deviceInstallState != InstallStateInstalled) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("First time installation. Do not enumerate a device.\n")); Information->PdoEnumInfo.Flags |= PDOENUM_FLAG_DRV_NOT_INSTALLED; } } else { ntStatus = STATUS_SUCCESS; Information->PdoEnumInfo.Flags &= ~PDOENUM_FLAG_DRV_NOT_INSTALLED; } } } } else { ntStatus = STATUS_NO_SUCH_DEVICE; } KeEnterCriticalRegion(); ExAcquireFastMutex (&FdoData->Mutex); ObDereferenceObject(PdoData->Self); break; } case INFORMATION_PDOEVENT: { for (entry = FdoData->ListOfPDOs.Flink; entry != &FdoData->ListOfPDOs; entry = entry->Flink) { PdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); if(Query->SlotNo == PdoData->SlotNo) { ObReferenceObject(PdoData->Self); break; } PdoData = NULL; } if(PdoData == NULL) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Could not find the PDO:%u.\n", Query->SlotNo)); ntStatus = STATUS_NO_SUCH_DEVICE; break; } if( Query->Flags & LSBUS_QUERYFLAG_USERHANDLE) { Information->PdoEvents.SlotNo = PdoData->SlotNo; Information->PdoEvents.Flags = LSBUS_QUERYFLAG_USERHANDLE; // // Get user-mode event handles. // ntStatus = ObOpenObjectByPointer( PdoData->LanscsiAdapterPDO.DisconEventToService, 0, NULL, EVENT_ALL_ACCESS, *ExEventObjectType, UserMode, &Information->PdoEvents.DisconEvent ); if(!NT_SUCCESS(ntStatus)) { ObDereferenceObject(PdoData->Self); Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Could not open Disconnect event object!!\n")); break; } ntStatus = ObOpenObjectByPointer( PdoData->LanscsiAdapterPDO.AlarmEventToService, 0, NULL, EVENT_ALL_ACCESS, *ExEventObjectType, UserMode, &Information->PdoEvents.AlarmEvent ); if(!NT_SUCCESS(ntStatus)) { ObDereferenceObject(PdoData->Self); Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Could not open Disconnect event object!!\n")); break; } } else { Information->PdoEvents.SlotNo = PdoData->SlotNo; Information->PdoEvents.Flags = 0; Information->PdoEvents.DisconEvent = PdoData->LanscsiAdapterPDO.DisconEventToService; Information->PdoEvents.AlarmEvent = PdoData->LanscsiAdapterPDO.AlarmEventToService; } ObDereferenceObject(PdoData->Self); break; } case INFORMATION_ISREGISTERED: { ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); ntStatus = LSBus_IsRegistered(FdoData, Query->SlotNo); break; } case INFORMATION_PDOSLOTLIST: { LONG outputLength; LONG entryCnt; if(OutBufferLength < FIELD_OFFSET(BUSENUM_INFORMATION, PdoSlotList)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("PDOSLOTLIST: Buffer size is less than required\n")); ntStatus = STATUS_INVALID_PARAMETER; break; } Information->Size = 0; Information->InfoClass = INFORMATION_PDOSLOTLIST; // // Add the size of information header. // outputLength = FIELD_OFFSET(BUSENUM_INFORMATION, PdoSlotList); outputLength += sizeof(UINT32); // SlotNoCnt entryCnt = 0; for (entry = FdoData->ListOfPDOs.Flink; entry != &FdoData->ListOfPDOs; entry = entry->Flink) { PdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); // // Add the size of each slot entry. // outputLength += sizeof(UINT32); if(outputLength > OutBufferLength) { continue; } Information->PdoSlotList.SlotNo[entryCnt] = PdoData->SlotNo; Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("PDOSLOTLIST: Entry #%u: %u\n", entryCnt, PdoData->SlotNo)); entryCnt ++; } if(outputLength > OutBufferLength) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("PDOSLOTLIST: Could not find a Device(%d).\n", Query->SlotNo)); *OutBufferLenNeeded = outputLength; ntStatus = STATUS_BUFFER_TOO_SMALL; } else { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("PDOSLOTLIST: Entry count:%d.\n", entryCnt)); Information->Size = outputLength; Information->PdoSlotList.SlotNoCnt = entryCnt; *OutBufferLenNeeded = outputLength; } break; } case INFORMATION_PDOFILEHANDLE: { PWCHAR devName; USHORT devNameLen; OBJECT_ATTRIBUTES objectAttr; UNICODE_STRING objName; HANDLE devFileHandle; IO_STATUS_BLOCK ioStatus; devName = NULL; for (entry = FdoData->ListOfPDOs.Flink; entry != &FdoData->ListOfPDOs; entry = entry->Flink) { PdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); if(Query->SlotNo == PdoData->SlotNo) { ObReferenceObject(PdoData->Self); break; } PdoData = NULL; } if(PdoData == NULL) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Could not find the PDO:%u.\n", Query->SlotNo)); ntStatus = STATUS_NO_SUCH_DEVICE; break; } // // Get the name of the physical device object. // ntStatus = GetPhyDeviceName(PdoData->Self, &devName, &devNameLen); if(!NT_SUCCESS(ntStatus)) { ObDereferenceObject(PdoData->Self); break; } // // Build unicode name of the device. // Get rid of NULL termination from the length // objName.Buffer = devName; if(devNameLen > 0 && devName[devNameLen/sizeof(WCHAR) - 1] == L'\0') { objName.MaximumLength = devNameLen; objName.Length = devNameLen - sizeof(WCHAR); } else { objName.MaximumLength = objName.Length = devNameLen; } // // Open a device file. // if(Query->Flags & LSBUS_QUERYFLAG_USERHANDLE) { Information->PdoFile.Flags = LSBUS_QUERYFLAG_USERHANDLE; InitializeObjectAttributes(&objectAttr, &objName, OBJ_CASE_INSENSITIVE , NULL, NULL); } else { Information->PdoFile.Flags = 0; InitializeObjectAttributes(&objectAttr, &objName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); } ntStatus = ZwCreateFile( &devFileHandle, SYNCHRONIZE|FILE_READ_DATA, &objectAttr, &ioStatus, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if(!NT_SUCCESS(ntStatus)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Could not open the PDO:%u. STATUS=%08lx\n", Query->SlotNo, ntStatus)); ExFreePool(devName); ObDereferenceObject(PdoData->Self); break; } // // Set the return values // Information->PdoFile.SlotNo = PdoData->SlotNo; Information->PdoFile.PdoFileHandle = devFileHandle; if(devName) ExFreePool(devName); ObDereferenceObject(PdoData->Self); break; } default: ntStatus = STATUS_INVALID_PARAMETER; } ExReleaseFastMutex (&FdoData->Mutex); KeLeaveCriticalRegion(); return ntStatus; }
// // I/O Control to the LanscsiMiniport. // Buffers must be allocated from NonPagedPool // // NOTE: Do not use LANSCSIMINIPORT_IOCTL_QUERYINFO. // It uses separate input/output buffer. // It will be obsolete. // NTSTATUS LSBus_IoctlToLSMPDevice( PPDO_DEVICE_DATA PdoData, ULONG IoctlCode, PVOID InputBuffer, LONG InputBufferLength, PVOID OutputBuffer, LONG OutputBufferLength ) { PDEVICE_OBJECT AttachedDevice; PIRP irp; KEVENT event; PSRB_IO_CONTROL psrbIoctl; LONG srbIoctlLength; PVOID srbIoctlBuffer; LONG srbIoctlBufferLength; NTSTATUS status; PIO_STACK_LOCATION irpStack; SCSI_REQUEST_BLOCK srb; LARGE_INTEGER startingOffset; IO_STATUS_BLOCK ioStatusBlock; AttachedDevice = NULL; psrbIoctl = NULL; irp = NULL; // // get a ScsiPort device or attached one. // AttachedDevice = IoGetAttachedDeviceReference(PdoData->Self); if(AttachedDevice == NULL) { Bus_KdPrint_Def( BUS_DBG_SS_ERROR, ("STATUS_INVALID_DEVICE\n")); return STATUS_NO_SUCH_DEVICE; } // // build an SRB for the miniport // srbIoctlBufferLength = (InputBufferLength>OutputBufferLength)?InputBufferLength:OutputBufferLength; srbIoctlLength = sizeof(SRB_IO_CONTROL) + srbIoctlBufferLength; psrbIoctl = (PSRB_IO_CONTROL)ExAllocatePoolWithTag(NonPagedPool , srbIoctlLength, BUSENUM_POOL_TAG); if(psrbIoctl == NULL) { Bus_KdPrint_Def( BUS_DBG_SS_ERROR, ("STATUS_INSUFFICIENT_RESOURCES\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto cleanup; } RtlZeroMemory(psrbIoctl, srbIoctlLength); psrbIoctl->HeaderLength = sizeof(SRB_IO_CONTROL); RtlCopyMemory(psrbIoctl->Signature, LANSCSIMINIPORT_IOCTL_SIGNATURE, 8); psrbIoctl->Timeout = 60 * 60; psrbIoctl->ControlCode = IoctlCode; psrbIoctl->Length = srbIoctlBufferLength; srbIoctlBuffer = (PUCHAR)psrbIoctl + sizeof(SRB_IO_CONTROL); RtlCopyMemory(srbIoctlBuffer, InputBuffer, InputBufferLength); // // Initialize the notification event. // KeInitializeEvent(&event, NotificationEvent, FALSE); startingOffset.QuadPart = 1; // // Build IRP for this request. // Note we do this synchronously for two reasons. If it was done // asynchonously then the completion code would have to make a special // check to deallocate the buffer. Second if a completion routine were // used then an additional IRP stack location would be needed. // irp = IoBuildSynchronousFsdRequest( IRP_MJ_SCSI, AttachedDevice, psrbIoctl, srbIoctlLength, &startingOffset, &event, &ioStatusBlock); irpStack = IoGetNextIrpStackLocation(irp); if (irp == NULL) { Bus_KdPrint_Def( BUS_DBG_SS_ERROR, ("STATUS_INSUFFICIENT_RESOURCES\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto cleanup; } // // Set major and minor codes. // irpStack->MajorFunction = IRP_MJ_SCSI; irpStack->MinorFunction = 1; // // Fill in SRB fields. // irpStack->Parameters.Others.Argument1 = &srb; // // Zero out the srb. // RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); srb.PathId = 0; srb.TargetId = 0; srb.Lun = 0; srb.Function = SRB_FUNCTION_IO_CONTROL; srb.Length = sizeof(SCSI_REQUEST_BLOCK); srb.SrbFlags = /*SRB_FLAGS_DATA_IN |*/ SRB_FLAGS_NO_QUEUE_FREEZE /*| SRB_FLAGS_BYPASS_FROZEN_QUEUE */; srb.OriginalRequest = irp; // // Set timeout to requested value. // srb.TimeOutValue = psrbIoctl->Timeout; // // Set the data buffer. // srb.DataBuffer = psrbIoctl; srb.DataTransferLength = srbIoctlLength; // // Flush the data buffer for output. This will insure that the data is // written back to memory. Since the data-in flag is the the port driver // will flush the data again for input which will ensure the data is not // in the cache. // /* KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE); */ status = IoCallDriver( AttachedDevice, irp ); // // Wait for request to complete. // if (status == STATUS_PENDING) { (VOID)KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL ); status = ioStatusBlock.Status; } // // get the result // // if(status == STATUS_SUCCESS) { if(OutputBuffer && OutputBufferLength) RtlCopyMemory(OutputBuffer, srbIoctlBuffer, OutputBufferLength); Bus_KdPrint_Def( BUS_DBG_SS_NOISE, ("%d succeeded!\n", IoctlCode)); // } if(psrbIoctl->ControlCode == STATUS_BUFFER_TOO_SMALL) { status = STATUS_BUFFER_TOO_SMALL; } cleanup: if(psrbIoctl) ExFreePool(psrbIoctl); if(AttachedDevice) ObDereferenceObject(AttachedDevice); return status; }
NTSTATUS NCommVerifyNdasDevWithDIB( IN OUT PNDASBUS_ADD_TARGET_DATA AddTargetData, IN PTA_LSTRANS_ADDRESS SecondaryAddress ) { NTSTATUS status; LSSLOGIN_INFO loginInfo; PNDASBUS_UNITDISK unit; TA_LSTRANS_ADDRESS targetAddr; TA_LSTRANS_ADDRESS bindingAddr; TA_LSTRANS_ADDRESS bindingAddr2; TA_LSTRANS_ADDRESS boundAddr; ULONG idx_unit; ULONG fault_cnt; BOOLEAN oriDibValid; UINT32 crcunit = 0; BOOLEAN exitImm; // // check AddTargetData sanity // status = VerifyAddTargetData(AddTargetData); if(!NT_SUCCESS(status)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("VerifyAddTargetData() failed. STATUS=%08lx\n", status)); return status; } // // Start verifying // fault_cnt = 0; oriDibValid = FALSE; exitImm = FALSE; for(idx_unit = 0; idx_unit < AddTargetData->ulNumberOfUnitDiskList; idx_unit++) { Bus_KdPrint_Def(BUS_DBG_SS_INFO, ("== UNIT #%u ==\n", idx_unit)); unit = AddTargetData->UnitDiskList + idx_unit; LSTRANS_COPY_LPXADDRESS(&targetAddr, &unit->Address); LSTRANS_COPY_LPXADDRESS(&bindingAddr, &unit->NICAddr); if(SecondaryAddress) LSTRANS_COPY_LPXADDRESS(&bindingAddr2, &SecondaryAddress->Address[0].Address); BUILD_LOGININFO(&loginInfo, unit); if(unit->ucHWVersion <= LANSCSIIDE_VERSION_2_0) loginInfo.UserID = CONVERT_TO_ROUSERID(loginInfo.UserID); // // Query binding address // if(SecondaryAddress) status = LsuQueryBindingAddress(&boundAddr, &targetAddr, &bindingAddr, &bindingAddr2, TRUE); else status = LsuQueryBindingAddress(&boundAddr, &targetAddr, &bindingAddr, NULL, TRUE); if(!NT_SUCCESS(status)) { unit->LurnOptions |= LURNOPTION_MISSING; fault_cnt ++; Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("LsuQueryBindingAddress() failed. STATUS=%08lx\n", status)); continue; } // // Set the actual binding address. // LSTRANS_COPY_TO_LPXADDRESS(&unit->NICAddr, &boundAddr); RtlCopyMemory(&bindingAddr, &boundAddr, sizeof(TA_LSTRANS_ADDRESS)); // // Read and verify DIB // switch(AddTargetData->ucTargetType) { case NDASSCSI_TYPE_DISK_NORMAL: { PBLOCK_ACCESS_CONTROL_LIST bacl = NULL; union { NDAS_DIB V1; NDAS_DIB_V2 V2; } DIB; status = NCommGetDIBV2( &DIB.V2, &bacl, &loginInfo, unit->ulPhysicalBlocks + NDAS_BLOCK_LOCATION_DIB_V2, unit->ulPhysicalBlocks + NDAS_BLOCK_LOCATION_ENCRYPT, unit->ulPhysicalBlocks + NDAS_BLOCK_LOCATION_BACL, &targetAddr, &bindingAddr, unit->UDMARestrict); if(NT_SUCCESS(status)) { // // Disk information block Version 2 // if(DIB.V2.iMediaType != NMT_SINGLE) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("NORMAL: DIB's disktype mismatch. MediaType:%x\n", DIB.V2.iMediaType)); status = STATUS_OBJECT_TYPE_MISMATCH; break; } // // Verify block access control list // status = NCommVerifyNdasBlockACLWithTargetData(AddTargetData, DIB.V2.BACLSize, bacl); if(!NT_SUCCESS(status)) break; status = STATUS_SUCCESS; } else if(status == STATUS_REVISION_MISMATCH) { // // Disk information block Version 1 // Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("NORMAL: DIBV2 doesn't exist. try DIBV1. NTSTATUS:%08lx\n", status)); status = NCommGetDIBV1( &DIB.V1, &loginInfo, unit->ulPhysicalBlocks + NDAS_BLOCK_LOCATION_DIB_V1, &targetAddr, &bindingAddr, unit->UDMARestrict); if(status == STATUS_REVISION_MISMATCH) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("NORMAL: DIBV1 doesn't exist. Take it Single. NTSTATUS:%08lx\n", status)); status = STATUS_SUCCESS; break; } else if(!NT_SUCCESS(status)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("NORMAL: NCommGetDIBV1() failed. NTSTATUS:%08lx\n", status)); break; } if(DIB.V1.DiskType != NDAS_DIB_DISK_TYPE_SINGLE) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("NORMAL: DIB's disktype mismatch. DiskType:%x\n", DIB.V1.DiskType)); status = STATUS_OBJECT_TYPE_MISMATCH; break; } status = STATUS_SUCCESS; } else { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("NORMAL: NCommGetDIBV2() failed. NTSTATUS:%08lx\n", status)); } break; } case NDASSCSI_TYPE_DISK_RAID1R2: Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("RAID1R2: Not supported.\n")); status = STATUS_NOT_SUPPORTED; break; case NDASSCSI_TYPE_DISK_RAID1R3: { PBLOCK_ACCESS_CONTROL_LIST bacl = NULL; NDAS_DIB_V2 DIBV2; // // Disk information block Version 2 // // // ulPhysicalBlocks can be 0 if mounted in degraded mode. // Temporary fix: Just don't mount. // to do later: read RMD and compare RAID set ID and config set ID. if (unit->ulPhysicalBlocks ==0) { exitImm = TRUE; status = STATUS_OBJECT_TYPE_MISMATCH; break; } status = NCommGetDIBV2( &DIBV2, &bacl, &loginInfo, unit->ulPhysicalBlocks + NDAS_BLOCK_LOCATION_DIB_V2, unit->ulPhysicalBlocks + NDAS_BLOCK_LOCATION_ENCRYPT, unit->ulPhysicalBlocks + NDAS_BLOCK_LOCATION_BACL, &targetAddr, &bindingAddr, unit->UDMARestrict); if(!NT_SUCCESS(status)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("RAID1R3: NCommGetDIBV2() failed. NTSTATUS:%08lx\n", status)); exitImm = TRUE; } if(DIBV2.iMediaType != NdasDevType2DIBType(AddTargetData->ucTargetType)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("RAID1R3: DIBv2's disktype mismatch. MediaType:%x\n", DIBV2.iMediaType)); status = STATUS_OBJECT_TYPE_MISMATCH; exitImm = TRUE; break; } if(DIBV2.nDiskCount != AddTargetData->ulNumberOfUnitDiskList) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("RAID1R3: DIBv2's Diskcount mismatch." " numberofunitdisklist=%u ndiskcount=%u\n", AddTargetData->ulNumberOfUnitDiskList, DIBV2.nDiskCount)); status = STATUS_OBJECT_TYPE_MISMATCH; exitImm = TRUE; break; } if(DIBV2.iSequence != idx_unit) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("RAID1R3: DIBv2's sequence number mismatch." " idx_unit=%u Seq=%u\n", idx_unit, DIBV2.iSequence)); status = STATUS_OBJECT_TYPE_MISMATCH; exitImm = TRUE; break; } // // Compare Unit crc with the other units. // if(oriDibValid == TRUE){ if(DIBV2.crc32_unitdisks != crcunit) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("RAID1R3: DIBv2's unit crc mismatch." " original=%08lx crc unit=%08lx\n", crcunit, DIBV2.crc32_unitdisks)); status = STATUS_OBJECT_TYPE_MISMATCH; exitImm = TRUE; break; } } else { // // Set original DIB information to compare with the rest of units. // crcunit = DIBV2.crc32_unitdisks; oriDibValid = TRUE; Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("RAID1R3: Set original CRC." " original=%08lx\n", crcunit)); } // // Verify block access control list // status = NCommVerifyNdasBlockACLWithTargetData(AddTargetData, DIBV2.BACLSize, bacl); if(!NT_SUCCESS(status)) { exitImm = TRUE; break; } status = STATUS_SUCCESS; break; } case NDASSCSI_TYPE_DISK_RAID4R2: Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("MIRROR: Not supported.\n")); status = STATUS_NOT_SUPPORTED; break; case NDASSCSI_TYPE_DISK_RAID0: case NDASSCSI_TYPE_DISK_RAID4R3: case NDASSCSI_TYPE_DISK_RAID5:{ PBLOCK_ACCESS_CONTROL_LIST bacl = NULL; NDAS_DIB_V2 DIBV2; status = NCommGetDIBV2( &DIBV2, &bacl, &loginInfo, unit->ulPhysicalBlocks + NDAS_BLOCK_LOCATION_DIB_V2, unit->ulPhysicalBlocks + NDAS_BLOCK_LOCATION_ENCRYPT, unit->ulPhysicalBlocks + NDAS_BLOCK_LOCATION_BACL, &targetAddr, &bindingAddr, unit->UDMARestrict); if(status == STATUS_REVISION_MISMATCH) { exitImm = TRUE; break; } if(!NT_SUCCESS(status)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("RAID0/4: could not read DIBV2. NTSTATUS:%x\n", status)); unit->LurnOptions |= LURNOPTION_MISSING; fault_cnt ++; break; } // // Disk information block Version 2 // if(DIBV2.iMediaType != NdasDevType2DIBType(AddTargetData->ucTargetType) || DIBV2.iSequence != idx_unit ) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("RAID0/4: DIBv2's disktype mismatch. MediaType:%x Sequence:%d\n", DIBV2.iMediaType, DIBV2.iSequence)); status = STATUS_OBJECT_TYPE_MISMATCH; exitImm = TRUE; break; } // // Compare Unit crc with the other units. // if(oriDibValid == TRUE){ if(DIBV2.crc32_unitdisks != crcunit) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("RAID0/4: DIBv2's unit crc mismatch." " original=%08lx crc unit=%08lx\n", crcunit, DIBV2.crc32_unitdisks)); status = STATUS_OBJECT_TYPE_MISMATCH; exitImm = TRUE; break; } } else { // // Set original DIB information to compare with the rest of units. // crcunit = DIBV2.crc32_unitdisks; oriDibValid = TRUE; Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("RAID0/4: Set original CRC." " original=%08lx\n", crcunit)); } // // Verify block access control list // status = NCommVerifyNdasBlockACLWithTargetData(AddTargetData, DIBV2.BACLSize, bacl); if(!NT_SUCCESS(status)) { exitImm = TRUE; break; } status = STATUS_SUCCESS; break; } case NDASSCSI_TYPE_DISK_MIRROR: Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("MIRROR: Not supported.\n")); status = STATUS_NOT_SUPPORTED; break; case NDASSCSI_TYPE_DISK_AGGREGATION: { PBLOCK_ACCESS_CONTROL_LIST bacl = NULL; union { NDAS_DIB V1; NDAS_DIB_V2 V2; } DIB; // // Disk information block Version 2 // status = NCommGetDIBV2( &DIB.V2, &bacl, &loginInfo, unit->ulPhysicalBlocks + NDAS_BLOCK_LOCATION_DIB_V2, unit->ulPhysicalBlocks + NDAS_BLOCK_LOCATION_ENCRYPT, unit->ulPhysicalBlocks + NDAS_BLOCK_LOCATION_BACL, &targetAddr, &bindingAddr, unit->UDMARestrict); if(NT_SUCCESS(status)) { if(DIB.V2.iMediaType != NdasDevType2DIBType(AddTargetData->ucTargetType)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("MIRAGR: DIBv2's disktype mismatch. MediaType:%x\n", DIB.V2.iMediaType)); status = STATUS_OBJECT_TYPE_MISMATCH; exitImm = TRUE; break; } if(DIB.V2.nDiskCount != AddTargetData->ulNumberOfUnitDiskList) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("MIRAGR: DIBv2's Diskcount mismatch." " numberofunitdisklist=%u ndiskcount=%u\n", AddTargetData->ulNumberOfUnitDiskList, DIB.V2.nDiskCount)); status = STATUS_OBJECT_TYPE_MISMATCH; exitImm = TRUE; break; } if(DIB.V2.iSequence != idx_unit) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("MIRAGR: DIBv2's sequence number mismatch." " idx_unit=%u Seq=%u\n", idx_unit, DIB.V2.iSequence)); status = STATUS_OBJECT_TYPE_MISMATCH; exitImm = TRUE; break; } // // Verify block access control list // status = NCommVerifyNdasBlockACLWithTargetData(AddTargetData, DIB.V2.BACLSize, bacl); if(!NT_SUCCESS(status)) { exitImm = TRUE; break; } status = STATUS_SUCCESS; } else if(status == STATUS_REVISION_MISMATCH) { // // Disk information block Version 1 // status = NCommGetDIBV1( &DIB.V1, &loginInfo, unit->ulPhysicalBlocks + NDAS_BLOCK_LOCATION_DIB_V1, &targetAddr, &bindingAddr, unit->UDMARestrict); if(!NT_SUCCESS(status)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("MIRAGR: NCommGetDIBV1() failed. NTSTATUS:%08lx\n", status)); // // Set fault_cnt to exit immediately from this loop. // fault_cnt = AddTargetData->ulNumberOfUnitDiskList; break; } if(LagacyMirrAggrType2TargetType(DIB.V1.DiskType) != AddTargetData->ucTargetType) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("MIRAGR: DIBv1's disktype mismatch. Disktype:%x\n", DIB.V1.DiskType)); status = STATUS_OBJECT_TYPE_MISMATCH; exitImm = TRUE; } if(LagacyMirrAggrType2SeqNo(DIB.V1.DiskType) != idx_unit) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("MIRAGR: DIBv1's sequnece mismatch." " DiskType:%x expected seq:%u\n", DIB.V1.DiskType, idx_unit)); status = STATUS_OBJECT_TYPE_MISMATCH; exitImm = TRUE; break; } } else { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("MIRAGR: NCommGetDIBV2() failed. NTSTATUS:%08lx\n", status)); exitImm = TRUE; } status = STATUS_SUCCESS; break; } case NDASSCSI_TYPE_DVD: case NDASSCSI_TYPE_VDVD: case NDASSCSI_TYPE_MO: status = STATUS_SUCCESS; break; case NDASSCSI_TYPE_AOD: Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("AOD: Not supported.\n")); status = STATUS_NOT_SUPPORTED; break; default: status = STATUS_OBJECT_TYPE_MISMATCH; Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Invalid target type.\n")); break; } if(exitImm) { Bus_KdPrint_Def(BUS_DBG_SS_INFO, ("Exit from this verification loop immediately.\n")); break; } } // Online-recoverable RAIDs. // Even if only one is successfully detected, // go ahead to the plug-in process. // Bus_KdPrint_Def(BUS_DBG_SS_INFO, ("Fault count = %u\n", fault_cnt)); if(AddTargetData->ucTargetType == NDASSCSI_TYPE_DISK_RAID1R3 || AddTargetData->ucTargetType == NDASSCSI_TYPE_DISK_RAID4R3 || AddTargetData->ucTargetType == NDASSCSI_TYPE_DISK_RAID5 ) { #if 0 // // Boot-up mount policy: Do not mount if any of the member is missing // if (fault_cnt !=0) { status = STATUS_UNSUCCESSFUL; Bus_KdPrint_Def(BUS_DBG_SS_INFO, ("Member is missing. Denying auto mount.\n")); } #else // // Boot-up mount policy: Do not mount if any of the member is missing // if (fault_cnt !=0) { status = STATUS_UNSUCCESSFUL; Bus_KdPrint_Def(BUS_DBG_SS_INFO, ("Member is missing. Denying auto mount.\n")); } #endif } else { // // Check the fault counter because RAID0 may set status to SUCCESS // even if a member is in fault. // if(NT_SUCCESS(status)) { if(fault_cnt) { status = STATUS_UNSUCCESSFUL; Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Fault count=%u.\n", fault_cnt)); } } } return status; }
NTSTATUS GetPhyDeviceName( PDEVICE_OBJECT PhysicalDeviceObject, PWCHAR *DeviceName, PUSHORT DeviceNameLen ){ PWCHAR deviceName = NULL; ULONG nameLength; NTSTATUS status; status = IoGetDeviceProperty ( PhysicalDeviceObject, DevicePropertyPhysicalDeviceObjectName, 0, NULL, &nameLength); if (status != STATUS_BUFFER_TOO_SMALL) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR,("IoGetDeviceProperty failed (0x%x)\n", status)); goto Error; } deviceName = ExAllocatePoolWithTag (NonPagedPool, nameLength, BUSENUM_POOL_TAG); if (NULL == deviceName) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("no memory to alloc for deviceName(0x%x)\n", nameLength)); status = STATUS_INSUFFICIENT_RESOURCES; goto Error; } status = IoGetDeviceProperty ( PhysicalDeviceObject, DevicePropertyPhysicalDeviceObjectName, nameLength, deviceName, &nameLength); if (!NT_SUCCESS (status)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("IoGetDeviceProperty(2) failed (0x%x)", status)); goto Error; } Bus_KdPrint_Def(BUS_DBG_SS_INFO, ("%x (%ws) \n", PhysicalDeviceObject, deviceName)); // // Set return values // *DeviceName = deviceName; *DeviceNameLen = (USHORT)nameLength; Error: if(!NT_SUCCESS(status)) { if(deviceName) ExFreePool(deviceName); } return status; }
NTSTATUS NCommGetDIBV2( OUT PNDAS_DIB_V2 DiskInformationBlock, OUT PBLOCK_ACCESS_CONTROL_LIST *BlockACL, IN PLSSLOGIN_INFO LoginInfo, IN UINT64 DIBAddress, IN UINT64 EncryptInfoBlockAddr, IN UINT64 BaclBlockAddr, IN PTA_LSTRANS_ADDRESS NodeAddress, IN PTA_LSTRANS_ADDRESS BindingAddress, IN UCHAR UdmaRestrict ) { PLANSCSI_SESSION LSS; NTSTATUS status; LSTRANS_TYPE LstransType; ULONG pduFlags; BOOLEAN dma; ULONG bytesOfBlock; UNREFERENCED_PARAMETER(EncryptInfoBlockAddr); LSS = (PLANSCSI_SESSION)ExAllocatePoolWithTag(NonPagedPool, sizeof(LANSCSI_SESSION), NCOMM_POOLTAG_LSS); if(!LSS) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("ExAllocatePoolWithTag() failed.\n")); return STATUS_INSUFFICIENT_RESOURCES; } // // Connect and log in. // status = LsuConnectLogin( LSS, NodeAddress, BindingAddress, LoginInfo, &LstransType); if(!NT_SUCCESS(status)) { ExFreePool(LSS); Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("LsuConnectLogin() failed. NTSTATUS: %08lx.\n", status)); return status; } do { status = LsuConfigureIdeDisk(LSS, UdmaRestrict, &pduFlags, &dma, &bytesOfBlock); if(!NT_SUCCESS(status)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("IdeConfigure() failed. NTSTATUS: %08lx.\n", status)); break; } if(dma == FALSE) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Disk does not support DMA. DMA required.\n")); status = STATUS_INSUFFICIENT_RESOURCES; break; } // // Read information block // Bus_KdPrint_Def(BUS_DBG_SS_INFO, ("DIB addr=%I64u\n", DIBAddress)); status = LsuGetDiskInfoBlockV2( LSS, DiskInformationBlock, DIBAddress, bytesOfBlock, pduFlags ); // // Read Block ACL // if(NT_SUCCESS(status) && DiskInformationBlock->BACLSize) { PBLOCK_ACCESS_CONTROL_LIST bacl; // // Allocate memory for BACL. Caller take charge in freeing it. // bacl = ExAllocatePoolWithTag( NonPagedPool, DiskInformationBlock->BACLSize, NCOMM_POOLTAG_BACL); if(bacl == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } status = LsuGetBlockACL( LSS, bacl, DiskInformationBlock->BACLSize, BaclBlockAddr, bytesOfBlock, pduFlags); if(NT_SUCCESS(status)) { *BlockACL = bacl; } else { *BlockACL = NULL; ExFreePoolWithTag(bacl, NCOMM_POOLTAG_BACL); } } } while(0); LspLogout(LSS, NULL); LspDisconnect(LSS); ExFreePool(LSS); return status; }
NTSTATUS NCommGetDIBV1( OUT PNDAS_DIB DiskInformationBlock, IN PLSSLOGIN_INFO LoginInfo, IN UINT64 DIBAddress, IN PTA_LSTRANS_ADDRESS NodeAddress, IN PTA_LSTRANS_ADDRESS BindingAddress, IN UCHAR UdmaRestrict ) { PLANSCSI_SESSION LSS; NTSTATUS status; LSTRANS_TYPE LstransType; ULONG pduFlags; BOOLEAN dma; ULONG bytesOfBlock; LSS = (PLANSCSI_SESSION)ExAllocatePoolWithTag(NonPagedPool, sizeof(LANSCSI_SESSION), NCOMM_POOLTAG_LSS); if(!LSS) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("ExAllocatePoolWithTag() failed.\n")); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory( LSS, sizeof(LANSCSI_SESSION) ); // // Connect and log in. // status = LsuConnectLogin( LSS, NodeAddress, BindingAddress, LoginInfo, &LstransType); if(!NT_SUCCESS(status)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("LsuConnectLogin() failed. NTSTATUS: %08lx.\n", status)); ExFreePoolWithTag(LSS, NCOMM_POOLTAG_LSS); return status; } status = LsuConfigureIdeDisk(LSS, UdmaRestrict, &pduFlags, &dma, &bytesOfBlock); if(!NT_SUCCESS(status)) { ExFreePoolWithTag(LSS, NCOMM_POOLTAG_LSS); Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("IdeConfigure() failed. NTSTATUS: %08lx.\n", status)); return status; } if(dma == FALSE) { ExFreePoolWithTag(LSS, NCOMM_POOLTAG_LSS); Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Disk does not support DMA. DMA required.\n")); return STATUS_INSUFFICIENT_RESOURCES; } // // Read informaition block // Bus_KdPrint_Def(BUS_DBG_SS_INFO, ("DIB addr=%I64u\n", DIBAddress)); status = LsuGetDiskInfoBlockV1( LSS, DiskInformationBlock, DIBAddress, bytesOfBlock, pduFlags ); LspLogout(LSS, NULL); LspDisconnect(LSS); ExFreePoolWithTag(LSS, NCOMM_POOLTAG_LSS); return status; }
NTSTATUS Bus_CreateClose ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: Some outside source is trying to create a file against us. If this is for the FDO (the bus itself) then the caller is trying to open the proprietary connection to tell us to enumerate or remove a device. If this is for the PDO (an object on the bus) then this is a client that wishes to use the toaster device. Arguments: DeviceObject - pointer to a device object. Irp - pointer to an I/O Request Packet. Return Value: NT status code --*/ { PIO_STACK_LOCATION irpStack; NTSTATUS status; PFDO_DEVICE_DATA fdoData; PAGED_CODE (); Bus_KdPrint_Def (BUS_DBG_SS_TRACE, ("Entered. \n")); fdoData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension; status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Information = 0; Bus_IncIoCount (fdoData); // // If it's not for the FDO. We don't allow create/close on PDO // if (fdoData->IsFDO) { // // Check to see whether the bus is removed // if (fdoData->DevicePnPState == Deleted){ status = STATUS_NO_SUCH_DEVICE; } else { irpStack = IoGetCurrentIrpStackLocation (Irp); switch (irpStack->MajorFunction) { case IRP_MJ_CREATE: Bus_KdPrint_Def (BUS_DBG_SS_TRACE, ("Create \n")); status = STATUS_SUCCESS; break; case IRP_MJ_CLOSE: Bus_KdPrint_Def (BUS_DBG_SS_TRACE, ("Close \n")); status = STATUS_SUCCESS; break; default: break; } } } Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); Bus_DecIoCount (fdoData); return status; }
NTSTATUS QueueUnplugWorker( PFDO_DEVICE_DATA FdoData, ULONG SlotNo ) { NTSTATUS status; PNDBUS_UNPLUGWORKER workItemCtx; Bus_KdPrint_Def(BUS_DBG_SS_TRACE, ("entered.\n")); // // Parameter check // if(!FdoData) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("FdoData NULL!\n")); return STATUS_INVALID_PARAMETER; } // // Allocate worker's context // workItemCtx = (PNDBUS_UNPLUGWORKER)ExAllocatePoolWithTag( NonPagedPool, sizeof(NDBUS_UNPLUGWORKER), NDBUS_POOLTAG_UNPLUGWORKITEM); if(!workItemCtx) { return STATUS_INSUFFICIENT_RESOURCES; } workItemCtx->FdoData = FdoData; workItemCtx->SlotNo = SlotNo; // // Allocate IO work item for NDASBUS's Functional device object. // workItemCtx->IoWorkItem = IoAllocateWorkItem(FdoData->Self); if(workItemCtx->IoWorkItem == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto cleanup; } // // Queue the work item. // IoQueueWorkItem( workItemCtx->IoWorkItem, UnplugWorker, DelayedWorkQueue, workItemCtx ); return STATUS_SUCCESS; cleanup: if(workItemCtx) { ExFreePool(workItemCtx); } return status; }
NTSTATUS DriverEntry ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: Initialize the driver dispatch table. Arguments: DriverObject - pointer to the driver object RegistryPath - pointer to a unicode string representing the path, to driver-specific key in the registry. Return Value: NT Status Code --*/ { NTSTATUS status; ULONG tempUlong; Bus_KdPrint_Def (BUS_DBG_SS_INFO, ("%s, %s\n", __DATE__, __TIME__)); // // Save the RegistryPath for WMI. // Globals.RegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL); Globals.RegistryPath.Length = RegistryPath->Length; Globals.RegistryPath.Buffer = ExAllocatePoolWithTag( PagedPool, Globals.RegistryPath.MaximumLength, BUSENUM_POOL_TAG_DRIVER_REGISTRYPATH ); if (!Globals.RegistryPath.Buffer) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyUnicodeString(&Globals.RegistryPath, RegistryPath); // // Query OS Versions // Globals.bCheckVersion = PsGetVersion( &Globals.MajorVersion, &Globals.MinorVersion, &Globals.BuildNumber, NULL ); if(Globals.bCheckVersion == TRUE) { Bus_KdPrint_Def (BUS_DBG_SS_INFO, ("Checkd Build, Major Ver %d, Minor Ver %d, Build %d\n", Globals.MajorVersion, Globals.MinorVersion, Globals.BuildNumber)); } else { Bus_KdPrint_Def (BUS_DBG_SS_INFO, ("Free Build, Major Ver %d, Minor Ver %d, Build %d\n", Globals.MajorVersion, Globals.MinorVersion, Globals.BuildNumber)); } // // Set entry points into the driver // DriverObject->MajorFunction [IRP_MJ_CREATE] = DriverObject->MajorFunction [IRP_MJ_CLOSE] = Bus_CreateClose; DriverObject->MajorFunction [IRP_MJ_PNP] = Bus_PnP; DriverObject->MajorFunction [IRP_MJ_POWER] = Bus_Power; DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = Bus_IoCtl; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = Bus_SystemControl; DriverObject->DriverUnload = Bus_DriverUnload; DriverObject->DriverExtension->AddDevice = Bus_AddDevice; // // Init mutex // ExInitializeFastMutex(&Globals.Mutex); // // Default setting // Globals.PersistentPdo = TRUE; Globals.LfsFilterInstalled = FALSE; // // Read options in the registry // // Disable persistent PDO option status = DrReadKeyValueInstantly( RegistryPath, BUSENUM_DRVREG_DISABLE_PERSISTENTPDO, REG_DWORD, &tempUlong, sizeof(tempUlong), NULL); if(NT_SUCCESS(status) && tempUlong != 0) { Globals.PersistentPdo = FALSE; Bus_KdPrint_Def (BUS_DBG_SS_INFO, ("Persistent PDO option disabled.\n")); } // // Check to see if LFS filter is installed. // status = LfsFiltDriverServiceExist(); if(NT_SUCCESS(status)) { Globals.LfsFilterInstalled = TRUE; Bus_KdPrint_Def (BUS_DBG_SS_INFO, ("LFS Filter is detected.\n")); } else { Globals.LfsFilterInstalled = FALSE; Bus_KdPrint_Def (BUS_DBG_SS_INFO, ("LFS Filter is not detected. STATUS=%08lx\n", status)); } return STATUS_SUCCESS; }
NTSTATUS DriverEntry ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: Initialize the driver dispatch table. Arguments: DriverObject - pointer to the driver object RegistryPath - pointer to a unicode string representing the path, to driver-specific key in the registry. Return Value: NT Status Code --*/ { Bus_KdPrint_Def (BUS_DBG_SS_INFO, ("%s, %s\n", __DATE__, __TIME__)); // // Save the RegistryPath for WMI. // Globals.RegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL); Globals.RegistryPath.Length = RegistryPath->Length; Globals.RegistryPath.Buffer = ExAllocatePoolWithTag( PagedPool, Globals.RegistryPath.MaximumLength, BUSENUM_POOL_TAG ); if (!Globals.RegistryPath.Buffer) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyUnicodeString(&Globals.RegistryPath, RegistryPath); // Added by jgahn. // Get OS Version. Globals.bCheckVersion = PsGetVersion( &Globals.MajorVersion, &Globals.MinorVersion, &Globals.BuildNumber, NULL ); if(Globals.bCheckVersion == TRUE) { Bus_KdPrint_Def (BUS_DBG_SS_INFO, ("Checkd Build, Major Ver %d, Minor Ver %d, Build %d\n", Globals.MajorVersion, Globals.MinorVersion, Globals.BuildNumber)); } else { Bus_KdPrint_Def (BUS_DBG_SS_INFO, ("Free Build, Major Ver %d, Minor Ver %d, Build %d\n", Globals.MajorVersion, Globals.MinorVersion, Globals.BuildNumber)); } // // Set entry points into the driver // DriverObject->MajorFunction [IRP_MJ_CREATE] = DriverObject->MajorFunction [IRP_MJ_CLOSE] = Bus_CreateClose; DriverObject->MajorFunction [IRP_MJ_PNP] = Bus_PnP; DriverObject->MajorFunction [IRP_MJ_POWER] = Bus_Power; DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = Bus_IoCtl; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = Bus_SystemControl; DriverObject->DriverUnload = Bus_DriverUnload; DriverObject->DriverExtension->AddDevice = Bus_AddDevice; return STATUS_SUCCESS; }
static NTSTATUS LfsFiltOpenControl ( OUT PHANDLE ControlFileHandle, OUT PFILE_OBJECT *ControlFileObject ) { HANDLE controlFileHandle; PFILE_OBJECT controlFileObject; UNICODE_STRING nameString; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatusBlock; NTSTATUS status; Bus_KdPrint_Def(BUS_DBG_SS_TRACE, ("Entered\n")); // // Init object attributes // RtlInitUnicodeString (&nameString, LFSFILT_CTLDEVICE_NAME); InitializeObjectAttributes ( &objectAttributes, &nameString, 0, NULL, NULL ); status = ZwCreateFile( &controlFileHandle, GENERIC_READ, &objectAttributes, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, 0, 0, NULL, // Open as control 0 // ); if (!NT_SUCCESS(status)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("FAILURE, ZwCreateFile returned status code=%x\n", status)); *ControlFileHandle = NULL; *ControlFileObject = NULL; return status; } status = ioStatusBlock.Status; if (!NT_SUCCESS(status)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("FAILURE, IoStatusBlock.Status contains status code=%x\n", status)); *ControlFileHandle = NULL; *ControlFileObject = NULL; return status; } status = ObReferenceObjectByHandle ( controlFileHandle, 0L, NULL, KernelMode, (PVOID *) &controlFileObject, NULL ); if (!NT_SUCCESS(status)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("ObReferenceObjectByHandle() failed. STATUS=%08lx\n", status)); ZwClose(controlFileHandle); *ControlFileHandle = NULL; *ControlFileObject = NULL; return status; } *ControlFileHandle = controlFileHandle; *ControlFileObject = controlFileObject; return status; }
// // Plug in a device on LanscsiBus in KernelMode. // NTSTATUS LSBus_PlugInLSBUSDevice( PFDO_DEVICE_DATA FdoData, ULONG SlotNo, PWCHAR HardwareIDs, LONG HardwareIDLen, ULONG MaxBlocksPerRequest ){ PBUSENUM_PLUGIN_HARDWARE_EX BusDevice; ULONG Length; HANDLE DisconEvent; HANDLE AlarmEvent; NTSTATUS status; // // Create events // status = ZwCreateEvent( &DisconEvent, GENERIC_READ, NULL, NotificationEvent, FALSE ); if(!NT_SUCCESS(status)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("PlugInLSBUSDevice: ZwCreateEvent() failed. Disconnection event.\n")); return status; } status = ZwCreateEvent( &AlarmEvent, GENERIC_READ, NULL, NotificationEvent, FALSE ); if(!NT_SUCCESS(status)) { ZwClose(DisconEvent); Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("PlugInLSBUSDevice: ExAllocatePoolWithTag() failed. AlarmEvent\n")); return status; } // // Build BUSENUM_PLUGIN_HARDWARE_EX structure. // Length = sizeof(BUSENUM_PLUGIN_HARDWARE_EX) + HardwareIDLen; BusDevice = ExAllocatePoolWithTag( PagedPool, Length, LSBUS_POOTAG_PLUGIN ); if(!BusDevice) { ZwClose(DisconEvent); ZwClose(AlarmEvent); Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("PlugInLSBUSDevice: ExAllocatePoolWithTag() failed.\n")); return STATUS_INSUFFICIENT_RESOURCES; } BusDevice->Size = Length; BusDevice->SlotNo = SlotNo; RtlCopyMemory(BusDevice->HardwareIDs, HardwareIDs, HardwareIDLen); BusDevice->MaxRequestBlocks = MaxBlocksPerRequest; BusDevice->phAlarmEvent = &AlarmEvent; BusDevice->phEvent = &DisconEvent; status = Bus_PlugInDeviceEx(BusDevice, Length, FdoData, KernelMode); // // Close handle to decrease one reference from events. // ZwClose(AlarmEvent); ZwClose(DisconEvent); ExFreePool(BusDevice); return status; }
// // Query information on LanscsiBus // NTSTATUS LSBus_QueryInformation( PFDO_DEVICE_DATA FdoData, PBUSENUM_QUERY_INFORMATION Query, PBUSENUM_INFORMATION Information, LONG OutBufferLength, PLONG OutBufferLenNeeded ) { NTSTATUS ntStatus; PLIST_ENTRY entry; PPDO_DEVICE_DATA PdoData; ntStatus = STATUS_SUCCESS; *OutBufferLenNeeded = OutBufferLength; PdoData = NULL; // // Acquire the mutex to prevent PdoData ( Device Extension ) to disappear. // KeEnterCriticalRegion(); ExAcquireFastMutex (&FdoData->Mutex); switch(Query->InfoClass) { case INFORMATION_NUMOFPDOS: { ULONG NumOfPDOs; NumOfPDOs = 0; for (entry = FdoData->ListOfPDOs.Flink; entry != &FdoData->ListOfPDOs; entry = entry->Flink) { NumOfPDOs ++; } Information->NumberOfPDOs = NumOfPDOs; break; } case INFORMATION_PDO: { KIRQL oldIrql; for (entry = FdoData->ListOfPDOs.Flink; entry != &FdoData->ListOfPDOs; entry = entry->Flink) { PdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); if(Query->SlotNo == PdoData->SlotNo) { ObReferenceObject(PdoData->Self); break; } PdoData = NULL; } if(PdoData) { KeAcquireSpinLock(&PdoData->LanscsiAdapterPDO.LSDevDataSpinLock, &oldIrql); Bus_KdPrint_Def(BUS_DBG_SS_TRACE, ("Status:%08lx DAcc:%08lx GAcc:%08lx\n", PdoData->LanscsiAdapterPDO.AdapterStatus, PdoData->LanscsiAdapterPDO.DesiredAccess, PdoData->LanscsiAdapterPDO.GrantedAccess )); Information->PdoInfo.AdapterStatus = PdoData->LanscsiAdapterPDO.AdapterStatus; Information->PdoInfo.DesiredAccess = PdoData->LanscsiAdapterPDO.DesiredAccess; Information->PdoInfo.GrantedAccess = PdoData->LanscsiAdapterPDO.GrantedAccess; KeReleaseSpinLock(&PdoData->LanscsiAdapterPDO.LSDevDataSpinLock, oldIrql); ObDereferenceObject(PdoData->Self); } else { Bus_KdPrint_Def(BUS_DBG_SS_NOISE, ("No PDO for SlotNo %d!\n", Query->SlotNo)); ntStatus = STATUS_NO_SUCH_DEVICE; } break; } case INFORMATION_PDOENUM: { LARGE_INTEGER TimeOut; for (entry = FdoData->ListOfPDOs.Flink; entry != &FdoData->ListOfPDOs; entry = entry->Flink) { PdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); if(Query->SlotNo == PdoData->SlotNo) { ObReferenceObject(PdoData->Self); break; } PdoData = NULL; } ExReleaseFastMutex (&FdoData->Mutex); KeLeaveCriticalRegion(); if(!PdoData) { KeEnterCriticalRegion(); ExAcquireFastMutex (&FdoData->Mutex); ntStatus = STATUS_NO_SUCH_DEVICE; break; } // // Wait until LDServ sends AddTargetData. // Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("waiting for AddTargetEvent.\n")); TimeOut.QuadPart = -10 * 1000 * 1000 * 120; // 120 seconds ntStatus = KeWaitForSingleObject( &PdoData->LanscsiAdapterPDO.AddTargetEvent, Executive, KernelMode, FALSE, &TimeOut ); if(ntStatus != STATUS_SUCCESS) { KeEnterCriticalRegion(); ExAcquireFastMutex (&FdoData->Mutex); Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("failed to wait for AddTargetEvent.\n")); ntStatus = STATUS_NO_SUCH_DEVICE; ObDereferenceObject(PdoData->Self); break; } Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Completed to wait for AddTargetEvent.\n")); KeEnterCriticalRegion(); ExAcquireFastMutex (&FdoData->Mutex); if(PdoData) { if(PdoData->LanscsiAdapterPDO.Flags & LSDEVDATA_FLAG_LURDESC) { // // A LUR descriptor is set. // if(PdoData->LanscsiAdapterPDO.AddDevInfo == NULL) { ntStatus = STATUS_NO_SUCH_DEVICE; ObDereferenceObject(PdoData->Self); break; } *OutBufferLenNeeded = FIELD_OFFSET(BUSENUM_INFORMATION, PdoEnumInfo) + FIELD_OFFSET(BUSENUM_INFORMATION_PDOENUM, AddDevInfo) + PdoData->LanscsiAdapterPDO.AddDevInfoLength; if(OutBufferLength < *OutBufferLenNeeded) { ntStatus = STATUS_BUFFER_TOO_SMALL; } else { RtlCopyMemory( &Information->PdoEnumInfo.AddDevInfo, PdoData->LanscsiAdapterPDO.AddDevInfo, PdoData->LanscsiAdapterPDO.AddDevInfoLength ); Information->PdoEnumInfo.Flags = PDOENUM_FLAG_LURDESC; Information->PdoEnumInfo.DisconEventToService = PdoData->LanscsiAdapterPDO.DisconEventToService; Information->PdoEnumInfo.AlarmEventToService = PdoData->LanscsiAdapterPDO.AlarmEventToService; Information->PdoEnumInfo.MaxBlocksPerRequest = PdoData->LanscsiAdapterPDO.MaxBlocksPerRequest; } } else { // // ADD_TARGET_DATA is set. // PLANSCSI_ADD_TARGET_DATA AddTargetData; LONG AddTargetLenNeeded; LONG InfoBuffLenNeeded; AddTargetData = PdoData->LanscsiAdapterPDO.AddDevInfo; if(AddTargetData == NULL) { ntStatus = STATUS_NO_SUCH_DEVICE; ObDereferenceObject(PdoData->Self); break; } // // calculate the length needed. // AddTargetLenNeeded = sizeof(LANSCSI_ADD_TARGET_DATA) + (AddTargetData->ulNumberOfUnitDiskList-1)*sizeof(LSBUS_UNITDISK); InfoBuffLenNeeded = sizeof(BUSENUM_INFORMATION) - sizeof(BYTE) + (AddTargetLenNeeded); *OutBufferLenNeeded = InfoBuffLenNeeded; if(OutBufferLength < InfoBuffLenNeeded) { ntStatus = STATUS_BUFFER_TOO_SMALL; } else { RtlCopyMemory(&Information->PdoEnumInfo.AddDevInfo, AddTargetData, AddTargetLenNeeded); Information->PdoEnumInfo.Flags = 0; Information->PdoEnumInfo.DisconEventToService = PdoData->LanscsiAdapterPDO.DisconEventToService; Information->PdoEnumInfo.AlarmEventToService = PdoData->LanscsiAdapterPDO.AlarmEventToService; Information->PdoEnumInfo.MaxBlocksPerRequest = PdoData->LanscsiAdapterPDO.MaxBlocksPerRequest; } } } else { ntStatus = STATUS_NO_SUCH_DEVICE; } ObDereferenceObject(PdoData->Self); break; } case INFORMATION_PDOEVENT: { for (entry = FdoData->ListOfPDOs.Flink; entry != &FdoData->ListOfPDOs; entry = entry->Flink) { PdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); if(Query->SlotNo == PdoData->SlotNo) { ObReferenceObject(PdoData->Self); break; } PdoData = NULL; } if(PdoData == NULL) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Could not find the PDO:%u.\n", Query->SlotNo)); ntStatus = STATUS_NO_SUCH_DEVICE; break; } if( Query->Flags & LSBUS_QUERYFLAG_USERHANDLE) { Information->PdoEvents.SlotNo = PdoData->SlotNo; Information->PdoEvents.Flags = LSBUS_QUERYFLAG_USERHANDLE; // // Get user-mode event handles. // ntStatus = ObOpenObjectByPointer( PdoData->LanscsiAdapterPDO.DisconEventToService, 0, NULL, GENERIC_READ, *ExEventObjectType, UserMode, &Information->PdoEvents.DisconEvent ); if(!NT_SUCCESS(ntStatus)) { ObDereferenceObject(PdoData->Self); Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Could not open Disconnect event object!!\n")); break; } ntStatus = ObOpenObjectByPointer( PdoData->LanscsiAdapterPDO.AlarmEventToService, 0, NULL, GENERIC_READ, *ExEventObjectType, UserMode, &Information->PdoEvents.AlarmEvent ); if(!NT_SUCCESS(ntStatus)) { ObDereferenceObject(PdoData->Self); Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("Could not open Disconnect event object!!\n")); break; } } else { Information->PdoEvents.SlotNo = PdoData->SlotNo; Information->PdoEvents.Flags = 0; Information->PdoEvents.DisconEvent = PdoData->LanscsiAdapterPDO.DisconEventToService; Information->PdoEvents.AlarmEvent = PdoData->LanscsiAdapterPDO.AlarmEventToService; } ObDereferenceObject(PdoData->Self); break; } case INFORMATION_ISREGISTERED: { HANDLE DeviceReg; HANDLE NdasDeviceReg; ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); DeviceReg = NULL; NdasDeviceReg = NULL; ntStatus = Reg_OpenDeviceRegistry(FdoData->UnderlyingPDO, &DeviceReg, KEY_READ|KEY_WRITE); if(!NT_SUCCESS(ntStatus)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("ISREGISTERED: OpenServiceRegistry() failed.\n")); break; } ntStatus = Reg_OpenNdasDeviceRegistry(&NdasDeviceReg, KEY_READ|KEY_WRITE, DeviceReg); if(!NT_SUCCESS(ntStatus)) { ZwClose(DeviceReg); Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("ISREGISTERED: OpenNdasDeviceRegistry() failed.\n")); break; } ntStatus = Reg_LookupRegDeviceWithSlotNo(NdasDeviceReg, Query->SlotNo, &DeviceReg); if(NT_SUCCESS(ntStatus)) { ZwClose(DeviceReg); Information->IsRegistered = 1; Bus_KdPrint_Def(BUS_DBG_SS_INFO, ("ISREGISTERED: Device(%d) is registered.\n", Query->SlotNo)); } else { Information->IsRegistered = 0; Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("ISREGISTERED: Could not find a Device(%d).\n", Query->SlotNo)); } if(NdasDeviceReg) ZwClose(NdasDeviceReg); if(DeviceReg) ZwClose(DeviceReg); break; } case INFORMATION_PDOSLOTLIST: { LONG outputLength; LONG entryCnt; if(OutBufferLength < FIELD_OFFSET(BUSENUM_INFORMATION, PdoSlotList)) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("PDOSLOTLIST: Buffer size is less than required\n")); ntStatus = STATUS_INVALID_PARAMETER; break; } Information->Size = 0; Information->InfoClass = INFORMATION_PDOSLOTLIST; // // Add the size of information header. // outputLength = FIELD_OFFSET(BUSENUM_INFORMATION, PdoSlotList); outputLength += sizeof(UINT32); // SlotNoCnt entryCnt = 0; for (entry = FdoData->ListOfPDOs.Flink; entry != &FdoData->ListOfPDOs; entry = entry->Flink) { PdoData = CONTAINING_RECORD(entry, PDO_DEVICE_DATA, Link); // // Add the size of each slot entry. // outputLength += sizeof(UINT32); if(outputLength > OutBufferLength) { continue; } Information->PdoSlotList.SlotNo[entryCnt] = PdoData->SlotNo; Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("PDOSLOTLIST: Entry #%u: %u\n", entryCnt, PdoData->SlotNo)); entryCnt ++; } if(outputLength > OutBufferLength) { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("PDOSLOTLIST: Could not find a Device(%d).\n", Query->SlotNo)); *OutBufferLenNeeded = outputLength; ntStatus = STATUS_BUFFER_TOO_SMALL; } else { Bus_KdPrint_Def(BUS_DBG_SS_ERROR, ("PDOSLOTLIST: Entry count:%d.\n", entryCnt)); Information->Size = outputLength; Information->PdoSlotList.SlotNoCnt = entryCnt; *OutBufferLenNeeded = outputLength; } break; } default: ntStatus = STATUS_INVALID_PARAMETER; } ExReleaseFastMutex (&FdoData->Mutex); KeLeaveCriticalRegion(); return ntStatus; }