NTSTATUS MpHwHandlePnP( __in pHW_HBA_EXT pHBAExt, // Adapter device-object extension from port driver. __in PSCSI_PNP_REQUEST_BLOCK pSrb ) { NTSTATUS status = STATUS_SUCCESS; KdPrint2(("PhDskMnt::MpHwHandlePnP: pHBAExt = 0x%p, pSrb = 0x%p\n", pHBAExt, pSrb)); switch(pSrb->PnPAction) { case StorRemoveDevice: status = ImScsiHandleRemoveDevice(pHBAExt, pSrb); break; case StorQueryCapabilities: status = ImScsiHandleQueryCapabilities(pHBAExt, pSrb); break; default: pSrb->SrbStatus = SRB_STATUS_SUCCESS; // Do nothing. } if (STATUS_SUCCESS!=status) { } KdPrint2(("PhDskMnt::MpHwHandlePnP: status = 0x%x\n", status)); return status; } // End MpHwHandlePnP().
LONG ImScsiCompletePendingSrbs( __in pHW_HBA_EXT pHBAExt // Adapter device-object extension from port driver. ) { pMP_WorkRtnParms pWkRtnParms; LONG done = 0; KdPrint2(("PhDskMnt::ImScsiCompletePendingSrbs start. pHBAExt = 0x%p\n", pHBAExt)); for (;;) { PLIST_ENTRY request = ExInterlockedRemoveHeadList(&pMPDrvInfoGlobal->ResponseList, &pMPDrvInfoGlobal->ResponseListLock); if (request == NULL) { LONG was_pending = _InterlockedExchangeAdd((volatile LONG*)&pHBAExt->WorkItems, -done); KdPrint2(("PhDskMnt::ImScsiCompletePendingSrbs finished.\n")); return was_pending - done; } ++done; pWkRtnParms = (pMP_WorkRtnParms)CONTAINING_RECORD(request, MP_WorkRtnParms, ResponseListEntry); KdPrint2(("PhDskMnt::ImScsiCompletePendingSrbs: Completing pWkRtnParms = 0x%p, pSrb = 0x%p\n", pWkRtnParms, pWkRtnParms->pSrb)); ScsiPortNotification(RequestComplete, pWkRtnParms->pHBAExt, pWkRtnParms->pSrb); ScsiPortNotification(NextRequest, pWkRtnParms->pHBAExt); ExFreePoolWithTag(pWkRtnParms, MP_TAG_GENERAL); // Free parm list. } }
NTSTATUS ImScsiGetAdapterDeviceObject() { NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; int i; UNICODE_STRING objname = { 0 }; PFILE_OBJECT file_object = NULL; PDEVICE_OBJECT device_object = NULL; WCHAR objstr[] = L"\\Device\\Scsi\\PhDskMnt00"; if (pMPDrvInfoGlobal->DeviceObject != NULL) return STATUS_SUCCESS; for (i = 0; i < 100; i++) { LARGE_INTEGER wait_time; if ((i & 7) == 7) { wait_time.QuadPart = -1; KeDelayExecutionThread(KernelMode, FALSE, &wait_time); } _snwprintf(objstr, sizeof(objstr)/sizeof(*objstr), L"\\Device\\Scsi\\PhDskMnt%i", i); RtlInitUnicodeString(&objname, objstr); KdPrint2(("PhDskMnt::ImScsiGetAdapterDeviceObject: Attempt to open %ws...\n", objstr)); status = IoGetDeviceObjectPointer(&objname, GENERIC_ALL, &file_object, &device_object); if (!NT_SUCCESS(status)) { KdPrint2(("PhDskMnt::ImScsiGetAdapterDeviceObject: Attempt to open %ws failed: status=0x%x\n", objstr, status)); continue; } if (device_object->DriverObject != pMPDrvInfoGlobal->pDriverObj) { KdPrint2(("PhDskMnt::ImScsiGetAdapterDeviceObject: %ws was not our device.\n", objstr, status)); continue; } pMPDrvInfoGlobal->DeviceObject = device_object; return STATUS_SUCCESS; } if (NT_SUCCESS(status)) KdPrint(("PhDskMnt::ImScsiGetAdapterDeviceObject: Successfully opened %ws.\n", objstr)); else DbgPrint(("PhDskMnt::ImScsiGetAdapterDeviceObject: Could not locate SCSI adapter device object by name.\n")); return status; }
/* Get next channel to be serviced (used in simplex mode only) */ PHW_CHANNEL NTAPI UniataGetNextChannel( IN PHW_CHANNEL chan ) { ULONG c=0, _c; PHW_DEVICE_EXTENSION deviceExtension; ULONG best_c; ULONG cost_c; deviceExtension = chan->DeviceExtension; if(!deviceExtension->simplexOnly) { return chan; } KdPrint2((PRINT_PREFIX "UniataGetNextChannel:\n")); best_c = -1; cost_c = 0; for(_c=0; _c<deviceExtension->NumberChannels; _c++) { c = (_c+deviceExtension->FirstChannelToCheck) % deviceExtension->NumberChannels; chan = &deviceExtension->chan[c]; if(chan->queue_depth && chan->queue_depth * (chan->ChannelSelectWaitCount+1) > cost_c) { best_c = c; cost_c = chan->queue_depth * (chan->ChannelSelectWaitCount+1); } } if(best_c == CHAN_NOT_SPECIFIED) { KdPrint2((PRINT_PREFIX " empty queues\n")); return NULL; } deviceExtension->FirstChannelToCheck = c; for(_c=0; _c<deviceExtension->NumberChannels; _c++) { chan = &deviceExtension->chan[_c]; if(_c == best_c) { chan->ChannelSelectWaitCount = 0; continue; } chan->ChannelSelectWaitCount++; if(!chan->queue_depth) { chan->ChannelSelectWaitCount = 0; } else { chan->ChannelSelectWaitCount++; } } KdPrint2((PRINT_PREFIX " select chan %d\n", best_c)); return &deviceExtension->chan[best_c]; } // end UniataGetNextChannel()
VOID MpHwFreeAdapterResources(__in PVOID DeviceExtension) { PLIST_ENTRY pNextEntry; pHW_HBA_EXT pLclHBAExt; KLOCK_QUEUE_HANDLE LockHandle; KIRQL lowest_assumed_irql = PASSIVE_LEVEL; pHW_HBA_EXT pHBAExt = (pHW_HBA_EXT)DeviceExtension; KdPrint2(("PhDskMnt::MpHwFreeAdapterResources: pHBAExt = 0x%p\n", pHBAExt)); // Free memory allocated for disk ImScsiStopAdapter(pHBAExt, &lowest_assumed_irql); ImScsiAcquireLock(&pMPDrvInfoGlobal->DrvInfoLock, &LockHandle, lowest_assumed_irql); for ( // Go through linked list of HBA extensions. pNextEntry = pMPDrvInfoGlobal->ListMPHBAObj.Flink; pNextEntry != &pMPDrvInfoGlobal->ListMPHBAObj; pNextEntry = pNextEntry->Flink ) { pLclHBAExt = CONTAINING_RECORD(pNextEntry, HW_HBA_EXT, List); if (pLclHBAExt == pHBAExt) { // Is this entry the same as pHBAExt? RemoveEntryList(pNextEntry); pMPDrvInfoGlobal->DrvInfoNbrMPHBAObj--; break; } } ImScsiReleaseLock(&LockHandle, &lowest_assumed_irql); } // End MpHwFreeAdapterResources().
LONG ImScsiCompletePendingSrbs( __in pHW_HBA_EXT pHBAExt, // Adapter device-object extension from port driver. __inout __deref PKIRQL LowestAssumedIrql ) { pMP_WorkRtnParms pWkRtnParms; LONG done = 0; KdPrint2(("PhDskMnt::ImScsiCompletePendingSrbs start. pHBAExt = 0x%p\n", pHBAExt)); for (;;) { KLOCK_QUEUE_HANDLE lock_handle; PLIST_ENTRY request; ImScsiAcquireLock(&pMPDrvInfoGlobal->ResponseListLock, &lock_handle, *LowestAssumedIrql); request = RemoveHeadList(&pMPDrvInfoGlobal->ResponseList); if (request == &pMPDrvInfoGlobal->ResponseList) { request = NULL; } ImScsiReleaseLock(&lock_handle, LowestAssumedIrql); if (request == NULL) { LONG was_pending = _InterlockedExchangeAdd((volatile LONG*)&pHBAExt->WorkItems, -done); KdPrint2(("PhDskMnt::ImScsiCompletePendingSrbs finished.\n")); return was_pending - done; } ++done; pWkRtnParms = (pMP_WorkRtnParms)CONTAINING_RECORD(request, MP_WorkRtnParms, ResponseListEntry); KdPrint2(("PhDskMnt::ImScsiCompletePendingSrbs: Completing pWkRtnParms = 0x%p, pSrb = 0x%p\n", pWkRtnParms, pWkRtnParms->pSrb)); ScsiPortNotification(RequestComplete, pWkRtnParms->pHBAExt, pWkRtnParms->pSrb); ScsiPortNotification(NextRequest, pWkRtnParms->pHBAExt); ExFreePoolWithTag(pWkRtnParms, MP_TAG_GENERAL); // Free parm list. } }
BOOLEAN MpHwInitialize(__in PVOID pHBAExt) { UNREFERENCED_PARAMETER(pHBAExt); KdPrint2(("PhDskMnt::MpHwInitialize: pHBAExt = 0x%p. IRQL=%i\n", pHBAExt, KeGetCurrentIrql())); return TRUE; } // End MpHwInitialize().
VOID ImScsiStopAdapter( __in pHW_HBA_EXT pHBAExt // Adapter device-object extension from port driver. ) { SRB_IMSCSI_REMOVE_DEVICE rem_data = { 0 }; KdPrint2(("PhDskMnt::ImScsiStopAdapter: pHBAExt = 0x%p\n", pHBAExt)); // Remove all devices, using "wildcard" device number. rem_data.DeviceNumber.LongNumber = IMSCSI_ALL_DEVICES; ImScsiRemoveDevice(pHBAExt, &rem_data); KdPrint2(("PhDskMnt::ImScsiStopAdapter End.\n")); return; } // End ImScsiStopAdapter().
NTSTATUS AWEAllocClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION io_stack = IoGetCurrentIrpStackLocation(Irp); POBJECT_CONTEXT context = io_stack->FileObject->FsContext2; KdPrint(("AWEAlloc: Close.\n")); PAGED_CODE(); if (context != NULL) { PBLOCK_DESCRIPTOR block = context->FirstBlock; KdPrint2(("AWEAlloc: Freeing context data. First block=%p\n", block)); if (context->CurrentMdl != NULL) IoFreeMdl(context->CurrentMdl); while (block != NULL) { PBLOCK_DESCRIPTOR next_block = block->NextBlock; KdPrint2(("AWEAlloc: Freeing block=%p mdl=%p.\n", block, block->Mdl)); MmFreePagesFromMdl(block->Mdl); ExFreePool(block->Mdl); ExFreePoolWithTag(block, POOL_TAG); block = next_block; } ExFreePoolWithTag(context, POOL_TAG); } Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; }
VOID ImScsiStopAdapter( __in pHW_HBA_EXT pHBAExt, // Adapter device-object extension from port driver. __inout __deref PKIRQL LowestAssumedIrql ) { DEVICE_NUMBER rem_data; KdPrint2(("PhDskMnt::ImScsiStopAdapter: pHBAExt = 0x%p\n", pHBAExt)); // Remove all devices, using "wildcard" device number. rem_data.LongNumber = IMSCSI_ALL_DEVICES; ImScsiRemoveDevice(pHBAExt, &rem_data, LowestAssumedIrql); KdPrint2(("PhDskMnt::ImScsiStopAdapter End.\n")); return; } // End ImScsiStopAdapter().
VOID MpHwTimer( __in pHW_HBA_EXT pHBAExt ) { ULONG wait = 40000; LONG pending; KdPrint2(("PhDskMnt::MpHwTimer start. pHBAExt = 0x%p\n", pHBAExt)); pending = ImScsiCompletePendingSrbs(pHBAExt); if (pending > 0) { KdPrint2(("PhDskMnt::MpHwTimer finished, %i items pending, restarting in %u µs.\n", pending, wait)); ScsiPortNotification(RequestTimerCall, pHBAExt, MpHwTimer, wait); } else KdPrint2(("PhDskMnt::MpHwTimer finished, nothing left to do.\n")); }
VOID MpHwFreeAdapterResources(__in pHW_HBA_EXT pHBAExt) { PLIST_ENTRY pNextEntry; pHW_HBA_EXT pLclHBAExt; #if defined(_AMD64_) KLOCK_QUEUE_HANDLE LockHandle; #else KIRQL SaveIrql; #endif KdPrint2(("PhDskMnt::MpHwFreeAdapterResources: pHBAExt = 0x%p\n", pHBAExt)); #if defined(_AMD64_) KeAcquireInStackQueuedSpinLock(&pMPDrvInfoGlobal->DrvInfoLock, &LockHandle); #else KeAcquireSpinLock(&pMPDrvInfoGlobal->DrvInfoLock, &SaveIrql); #endif for ( // Go through linked list of HBA extensions. pNextEntry = pMPDrvInfoGlobal->ListMPHBAObj.Flink; pNextEntry != &pMPDrvInfoGlobal->ListMPHBAObj; pNextEntry = pNextEntry->Flink ) { pLclHBAExt = CONTAINING_RECORD(pNextEntry, HW_HBA_EXT, List); if (pLclHBAExt==pHBAExt) { // Is this entry the same as pHBAExt? RemoveEntryList(pNextEntry); pMPDrvInfoGlobal->DrvInfoNbrMPHBAObj--; break; } } #if defined(_AMD64_) KeReleaseInStackQueuedSpinLock(&LockHandle); #else KeReleaseSpinLock(&pMPDrvInfoGlobal->DrvInfoLock, SaveIrql); #endif } // End MpHwFreeAdapterResources().
SCSI_ADAPTER_CONTROL_STATUS MpHwAdapterControl( __in pHW_HBA_EXT pHBAExt, // Adapter device-object extension from port driver. __in SCSI_ADAPTER_CONTROL_TYPE ControlType, __in PVOID pParameters ) { PSCSI_SUPPORTED_CONTROL_TYPE_LIST pCtlTypList; ULONG i; KdPrint2(("PhDskMnt::MpHwAdapterControl: pHBAExt = 0x%p, ControlType = 0x%p, pParameters=0x%p\n", pHBAExt, ControlType, pParameters)); pHBAExt->AdapterState = ControlType; switch (ControlType) { case ScsiQuerySupportedControlTypes: KdPrint2(("PhDskMnt::MpHwAdapterControl: ScsiQuerySupportedControlTypes\n")); // Ggt pointer to control type list pCtlTypList = (PSCSI_SUPPORTED_CONTROL_TYPE_LIST)pParameters; // Cycle through list to set TRUE for each type supported // making sure not to go past the MaxControlType for (i = 0; i < pCtlTypList->MaxControlType; i++) if ( i == ScsiQuerySupportedControlTypes || i == ScsiStopAdapter || i == ScsiRestartAdapter || i == ScsiSetBootConfig || i == ScsiSetRunningConfig ) { pCtlTypList->SupportedTypeList[i] = TRUE; } break; case ScsiStopAdapter: KdPrint2(("PhDskMnt::MpHwAdapterControl: ScsiStopAdapter\n")); // Free memory allocated for disk ImScsiStopAdapter(pHBAExt); break; case ScsiRestartAdapter: KdPrint2(("PhDskMnt::MpHwAdapterControl: ScsiRestartAdapter\n")); /* To Do: Add some function. */ break; case ScsiSetBootConfig: KdPrint2(("PhDskMnt::MpHwAdapterControl: ScsiSetBootConfig\n")); break; case ScsiSetRunningConfig: KdPrint2(("PhDskMnt::MpHwAdapterControl: ScsiSetRunningConfig\n")); break; default: KdPrint2(("PhDskMnt::MpHwAdapterControl: UNKNOWN: 0x%X\n", ControlType)); break; } KdPrint2(("PhDskMnt::MpHwAdapterControl End: status=0x%x\n", ScsiAdapterControlSuccess)); return ScsiAdapterControlSuccess; } // End MpHwAdapterControl().
NTSTATUS AWEAllocReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION io_stack = IoGetCurrentIrpStackLocation(Irp); POBJECT_CONTEXT context = io_stack->FileObject->FsContext2; ULONG length_done = 0; NTSTATUS status; PUCHAR system_buffer; KdPrint2(("AWEAlloc: Read/write request Offset=%#I64x Len=%#x.\n", io_stack->Parameters.Read.ByteOffset, io_stack->Parameters.Read.Length)); if (context == NULL) { KdPrint2(("AWEAlloc: Read/write request on not initialized device.\n")); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } if (context->FirstBlock == NULL) { KdPrint2(("AWEAlloc: Read/write request on not initialized device.\n")); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } if (io_stack->Parameters.Read.ByteOffset.QuadPart > context->VirtualSize) { KdPrint2(("AWEAlloc: Read/write request starting past EOF.\n")); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } if ((io_stack->Parameters.Read.ByteOffset.QuadPart + io_stack->Parameters.Read.Length) > context->VirtualSize) { if (io_stack->MajorFunction == IRP_MJ_WRITE) { IO_STATUS_BLOCK io_status; LARGE_INTEGER new_size; status = AWEAllocTryAcquireProtection(context, TRUE); if (!NT_SUCCESS(status)) { DbgPrint("AWEAlloc: Page table busy.\n"); Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } new_size.QuadPart = io_stack->Parameters.Read.ByteOffset.QuadPart + io_stack->Parameters.Read.Length; new_size.QuadPart = max(new_size.QuadPart, context->VirtualSize); status = AWEAllocSetSize(context, &io_status, &new_size); if (!NT_SUCCESS(status)) { DbgPrint("AWEAlloc: Error growing in-memory file.\n"); Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } AWEAllocReleaseProtection(context, TRUE); } else { io_stack->Parameters.Read.Length = (ULONG) (context->VirtualSize - io_stack->Parameters.Read.ByteOffset.QuadPart); KdPrint2(("AWEAlloc: Read request towards EOF. Len set to %x\n", io_stack->Parameters.Read.Length)); } } if (io_stack->Parameters.Read.Length == 0) { KdPrint2(("AWEAlloc: Zero bytes read/write request.\n")); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } system_buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority); if (system_buffer == NULL) { DbgPrint("AWEAlloc: Failed mapping system buffer.\n"); Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; } KdPrint2(("AWEAlloc: System buffer: %p\n", system_buffer)); status = AWEAllocTryAcquireProtection(context, FALSE); if (!NT_SUCCESS(status)) { DbgPrint("AWEAlloc: Page table is busy.\n"); Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } for (;;) { LONGLONG abs_offset_this_iter = io_stack->Parameters.Read.ByteOffset.QuadPart + length_done; ULONG page_offset_this_iter = AWEAllocGetPageOffsetFromAbsOffset(abs_offset_this_iter); ULONG bytes_this_iter = io_stack->Parameters.Read.Length - length_done; if (length_done >= io_stack->Parameters.Read.Length) { KdPrint2(("AWEAlloc: Nothing left to do.\n")); AWEAllocReleaseProtection(context, FALSE); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = length_done; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } if ((page_offset_this_iter + bytes_this_iter) > ALLOC_PAGE_SIZE) bytes_this_iter = ALLOC_PAGE_SIZE - page_offset_this_iter; status = AWEAllocMapPage(context, abs_offset_this_iter); if (!NT_SUCCESS(status)) { DbgPrint("AWEAlloc: Failed mapping current image page.\n"); AWEAllocReleaseProtection(context, FALSE); Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } KdPrint2(("AWEAlloc: Current image page mdl ptr=%p system ptr=%p.\n", context->CurrentMdl, context->CurrentPtr)); switch (io_stack->MajorFunction) { case IRP_MJ_READ: { KdPrint2(("AWEAlloc: Copying memory image -> I/O buffer.\n")); RtlCopyMemory(system_buffer + length_done, context->CurrentPtr + page_offset_this_iter, bytes_this_iter); break; } case IRP_MJ_WRITE: { KdPrint2(("AWEAlloc: Copying memory image <- I/O buffer.\n")); RtlCopyMemory(context->CurrentPtr + page_offset_this_iter, system_buffer + length_done, bytes_this_iter); break; } } io_stack->FileObject->CurrentByteOffset.QuadPart += bytes_this_iter; KdPrint2(("AWEAlloc: Copy done.\n")); length_done += bytes_this_iter; } }
BOOLEAN MpHwStartIo( __in pHW_HBA_EXT pHBAExt, // Adapter device-object extension from port driver. __in __out PSCSI_REQUEST_BLOCK pSrb ) { UCHAR Result = ResultDone; #ifdef USE_SCSIPORT UCHAR PathId = pSrb->PathId; UCHAR TargetId = pSrb->TargetId; UCHAR Lun = pSrb->Lun; #endif KdPrint2(("PhDskMnt::MpHwStartIo: pHBAExt = 0x%p, pSrb = 0x%p, Path=%i, Target=%i, Lun=%i, IRQL=%i\n", pHBAExt, pSrb, (int) pSrb->PathId, (int) pSrb->TargetId, (int) pSrb->Lun, KeGetCurrentIrql())); pSrb->SrbStatus = SRB_STATUS_PENDING; pSrb->ScsiStatus = SCSISTAT_GOOD; ImScsiCompletePendingSrbs(pHBAExt); _InterlockedExchangeAdd((volatile LONG *)&pHBAExt->SRBsSeen, 1); // Bump count of SRBs encountered. // Next, if true, will cause port driver to remove the associated LUNs if, for example, devmgmt.msc is asked "scan for hardware changes." //if (pHBAExt->bDontReport) //{ // Act as though the HBA/path is gone? // pSrb->SrbStatus = SRB_STATUS_INVALID_LUN; // goto done; //} switch (pSrb->Function) { case SRB_FUNCTION_IO_CONTROL: ScsiIoControl(pHBAExt, pSrb, &Result); break; case SRB_FUNCTION_EXECUTE_SCSI: ScsiExecute(pHBAExt, pSrb, &Result); break; case SRB_FUNCTION_RESET_LOGICAL_UNIT: DbgPrint("PhDskMnt::MpHwStartIo: SRB_FUNCTION_RESET_LOGICAL_UNIT.\n"); pSrb->SrbStatus = ScsiResetLun(pHBAExt, pSrb); break; case SRB_FUNCTION_RESET_DEVICE: DbgPrint("PhDskMnt::MpHwStartIo: SRB_FUNCTION_RESET_DEVICE.\n"); pSrb->SrbStatus = ScsiResetDevice(pHBAExt, pSrb); break; case SRB_FUNCTION_RESET_BUS: DbgPrint("PhDskMnt::MpHwStartIo: SRB_FUNCTION_RESET_BUS.\n"); pSrb->SrbStatus = MpHwResetBus(pHBAExt, pSrb->PathId); break; case SRB_FUNCTION_PNP: MpHwHandlePnP(pHBAExt, (PSCSI_PNP_REQUEST_BLOCK)pSrb); break; case SRB_FUNCTION_POWER: KdPrint(("PhDskMnt::MpHwStartIo: SRB_FUNCTION_POWER.\n")); // Do nothing. pSrb->SrbStatus = SRB_STATUS_SUCCESS; break; case SRB_FUNCTION_SHUTDOWN: KdPrint(("PhDskMnt::MpHwStartIo: SRB_FUNCTION_SHUTDOWN.\n")); // Do nothing. pSrb->SrbStatus = SRB_STATUS_SUCCESS; break; default: KdPrint(("PhDskMnt::MpHwStartIo: Unknown pSrb Function = 0x%x\n", pSrb->Function)); ScsiSetCheckCondition(pSrb, SRB_STATUS_ERROR, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ADSENSE_ILLEGAL_COMMAND, 0); break; } // switch (pSrb->Function) if (Result == ResultDone) { // Complete now? // Note: A miniport with real hardware would not always be calling RequestComplete from HwScsiStartIo. Rather, // the miniport would typically be doing real I/O and would call RequestComplete only at the end of that // real I/O, in its HwScsiInterrupt or in a DPC routine. #ifdef USE_SCSIPORT KdPrint2(("PhDskMnt::MpHwStartIo sending 'RequestComplete', 'NextRequest' and 'NextLuRequest' to ScsiPort.\n")); ScsiPortNotification(RequestComplete, pHBAExt, pSrb); ScsiPortNotification(NextRequest, pHBAExt); ScsiPortNotification(NextLuRequest, pHBAExt, 0, 0, 0); #endif #ifdef USE_STORPORT KdPrint2(("PhDskMnt::MpHwStartIo sending 'RequestComplete' to port StorPort.\n")); StorPortNotification(RequestComplete, pHBAExt, pSrb); #endif } else { #ifdef USE_SCSIPORT _InterlockedExchangeAdd((volatile LONG*)&pHBAExt->WorkItems, 1); KdPrint2(("PhDskMnt::MpHwStartIo sending 'RequestTimerCall' and 'NextLuRequest' to ScsiPort.\n")); ScsiPortNotification(RequestTimerCall, pHBAExt, MpHwTimer, (ULONG) 1); ScsiPortNotification(NextLuRequest, pHBAExt, PathId, TargetId, Lun); ScsiPortNotification(NextLuRequest, pHBAExt, 0, 0, 0); #endif } KdPrint2(("PhDskMnt::MpHwStartIo End.\n")); return TRUE; } // End MpHwStartIo().
NTSTATUS AWEAllocQueryInformation(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION io_stack = IoGetCurrentIrpStackLocation(Irp); POBJECT_CONTEXT context = io_stack->FileObject->FsContext2; PAGED_CODE(); KdPrint2(("AWEAlloc: QueryFileInformation: %u.\n", io_stack->Parameters.QueryFile.FileInformationClass)); RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, io_stack->Parameters.QueryFile.Length); switch (io_stack->Parameters.QueryFile.FileInformationClass) { case FileAlignmentInformation: { PFILE_ALIGNMENT_INFORMATION alignment_info = (PFILE_ALIGNMENT_INFORMATION) Irp->AssociatedIrp.SystemBuffer; if (io_stack->Parameters.QueryFile.Length < sizeof(FILE_ALIGNMENT_INFORMATION)) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_PARAMETER; } alignment_info->AlignmentRequirement = FILE_BYTE_ALIGNMENT; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION); IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } case FileAttributeTagInformation: case FileBasicInformation: case FileInternalInformation: Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = io_stack->Parameters.QueryFile.Length; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; case FileNetworkOpenInformation: { PFILE_NETWORK_OPEN_INFORMATION network_open_info = (PFILE_NETWORK_OPEN_INFORMATION) Irp->AssociatedIrp.SystemBuffer; if (io_stack->Parameters.QueryFile.Length < sizeof(FILE_NETWORK_OPEN_INFORMATION)) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } network_open_info->AllocationSize.QuadPart = context->TotalSize; network_open_info->EndOfFile.QuadPart = context->VirtualSize; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(FILE_NETWORK_OPEN_INFORMATION); IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } case FileStandardInformation: { PFILE_STANDARD_INFORMATION standard_info = (PFILE_STANDARD_INFORMATION) Irp->AssociatedIrp.SystemBuffer; if (io_stack->Parameters.QueryFile.Length < sizeof(FILE_STANDARD_INFORMATION)) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_PARAMETER; } standard_info->AllocationSize.QuadPart = context->TotalSize; standard_info->EndOfFile.QuadPart = context->VirtualSize; standard_info->DeletePending = TRUE; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION); IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } case FilePositionInformation: { PFILE_POSITION_INFORMATION position_info = (PFILE_POSITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer; if (io_stack->Parameters.QueryFile.Length < sizeof(FILE_POSITION_INFORMATION)) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_PARAMETER; } position_info->CurrentByteOffset = io_stack->FileObject->CurrentByteOffset; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION); IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } default: KdPrint(("AWEAlloc: Unsupported QueryFile.FileInformationClass: %u\n", io_stack->Parameters.QueryFile.FileInformationClass)); Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_DEVICE_REQUEST; } }
NTSTATUS AWEAllocLoadImageFile(IN POBJECT_CONTEXT Context, IN OUT PIO_STATUS_BLOCK IoStatus, IN PUNICODE_STRING FileName) { OBJECT_ATTRIBUTES object_attributes; NTSTATUS status; HANDLE file_handle = NULL; FILE_STANDARD_INFORMATION file_standard; LARGE_INTEGER offset; PAGED_CODE(); InitializeObjectAttributes(&object_attributes, FileName, OBJ_CASE_INSENSITIVE | OBJ_FORCE_ACCESS_CHECK | OBJ_OPENIF, NULL, NULL); status = ZwOpenFile(&file_handle, SYNCHRONIZE | GENERIC_READ, &object_attributes, IoStatus, FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY | FILE_NO_INTERMEDIATE_BUFFERING | FILE_SYNCHRONOUS_IO_NONALERT); if (!NT_SUCCESS(status)) { KdPrint(("AWEAlloc: ZwOpenFile failed: %#x\n", status)); return status; } status = ZwQueryInformationFile(file_handle, IoStatus, &file_standard, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); if (!NT_SUCCESS(status)) { KdPrint(("AWEAlloc: ZwQueryInformationFile failed: %#x\n", status)); ZwClose(file_handle); return status; } status = AWEAllocSetSize(Context, IoStatus, &file_standard.EndOfFile); if (!NT_SUCCESS(status)) { KdPrint(("AWEAlloc: AWEAllocSetSize failed: %#x\n", status)); ZwClose(file_handle); return status; } for (offset.QuadPart = 0; offset.QuadPart < file_standard.EndOfFile.QuadPart; offset.QuadPart += ALLOC_PAGE_SIZE) { status = AWEAllocMapPage(Context, offset.QuadPart); if (!NT_SUCCESS(status)) { KdPrint(("AWEAlloc: Failed mapping current image page.\n")); IoStatus->Status = status; IoStatus->Information = 0; break; } KdPrint2(("AWEAlloc: Current image page mdl ptr=%p system ptr=%p.\n", Context->CurrentMdl, Context->CurrentPtr)); status = ZwReadFile(file_handle, NULL, NULL, NULL, IoStatus, Context->CurrentPtr, ALLOC_PAGE_SIZE, &offset, NULL); if (!NT_SUCCESS(status)) { KdPrint(("AWEAlloc: ZwReadFile failed on image file.\n")); break; } } ZwClose(file_handle); IoStatus->Information = 0; return status; }
VOID ImScsiWorkerThread(__in PVOID Context) { pHW_LU_EXTENSION pLUExt = (pHW_LU_EXTENSION)Context; pMP_WorkRtnParms pWkRtnParms = NULL; PLIST_ENTRY request_list = NULL; PKSPIN_LOCK request_list_lock = NULL; PKEVENT wait_objects[2] = { NULL }; KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY); if (pLUExt != NULL) { KdPrint(("PhDskMnt::ImScsiWorkerThread: Device worker thread start. pLUExt = 0x%p\n", pLUExt)); request_list = &pLUExt->RequestList; request_list_lock = &pLUExt->RequestListLock; wait_objects[0] = &pLUExt->RequestEvent; // If this is a VM backed disk that should be pre-loaded with an image file // we have to load the contents of that file now before entering the service // loop. if (pLUExt->VMDisk && (pLUExt->ImageFile != NULL)) if (!ImScsiFillMemoryDisk(pLUExt)) KeSetEvent(&pLUExt->StopThread, (KPRIORITY)0, FALSE); } else { KdPrint(("PhDskMnt::ImScsiWorkerThread: Global worker thread start. pLUExt=%p\n", pLUExt)); request_list = &pMPDrvInfoGlobal->RequestList; request_list_lock = &pMPDrvInfoGlobal->RequestListLock; wait_objects[0] = &pMPDrvInfoGlobal->RequestEvent; } wait_objects[1] = &pMPDrvInfoGlobal->StopWorker; for (;;) { PLIST_ENTRY request; KLOCK_QUEUE_HANDLE lock_handle; KIRQL lowest_assumed_irql = PASSIVE_LEVEL; #ifdef USE_SCSIPORT NTSTATUS status = STATUS_SUCCESS; PIRP irp = NULL; ImScsiGetControllerObject(); if (pMPDrvInfoGlobal->ControllerObject != NULL) { KdPrint2(("PhDskMnt::ImScsiWorkerThread: Pre-building IRP for next SMB_IMSCSI_CHECK.\n")); irp = ImScsiBuildCompletionIrp(); } #endif for (;;) { ImScsiAcquireLock(request_list_lock, &lock_handle, lowest_assumed_irql); request = RemoveHeadList(request_list); ImScsiReleaseLock(&lock_handle, &lowest_assumed_irql); if (request != request_list) { break; } if (KeReadStateEvent(&pMPDrvInfoGlobal->StopWorker) || ((pLUExt != NULL) && (KeReadStateEvent(&pLUExt->StopThread)))) { KdPrint(("PhDskMnt::ImScsiWorkerThread shutting down.\n")); if (pLUExt != NULL) { KIRQL lowest_assumed_irql = PASSIVE_LEVEL; ImScsiCleanupLU(pLUExt, &lowest_assumed_irql); } #ifdef USE_SCSIPORT // One last SMB_IMSCSI_CHECK call to flush response queue and free allocated IRP if (irp != NULL) { IoCallDriver(pMPDrvInfoGlobal->ControllerObject, irp); } #endif PsTerminateSystemThread(STATUS_SUCCESS); return; } KdPrint2(("PhDskMnt::ImScsiWorkerThread idle, waiting for request.\n")); KeWaitForMultipleObjects(2, (PVOID*)wait_objects, WaitAny, Executive, KernelMode, FALSE, NULL, NULL); } pWkRtnParms = CONTAINING_RECORD(request, MP_WorkRtnParms, RequestListEntry); KdPrint2(("PhDskMnt::ImScsiWorkerThread got request. pWkRtnParms = 0x%p\n", pWkRtnParms)); // Request to wait for LU worker thread to terminate if (pWkRtnParms->pSrb == NULL) { KdPrint(("PhDskMnt::ImScsiWorkerThread: Request to wait for LU worker thread to exit. pLUExt=%p\n", pWkRtnParms->pLUExt)); if (pWkRtnParms->pLUExt->WorkerThread != NULL) { KeWaitForSingleObject( pWkRtnParms->pLUExt->WorkerThread, Executive, KernelMode, FALSE, NULL); ObDereferenceObject(pWkRtnParms->pLUExt->WorkerThread); pWkRtnParms->pLUExt->WorkerThread = NULL; KdPrint(("PhDskMnt::ImScsiWorkerThread: Worker thread exit. Ready to free LUExt.\n")); } else { KdPrint(("PhDskMnt::ImScsiWorkerThread: Worker not started. Ready to free LUExt.\n")); } ExFreePoolWithTag(pWkRtnParms->pLUExt, MP_TAG_GENERAL); ExFreePoolWithTag(pWkRtnParms, MP_TAG_GENERAL); continue; } ImScsiDispatchWork(pWkRtnParms); #ifdef USE_SCSIPORT KdPrint2(("PhDskMnt::ImScsiWorkerThread: Calling SMB_IMSCSI_CHECK for work: 0x%p.\n", pWkRtnParms)); status = ImScsiCallForCompletion(irp, pWkRtnParms, &lowest_assumed_irql); if (!NT_SUCCESS(status)) DbgPrint("PhDskMnt::ImScsiWorkerThread: IoCallDriver failed: 0x%X for work 0x%p\n", status, pWkRtnParms); else KdPrint2(("PhDskMnt::ImScsiWorkerThread: Finished SMB_IMSCSI_CHECK for work: 0x%p.\n", pWkRtnParms)); #endif #ifdef USE_STORPORT KdPrint2(("PhDskMnt::ImScsiWorkerThread: Sending 'RequestComplete' to StorPort for work: 0x%p.\n", pWkRtnParms)); StorPortNotification(RequestComplete, pWkRtnParms->pHBAExt, pWkRtnParms->pSrb); ExFreePoolWithTag(pWkRtnParms, MP_TAG_GENERAL); KdPrint2(("PhDskMnt::ImScsiWorkerThread: Finished work: 0x%p.\n", pWkRtnParms)); #endif } }
VOID ImScsiDispatchWork( __in pMP_WorkRtnParms pWkRtnParms ) { pHW_HBA_EXT pHBAExt = pWkRtnParms->pHBAExt; pHW_LU_EXTENSION pLUExt = pWkRtnParms->pLUExt; PSCSI_REQUEST_BLOCK pSrb = pWkRtnParms->pSrb; PETHREAD pReqThread = pWkRtnParms->pReqThread; PCDB pCdb = (PCDB)pSrb->Cdb; KdPrint2(("PhDskMnt::ImScsiDispatchWork Action: 0x%X, pSrb: 0x%p, pSrb->DataBuffer: 0x%p pSrb->DataTransferLength: 0x%X\n", (int)pSrb->Cdb[0], pSrb, pSrb->DataBuffer, pSrb->DataTransferLength)); switch (pSrb->Function) { case SRB_FUNCTION_IO_CONTROL: { PSRB_IO_CONTROL srb_io_control = (PSRB_IO_CONTROL)pSrb->DataBuffer; switch (srb_io_control->ControlCode) { case SMP_IMSCSI_CREATE_DEVICE: { // Create new? KIRQL lowest_assumed_irql = PASSIVE_LEVEL; KdPrint(("PhDskMnt::ImScsiDispatchWork: Request to create new device.\n")); ImScsiCreateLU(pHBAExt, pSrb, pReqThread, &lowest_assumed_irql); ObDereferenceObject(pReqThread); } break; default: break; } } break; case SRB_FUNCTION_EXECUTE_SCSI: switch (pSrb->Cdb[0]) { case SCSIOP_READ: case SCSIOP_WRITE: case SCSIOP_READ16: case SCSIOP_WRITE16: { // Read/write? PVOID sysaddress; PVOID buffer; ULONG status; LARGE_INTEGER startingSector; LARGE_INTEGER startingOffset; KLOCK_QUEUE_HANDLE LockHandle; KIRQL lowest_assumed_irql = PASSIVE_LEVEL; if ((pCdb->AsByte[0] == SCSIOP_READ16) | (pCdb->AsByte[0] == SCSIOP_WRITE16)) { REVERSE_BYTES_QUAD(&startingSector, pCdb->CDB16.LogicalBlock); } else { startingSector.QuadPart = 0; REVERSE_BYTES(&startingSector, &pCdb->CDB10.LogicalBlockByte0); } startingOffset.QuadPart = startingSector.QuadPart << pLUExt->BlockPower; KdPrint2(("PhDskMnt::ImScsiDispatchWork starting sector: 0x%I64X\n", startingSector)); status = StoragePortGetSystemAddress(pHBAExt, pSrb, &sysaddress); if ((status != STORAGE_STATUS_SUCCESS) | (sysaddress == NULL)) { DbgPrint("PhDskMnt::ImScsiDispatchWork: StorPortGetSystemAddress failed: status=0x%X address=0x%p translated=0x%p\n", status, pSrb->DataBuffer, sysaddress); pSrb->SrbStatus = SRB_STATUS_ERROR; pSrb->ScsiStatus = SCSISTAT_GOOD; break; } buffer = ExAllocatePoolWithTag(NonPagedPool, pSrb->DataTransferLength, MP_TAG_GENERAL); if (buffer == NULL) { DbgPrint("PhDskMnt::ImScsiDispatchWork: Memory allocation failed.\n"); pSrb->SrbStatus = SRB_STATUS_ERROR; pSrb->ScsiStatus = SCSISTAT_GOOD; break; } else { NTSTATUS status = STATUS_NOT_IMPLEMENTED; /// For write operations, prepare temporary buffer if ((pSrb->Cdb[0] == SCSIOP_WRITE) | (pSrb->Cdb[0] == SCSIOP_WRITE16)) { RtlMoveMemory(buffer, sysaddress, pSrb->DataTransferLength); } if ((pSrb->Cdb[0] == SCSIOP_READ) | (pSrb->Cdb[0] == SCSIOP_READ16)) { status = ImScsiReadDevice(pLUExt, buffer, &startingOffset, &pSrb->DataTransferLength); } else if ((pSrb->Cdb[0] == SCSIOP_WRITE) | (pSrb->Cdb[0] == SCSIOP_WRITE16)) { status = ImScsiWriteDevice(pLUExt, buffer, &startingOffset, &pSrb->DataTransferLength); } if (!NT_SUCCESS(status)) { ExFreePoolWithTag(buffer, MP_TAG_GENERAL); DbgPrint("PhDskMnt::ImScsiDispatchWork: I/O error status=0x%X\n", status); switch (status) { case STATUS_INVALID_BUFFER_SIZE: { DbgPrint("PhDskMnt::ImScsiDispatchWork: STATUS_INVALID_BUFFER_SIZE from image I/O. Reporting SCSI_SENSE_ILLEGAL_REQUEST/SCSI_ADSENSE_INVALID_CDB/0x00.\n"); ScsiSetCheckCondition( pSrb, SRB_STATUS_ERROR, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ADSENSE_INVALID_CDB, 0); break; } case STATUS_DEVICE_BUSY: { DbgPrint("PhDskMnt::ImScsiDispatchWork: STATUS_DEVICE_BUSY from image I/O. Reporting SRB_STATUS_BUSY/SCSI_SENSE_NOT_READY/SCSI_ADSENSE_LUN_NOT_READY/SCSI_SENSEQ_BECOMING_READY.\n"); ScsiSetCheckCondition( pSrb, SRB_STATUS_BUSY, SCSI_SENSE_NOT_READY, SCSI_ADSENSE_LUN_NOT_READY, SCSI_SENSEQ_BECOMING_READY ); break; } default: { ScsiSetError(pSrb, SRB_STATUS_PARITY_ERROR); break; } } break; } /// Fake random disk signature in case mounted read-only, 0xAA55 at end of mbr and 0x00000000 in disk id field. /// Compatibility fix for mounting Windows Backup vhd files in read-only. if ((pLUExt->FakeDiskSignature != 0) && ((pSrb->Cdb[0] == SCSIOP_READ) | (pSrb->Cdb[0] == SCSIOP_READ16)) && (startingSector.QuadPart == 0) && (pSrb->DataTransferLength >= 512) && (pLUExt->ReadOnly)) { PUCHAR mbr = (PUCHAR)buffer; if ((*(PUSHORT)(mbr + 0x01FE) == 0xAA55) & (*(PUSHORT)(mbr + 0x01BC) == 0x0000) & ((*(mbr + 0x01BE) & 0x7F) == 0x00) & ((*(mbr + 0x01CE) & 0x7F) == 0x00) & ((*(mbr + 0x01DE) & 0x7F) == 0x00) & ((*(mbr + 0x01EE) & 0x7F) == 0x00) & ((*(PULONG)(mbr + 0x01B8) == 0x00000000UL))) { DbgPrint("PhDskMnt::ImScsiDispatchWork: Faking disk signature as %#X.\n", pLUExt->FakeDiskSignature); *(PULONG)(mbr + 0x01B8) = pLUExt->FakeDiskSignature; } } /// For write operations, temporary buffer holds read data. /// Copy that to system buffer. if ((pSrb->Cdb[0] == SCSIOP_READ) | (pSrb->Cdb[0] == SCSIOP_READ16)) { RtlMoveMemory(sysaddress, buffer, pSrb->DataTransferLength); } } ImScsiAcquireLock(&pLUExt->LastIoLock, &LockHandle, lowest_assumed_irql); if (pLUExt->LastIoBuffer != NULL) ExFreePoolWithTag(pLUExt->LastIoBuffer, MP_TAG_GENERAL); pLUExt->LastIoStartSector = startingSector.QuadPart; pLUExt->LastIoLength = pSrb->DataTransferLength; pLUExt->LastIoBuffer = buffer; ImScsiReleaseLock(&LockHandle, &lowest_assumed_irql); ScsiSetSuccess(pSrb, pSrb->DataTransferLength); } break; default: { DbgPrint("PhDskMnt::ImScsiDispatchWork unknown function: 0x%X\n", (int)pSrb->Cdb[0]); ScsiSetError(pSrb, SRB_STATUS_INTERNAL_ERROR); } } default: break; } KdPrint2(("PhDskMnt::ImScsiDispatchWork: End pSrb: 0x%p.\n", pSrb)); } // End ImScsiDispatchWork().
NTSTATUS DriverEntry( __in PDRIVER_OBJECT pDrvObj, __in PUNICODE_STRING pRegistryPath ) { NTSTATUS status = STATUS_SUCCESS; #ifdef USE_STORPORT VIRTUAL_HW_INITIALIZATION_DATA hwInitData = { 0 }; #endif #ifdef USE_SCSIPORT HW_INITIALIZATION_DATA hwInitData = { 0 }; #endif pMPDriverInfo pMPDrvInfo; KdPrint2(("PhDskMnt::DriverEntry: Begin.\n")); #ifdef MP_DrvInfo_Inline // Because there's no good way to clean up the allocation of the global driver information, // the global information is kept in an inline structure. pMPDrvInfo = &lclDriverInfo; #else // // Allocate basic miniport driver object (shared across instances of miniport). The pointer is kept in the driver binary's static storage. // // Because there's no good way to clean up the allocation of the global driver information, // the global information will be leaked. This is deemed acceptable since it's not expected // that DriverEntry will be invoked often in the life of a Windows boot. // pMPDrvInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(MPDriverInfo), MP_TAG_GENERAL); if (!pMPDrvInfo) { // No good? status = STATUS_INSUFFICIENT_RESOURCES; goto Done; } #endif pMPDrvInfoGlobal = pMPDrvInfo; // Save pointer in binary's storage. RtlZeroMemory(pMPDrvInfo, sizeof(MPDriverInfo)); // Set pMPDrvInfo's storage to a known state. pMPDrvInfo->pDriverObj = pDrvObj; // Save pointer to driver object. KeInitializeSpinLock(&pMPDrvInfo->DrvInfoLock); // Initialize spin lock. InitializeListHead(&pMPDrvInfo->ListMPHBAObj); // Initialize list head. // Get registry parameters. MpQueryRegParameters(pRegistryPath, &pMPDrvInfo->MPRegInfo); // Set up information for ScsiPortInitialize(). #ifdef USE_STORPORT hwInitData.HwInitializationDataSize = sizeof(VIRTUAL_HW_INITIALIZATION_DATA); #endif #ifdef USE_SCSIPORT #if NT4_COMPATIBLE hwInitData.HwInitializationDataSize = FIELD_OFFSET(HW_INITIALIZATION_DATA, HwAdapterControl); #else hwInitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA); #endif #endif hwInitData.HwInitialize = MpHwInitialize; // Required for all ports. hwInitData.HwStartIo = MpHwStartIo; // Required for all ports. hwInitData.HwFindAdapter = MpHwFindAdapter; // Required for all ports. hwInitData.HwResetBus = MpHwResetBus; // Required for all ports. #ifndef NT4_COMPATIBLE hwInitData.HwAdapterControl = MpHwAdapterControl; // Required for all post NT4 ports. #endif #ifdef USE_STORPORT hwInitData.HwFreeAdapterResources = MpHwFreeAdapterResources; // Required for virtual StorPort. #endif hwInitData.AutoRequestSense = TRUE; hwInitData.TaggedQueuing = TRUE; hwInitData.MultipleRequestPerLu = TRUE; hwInitData.MapBuffers = STORAGE_MAP_BUFFERS_SETTING; hwInitData.DeviceExtensionSize = sizeof(HW_HBA_EXT); hwInitData.SpecificLuExtensionSize = sizeof(PVOID); hwInitData.SrbExtensionSize = sizeof(HW_SRB_EXTENSION); hwInitData.AdapterInterfaceType = STORAGE_INTERFACE_TYPE; status = StoragePortInitialize( // Tell port driver we're here. pDrvObj, pRegistryPath, (PHW_INITIALIZATION_DATA)&hwInitData, NULL ); DbgPrint("PhDskMnt::DriverEntry: StoragePortInitialize returned 0x%x\n", status); if (NT_SUCCESS(status)) { // Register our own unload routine pMPDrvInfo->pChainUnload = pDrvObj->DriverUnload; pDrvObj->DriverUnload = ImScsiUnload; } else { ImScsiFreeGlobalResources(); } KdPrint2(("PhDskMnt::DriverEntry: End. status=0x%x\n", status)); return status; } // End DriverEntry().
ULONG MpHwFindAdapter( __in PVOID DeviceExtension, __in PVOID pReservedArg1, __in PVOID pReservedArg2, #ifdef USE_STORPORT __in PVOID pReservedArg3, #endif __in PCHAR ArgumentString, __in __out PPORT_CONFIGURATION_INFORMATION pConfigInfo, __out PBOOLEAN pBAgain ) { ULONG i, len, status = SP_RETURN_FOUND; PCHAR pChar; pHW_HBA_EXT pHBAExt = (pHW_HBA_EXT)DeviceExtension; NTSTATUS ntstatus; #if defined(_AMD64_) KLOCK_QUEUE_HANDLE LockHandle; #else KIRQL SaveIrql; #endif UNREFERENCED_PARAMETER(pReservedArg1); UNREFERENCED_PARAMETER(pReservedArg2); #ifdef USE_STORPORT UNREFERENCED_PARAMETER(pReservedArg3); #endif UNREFERENCED_PARAMETER(ArgumentString); KdPrint2(("PhDskMnt::MpHwFindAdapter: Arg=%s%s%s, pHBAExt = 0x%p, pConfigInfo = 0x%p, IRQL=%i\n", ArgumentString != NULL ? "\"" : "(", ArgumentString != NULL ? ArgumentString : "null", ArgumentString != NULL ? "\"" : ")", pHBAExt, pConfigInfo, KeGetCurrentIrql())); if (pMPDrvInfoGlobal->GlobalsInitialized) { LARGE_INTEGER wait_time; DbgPrint("PhDskMnt::MpHwFindAdapter: Already initialized.\n"); wait_time.QuadPart = -1000000; KeDelayExecutionThread(KernelMode, FALSE, &wait_time); } KeInitializeSpinLock(&pHBAExt->LUListLock); InitializeListHead(&pHBAExt->LUList); pHBAExt->HostTargetId = (UCHAR)pMPDrvInfoGlobal->MPRegInfo.InitiatorID; #ifdef USE_STORPORT pConfigInfo->VirtualDevice = TRUE; // Inidicate no real hardware. pConfigInfo->SynchronizationModel = StorSynchronizeFullDuplex; #endif pConfigInfo->WmiDataProvider = FALSE; // Indicate WMI provider. pConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE; // Indicate unlimited. pConfigInfo->AlignmentMask = 0x3; // Indicate DWORD alignment. pConfigInfo->CachesData = FALSE; // Indicate miniport wants flush and shutdown notification. pConfigInfo->MaximumNumberOfTargets = SCSI_MAXIMUM_TARGETS; // Indicate maximum targets. pConfigInfo->NumberOfBuses = (UCHAR) pMPDrvInfoGlobal->MPRegInfo.NumberOfBuses; // Indicate number of busses. pConfigInfo->ScatterGather = TRUE; // Indicate scatter-gather (explicit setting needed for Win2003 at least). pConfigInfo->AutoRequestSense = TRUE; pConfigInfo->TaggedQueuing = TRUE; pConfigInfo->MultipleRequestPerLu = TRUE; // Save Vendor Id, Product Id, Revision in device extension. pChar = (PCHAR)pMPDrvInfoGlobal->MPRegInfo.VendorId.Buffer; len = min(8, (pMPDrvInfoGlobal->MPRegInfo.VendorId.Length/2)); for ( i = 0; i < len; i++, pChar+=2) pHBAExt->VendorId[i] = *pChar; pChar = (PCHAR)pMPDrvInfoGlobal->MPRegInfo.ProductId.Buffer; len = min(16, (pMPDrvInfoGlobal->MPRegInfo.ProductId.Length/2)); for ( i = 0; i < len; i++, pChar+=2) pHBAExt->ProductId[i] = *pChar; pChar = (PCHAR)pMPDrvInfoGlobal->MPRegInfo.ProductRevision.Buffer; len = min(4, (pMPDrvInfoGlobal->MPRegInfo.ProductRevision.Length/2)); for ( i = 0; i < len; i++, pChar+=2) pHBAExt->ProductRevision[i] = *pChar; // Add HBA extension to master driver object's linked list. #if defined(_AMD64_) KeAcquireInStackQueuedSpinLock(&pMPDrvInfoGlobal->DrvInfoLock, &LockHandle); #else KeAcquireSpinLock(&pMPDrvInfoGlobal->DrvInfoLock, &SaveIrql); #endif InsertTailList(&pMPDrvInfoGlobal->ListMPHBAObj, &pHBAExt->List); pMPDrvInfoGlobal->DrvInfoNbrMPHBAObj++; #if defined(_AMD64_) KeReleaseInStackQueuedSpinLock(&LockHandle); #else KeReleaseSpinLock(&pMPDrvInfoGlobal->DrvInfoLock, SaveIrql); #endif if (!pMPDrvInfoGlobal->GlobalsInitialized) { HANDLE thread_handle; OBJECT_ATTRIBUTES object_attributes; KeInitializeSpinLock(&pMPDrvInfoGlobal->RequestListLock); InitializeListHead(&pMPDrvInfoGlobal->RequestList); KeInitializeEvent(&pMPDrvInfoGlobal->RequestEvent, SynchronizationEvent, FALSE); #ifdef USE_SCSIPORT KeInitializeSpinLock(&pMPDrvInfoGlobal->ResponseListLock); KeInitializeEvent(&pMPDrvInfoGlobal->ResponseEvent, SynchronizationEvent, FALSE); InitializeListHead(&pMPDrvInfoGlobal->ResponseList); #endif KeInitializeEvent(&pMPDrvInfoGlobal->StopWorker, NotificationEvent, FALSE); pMPDrvInfoGlobal->GlobalsInitialized = TRUE; InitializeObjectAttributes(&object_attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); ntstatus = PsCreateSystemThread( &thread_handle, (ACCESS_MASK) 0L, &object_attributes, NULL, NULL, ImScsiWorkerThread, NULL); if (!NT_SUCCESS(ntstatus)) { DbgPrint("PhDskMnt::ScsiGetLUExtension: Cannot create worker thread. (%#x)\n", ntstatus); status = SP_RETURN_ERROR; } else { ObReferenceObjectByHandle( thread_handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, *PsThreadType, KernelMode, (PVOID*)&pMPDrvInfoGlobal->WorkerThread, NULL ); ZwClose(thread_handle); //for (i = 0; i < pHBAExt->NbrLUNsperHBA; i++) // ImScsiCreateLU(pHBAExt, 0, (UCHAR)i, 0); } } //Done: *pBAgain = FALSE; KdPrint2(("PhDskMnt::MpHwFindAdapter: End, status = 0x%x\n", status)); return status; } // End MpHwFindAdapter().
VOID ScsiIoControl( __in pHW_HBA_EXT pHBAExt, // Adapter device-object extension from port driver. __in PSCSI_REQUEST_BLOCK pSrb, __in PUCHAR pResult, __inout __deref PKIRQL LowestAssumedIrql ) { PSRB_IO_CONTROL srb_io_control = (PSRB_IO_CONTROL)pSrb->DataBuffer; *pResult = ResultDone; if (pSrb->DataTransferLength < sizeof(SRB_IO_CONTROL) || ((srb_io_control->HeaderLength != sizeof(SRB_IO_CONTROL)) | (srb_io_control->HeaderLength + srb_io_control->Length > pSrb->DataTransferLength))) { KdPrint2(("PhDskMnt::ScsiIoControl: Malformed MiniportIOCtl detected.\n", sizeof(srb_io_control->Signature), srb_io_control->Signature)); ScsiSetError(pSrb, SRB_STATUS_INVALID_REQUEST); goto Done; } if (memcmp(srb_io_control->Signature, IMSCSI_FUNCTION_SIGNATURE, sizeof(IMSCSI_FUNCTION_SIGNATURE) - 1)) { KdPrint2(("PhDskMnt::ScsiIoControl: MiniportIOCtl sig '%.*s' not supported\n", sizeof(srb_io_control->Signature), srb_io_control->Signature)); ScsiSetError(pSrb, SRB_STATUS_INVALID_REQUEST); goto Done; } KdPrint2(("PhDskMnt::ScsiIoControl: Miniport IOCtl ControlCode = %#x\n", srb_io_control->ControlCode)); switch (srb_io_control->ControlCode) { case SMP_IMSCSI_CHECK: { KdPrint2(("PhDskMnt::ScsiIoControl: Request to complete SRBs.\n")); srb_io_control->ReturnCode = STATUS_SUCCESS; ScsiSetSuccess(pSrb, 0); break; } case SMP_IMSCSI_CREATE_DEVICE: { PSRB_IMSCSI_CREATE_DATA srb_buffer = (PSRB_IMSCSI_CREATE_DATA)pSrb->DataBuffer; if ((srb_buffer->SrbIoControl.HeaderLength + srb_buffer->SrbIoControl.Length < FIELD_OFFSET(SRB_IMSCSI_CREATE_DATA, Fields.FileName)) || (srb_buffer->Fields.FileNameLength + (ULONG)FIELD_OFFSET(SRB_IMSCSI_CREATE_DATA, Fields.FileName) > pSrb->DataTransferLength)) { KdPrint(("PhDskMnt::ScsiIoControl: Bad SMP_IMSCSI_CREATE_DEVICE request.\n")); ScsiSetError(pSrb, SRB_STATUS_DATA_OVERRUN); goto Done; } ImScsiCreateDevice(pHBAExt, pSrb, pResult, LowestAssumedIrql); break; } case SMP_IMSCSI_REMOVE_DEVICE: { PSRB_IMSCSI_REMOVE_DEVICE srb_buffer = (PSRB_IMSCSI_REMOVE_DEVICE)pSrb->DataBuffer; KdPrint2(("PhDskMnt::ScsiIoControl: Request to remove device.\n")); if (!SRB_IO_CONTROL_SIZE_OK(srb_buffer)) { KdPrint(("PhDskMnt::ScsiIoControl: Bad SMP_IMSCSI_REMOVE_DEVICE request.\n")); ScsiSetError(pSrb, SRB_STATUS_DATA_OVERRUN); goto Done; } srb_io_control->ReturnCode = ImScsiRemoveDevice(pHBAExt, &srb_buffer->DeviceNumber, LowestAssumedIrql); ScsiSetSuccess(pSrb, pSrb->DataTransferLength); break; } case SMP_IMSCSI_QUERY_VERSION: { PSRB_IMSCSI_QUERY_VERSION srb_buffer = (PSRB_IMSCSI_QUERY_VERSION)pSrb->DataBuffer; KdPrint2(("PhDskMnt::ScsiIoControl: Request for driver version.\n")); if (!SRB_IO_CONTROL_SIZE_OK(srb_buffer)) { srb_io_control->ReturnCode = IMSCSI_DRIVER_VERSION; srb_io_control->Length = 0; ScsiSetSuccess(pSrb, pSrb->DataTransferLength); break; } srb_io_control->ReturnCode = IMSCSI_DRIVER_VERSION; srb_io_control->Length = sizeof(*srb_buffer) - sizeof(srb_buffer->SrbIoControl); srb_buffer->SubVersion = PHDSKMNT_VERSION_ULONG; ScsiSetSuccess(pSrb, pSrb->DataTransferLength); break; } case SMP_IMSCSI_QUERY_DEVICE: { PSRB_IMSCSI_CREATE_DATA srb_buffer = (PSRB_IMSCSI_CREATE_DATA)pSrb->DataBuffer; KdPrint2(("PhDskMnt::ScsiIoControl: Request SMP_IMSCSI_QUERY_DEVICE.\n")); if (!SRB_IO_CONTROL_SIZE_OK(srb_buffer)) { KdPrint(("PhDskMnt::ScsiIoControl: Bad SMP_IMSCSI_QUERY_DEVICE request.\n")); pSrb->DataTransferLength = 0; ScsiSetError(pSrb, SRB_STATUS_DATA_OVERRUN); goto Done; } srb_io_control->ReturnCode = ImScsiQueryDevice(pHBAExt, srb_buffer, &pSrb->DataTransferLength, LowestAssumedIrql); ScsiSetSuccess(pSrb, pSrb->DataTransferLength); break; } case SMP_IMSCSI_QUERY_ADAPTER: { PSRB_IMSCSI_QUERY_ADAPTER srb_buffer = (PSRB_IMSCSI_QUERY_ADAPTER)pSrb->DataBuffer; KdPrint2(("PhDskMnt::ScsiIoControl: Request SMP_IMSCSI_QUERY_ADAPTER.\n")); if (!SRB_IO_CONTROL_SIZE_OK(srb_buffer)) { KdPrint(("PhDskMnt::ScsiIoControl: Bad SMP_IMSCSI_QUERY_ADAPTER request.\n")); ScsiSetError(pSrb, SRB_STATUS_DATA_OVERRUN); goto Done; } srb_io_control->ReturnCode = ImScsiQueryAdapter(pHBAExt, srb_buffer, pSrb->DataTransferLength, LowestAssumedIrql); ScsiSetSuccess(pSrb, pSrb->DataTransferLength); break; } case SMP_IMSCSI_SET_DEVICE_FLAGS: { PSRB_IMSCSI_SET_DEVICE_FLAGS srb_buffer = (PSRB_IMSCSI_SET_DEVICE_FLAGS)pSrb->DataBuffer; KdPrint2(("PhDskMnt::ScsiIoControl: Request SMP_IMSCSI_SET_DEVICE_FLAGS.\n")); if (!SRB_IO_CONTROL_SIZE_OK(srb_buffer)) { KdPrint(("PhDskMnt::ScsiIoControl: Bad SMP_IMSCSI_SET_DEVICE_FLAGS request.\n")); ScsiSetError(pSrb, SRB_STATUS_DATA_OVERRUN); goto Done; } srb_io_control->ReturnCode = ImScsiSetFlagsDevice(pHBAExt, srb_buffer, LowestAssumedIrql); ScsiSetSuccess(pSrb, pSrb->DataTransferLength); break; } case SMP_IMSCSI_EXTEND_DEVICE: { PSRB_IMSCSI_EXTEND_DEVICE srb_buffer = (PSRB_IMSCSI_EXTEND_DEVICE)pSrb->DataBuffer; KdPrint2(("PhDskMnt::ScsiIoControl: Request SMP_IMSCSI_EXTEND_DEVICE.\n")); if (!SRB_IO_CONTROL_SIZE_OK(srb_buffer)) { KdPrint(("PhDskMnt::ScsiIoControl: Bad SMP_IMSCSI_EXTEND_DEVICE request.\n")); ScsiSetError(pSrb, SRB_STATUS_DATA_OVERRUN); goto Done; } ImScsiExtendDevice(pHBAExt, pSrb, pResult, LowestAssumedIrql, srb_buffer); break; } default: DbgPrint("PhDskMnt::ScsiExecute: Unknown IOControl code=0x%X\n", srb_io_control->ControlCode); ScsiSetError(pSrb, SRB_STATUS_INVALID_REQUEST); break; } // end switch Done: KdPrint2(("PhDskMnt::ScsiIoControl: End: *Result=%i\n", (INT)*pResult)); return; }
VOID ImScsiCreateDevice( __in pHW_HBA_EXT pHBAExt, __in PSCSI_REQUEST_BLOCK pSrb, __inout __deref PUCHAR pResult, __inout __deref PKIRQL LowestAssumedIrql ) { pHW_LU_EXTENSION pLUExt = NULL; PSRB_IMSCSI_CREATE_DATA new_device = (PSRB_IMSCSI_CREATE_DATA)pSrb->DataBuffer; pMP_WorkRtnParms pWkRtnParms; KLOCK_QUEUE_HANDLE lock_handle; // If auto-selecting device number if (new_device->Fields.DeviceNumber.LongNumber == IMSCSI_AUTO_DEVICE_NUMBER) { KdPrint(("PhDskMnt::ImScsiCreateDevice: Auto-select device number.\n")); for (new_device->Fields.DeviceNumber.PathId = 0; new_device->Fields.DeviceNumber.PathId < pMPDrvInfoGlobal->MPRegInfo.NumberOfBuses; new_device->Fields.DeviceNumber.PathId++) { for (new_device->Fields.DeviceNumber.Lun = 0; new_device->Fields.DeviceNumber.Lun < MAX_LUNS; new_device->Fields.DeviceNumber.Lun++) { for (new_device->Fields.DeviceNumber.TargetId = 0; new_device->Fields.DeviceNumber.TargetId < MAX_TARGETS; new_device->Fields.DeviceNumber.TargetId++) { #ifdef USE_SCSIPORT // With SCSIPORT, reserve device 0:0:0 as control device if (new_device->Fields.DeviceNumber.LongNumber == 0) continue; #endif ScsiGetLUExtension( pHBAExt, &pLUExt, new_device->Fields.DeviceNumber.PathId, new_device->Fields.DeviceNumber.TargetId, new_device->Fields.DeviceNumber.Lun, LowestAssumedIrql ); if (pLUExt == NULL) break; } if (pLUExt == NULL) break; } if (pLUExt == NULL) break; } if (pLUExt != NULL) { KdPrint(("PhDskMnt::ImScsiCreateDevice: No free device number found.\n")); new_device->SrbIoControl.ReturnCode = (ULONG)STATUS_NO_MORE_ENTRIES; ScsiSetSuccess(pSrb, pSrb->DataTransferLength); return; } KdPrint(("PhDskMnt::ImScsiCreateDevice: PathId=%i, TargetId=%i, Lun=%i.\n", (int)new_device->Fields.DeviceNumber.PathId, (int)new_device->Fields.DeviceNumber.TargetId, (int)new_device->Fields.DeviceNumber.Lun)); } else { KdPrint(("PhDskMnt::ImScsiCreateDevice: PathId=%i, TargetId=%i, Lun=%i.\n", (int)new_device->Fields.DeviceNumber.PathId, (int)new_device->Fields.DeviceNumber.TargetId, (int)new_device->Fields.DeviceNumber.Lun)); #ifdef USE_SCSIPORT if (new_device->Fields.DeviceNumber.LongNumber == 0) { DbgPrint("PhDskMnt::ImScsiCreateDevice: Device number 0:0:0 is reserved.\n"); new_device->SrbIoControl.ReturnCode = (ULONG)STATUS_OBJECT_NAME_COLLISION; ScsiSetSuccess(pSrb, pSrb->DataTransferLength); return; } #endif ScsiGetLUExtension( pHBAExt, &pLUExt, new_device->Fields.DeviceNumber.PathId, new_device->Fields.DeviceNumber.TargetId, new_device->Fields.DeviceNumber.Lun, LowestAssumedIrql ); if (pLUExt != NULL) { KdPrint(("PhDskMnt::ImScsiCreateDevice: Device already exists.\n")); new_device->SrbIoControl.ReturnCode = (ULONG)STATUS_OBJECT_NAME_COLLISION; ScsiSetSuccess(pSrb, pSrb->DataTransferLength); return; } } pWkRtnParms = // Allocate parm area for work routine. (pMP_WorkRtnParms)ExAllocatePoolWithTag(NonPagedPool, sizeof(MP_WorkRtnParms), MP_TAG_GENERAL); if (pWkRtnParms == NULL) { DbgPrint("PhDskMnt::ImScsiCreateDevice Failed to allocate work parm structure\n"); new_device->SrbIoControl.ReturnCode = (ULONG)STATUS_INSUFFICIENT_RESOURCES; ScsiSetSuccess(pSrb, pSrb->DataTransferLength); return; } RtlZeroMemory(pWkRtnParms, sizeof(MP_WorkRtnParms)); pWkRtnParms->pHBAExt = pHBAExt; pWkRtnParms->pSrb = pSrb; pWkRtnParms->pReqThread = PsGetCurrentThread(); ObReferenceObject(pWkRtnParms->pReqThread); // Queue work item, which will run in the System process. KdPrint2(("PhDskMnt::ImScsiCreateDevice: Queuing work=0x%p\n", pWkRtnParms)); new_device->SrbIoControl.ReturnCode = (ULONG)STATUS_PENDING; ImScsiAcquireLock(&pMPDrvInfoGlobal->RequestListLock, &lock_handle, *LowestAssumedIrql); InsertTailList(&pMPDrvInfoGlobal->RequestList, &pWkRtnParms->RequestListEntry); ImScsiReleaseLock(&lock_handle, LowestAssumedIrql); KeSetEvent(&pMPDrvInfoGlobal->RequestEvent, (KPRIORITY)0, FALSE); *pResult = ResultQueued; // Indicate queuing. StoragePortNotification(BusChangeDetected, pHBAExt, new_device->Fields.DeviceNumber.PathId); KdPrint(("PhDskMnt::ImScsiCreateDevice: End: *Result=%i\n", *pResult)); return; }
NTSTATUS AWEAllocMapPage(IN POBJECT_CONTEXT Context, IN LONGLONG Offset) { LONGLONG page_base = AWEAllocGetPageBaseFromAbsOffset(Offset); LONGLONG page_base_within_block; ULONG size_to_map = ALLOC_PAGE_SIZE; PBLOCK_DESCRIPTOR block; NTSTATUS status; KdPrint2(("AWEAlloc: MapPage request Offset=%#I64x BaseAddress=%#I64x.\n", Offset, page_base)); if ((Context->CurrentPageBase == page_base) & (Context->CurrentMdl != NULL) & (Context->CurrentPtr != NULL)) { KdPrint2(("AWEAlloc: MapPage: Page already mapped.\n")); return STATUS_SUCCESS; } // Find block that contains this page for (block = Context->FirstBlock; block != NULL; block = block->NextBlock) if (block->Offset <= page_base) break; if (block == NULL) { DbgPrint("AWEAlloc: MapPage: Cannot find blk for BaseAddress=%#I64x.\n", page_base); return STATUS_DRIVER_INTERNAL_ERROR; } page_base_within_block = page_base - block->Offset; KdPrint2(("AWEAlloc: MapPage found blk Offset=%#I64x BaseAddress=%#I64x.\n", block->Offset, page_base_within_block)); status = AWEAllocTryAcquireProtection(Context, TRUE); if (!NT_SUCCESS(status)) { DbgPrint("AWEAlloc: Block table busy.\n"); return status; } Context->CurrentPtr = NULL; Context->CurrentPageBase = (ULONG_PTR)-1; try { try { if (Context->CurrentMdl != NULL) IoFreeMdl(Context->CurrentMdl); Context->CurrentMdl = NULL; Context->CurrentMdl = IoAllocateMdl(MmGetMdlVirtualAddress(block->Mdl), size_to_map, FALSE, FALSE, NULL); if (Context->CurrentMdl == NULL) { DbgPrint("AWEAlloc: IoAllocateMdl() FAILED.\n"); return STATUS_INSUFFICIENT_RESOURCES; } if ((MmGetMdlByteCount(block->Mdl) - page_base_within_block) < size_to_map) { KdPrint (("AWEAlloc: Incomplete page size! Shrinking page size.\n")); size_to_map = 0; // This will map remaining bytes } IoBuildPartialMdl(block->Mdl, Context->CurrentMdl, (PUCHAR) MmGetMdlVirtualAddress(block->Mdl) + page_base_within_block, size_to_map); Context->CurrentPtr = MmGetSystemAddressForMdlSafe(Context->CurrentMdl, HighPagePriority); if (Context->CurrentPtr == NULL) { DbgPrint("AWEAlloc: MmGetSystemAddressForMdlSafe() FAILED.\n"); AWEAllocLogError(AWEAllocDriverObject, 0, 0, NULL, 0, 1000, STATUS_INSUFFICIENT_RESOURCES, 101, STATUS_INSUFFICIENT_RESOURCES, 0, 0, NULL, L"MmGetSystemAddressForMdlSafe() failed during " L"page mapping."); IoFreeMdl(Context->CurrentMdl); Context->CurrentMdl = NULL; return STATUS_INSUFFICIENT_RESOURCES; } Context->CurrentPageBase = page_base; KdPrint2(("AWEAlloc: MapPage success BaseAddress=%#I64x.\n", page_base)); } finally { AWEAllocReleaseProtection(Context, TRUE); } } except (EXCEPTION_EXECUTE_HANDLER) { DbgPrint("AWEAlloc: Exception occured during page mapping.\n"); AWEAllocLogError(AWEAllocDriverObject, 0, 0, NULL, 0, 1000, STATUS_INSUFFICIENT_RESOURCES, 101, STATUS_INSUFFICIENT_RESOURCES, 0, 0, NULL, L"Exception occured during page mapping."); return STATUS_INSUFFICIENT_RESOURCES; } return STATUS_SUCCESS; }
VOID ImScsiExtendDevice( __in pHW_HBA_EXT pHBAExt, __in PSCSI_REQUEST_BLOCK pSrb, __inout __deref PUCHAR pResult, __inout __deref PKIRQL LowestAssumedIrql, __inout __deref PSRB_IMSCSI_EXTEND_DEVICE extend_device_data ) { UCHAR scsi_status; pHW_LU_EXTENSION device_extension; KdPrint(("ImScsi: Request to grow device %i:%i:%i by %I64i bytes.\n", (int)extend_device_data->DeviceNumber.PathId, (int)extend_device_data->DeviceNumber.TargetId, (int)extend_device_data->DeviceNumber.Lun, extend_device_data->ExtendSize.QuadPart)); scsi_status = ScsiGetLUExtension( pHBAExt, &device_extension, extend_device_data->DeviceNumber.PathId, extend_device_data->DeviceNumber.TargetId, extend_device_data->DeviceNumber.Lun, LowestAssumedIrql ); if ((scsi_status != SRB_STATUS_SUCCESS) | (device_extension == NULL)) { extend_device_data->SrbIoControl.ReturnCode = (ULONG)STATUS_OBJECT_NAME_NOT_FOUND; ScsiSetSuccess(pSrb, pSrb->DataTransferLength); return; } if (device_extension->ReadOnly) { extend_device_data->SrbIoControl.ReturnCode = (ULONG)STATUS_MEDIA_WRITE_PROTECTED; ScsiSetSuccess(pSrb, pSrb->DataTransferLength); return; } pMP_WorkRtnParms pWkRtnParms = // Allocate parm area for work routine. (pMP_WorkRtnParms)ExAllocatePoolWithTag(NonPagedPool, sizeof(MP_WorkRtnParms), MP_TAG_GENERAL); if (pWkRtnParms == NULL) { DbgPrint("ImScsi::ImScsiExtendDevice Failed to allocate work parm structure\n"); ScsiSetCheckCondition(pSrb, SRB_STATUS_ERROR, SCSI_SENSE_HARDWARE_ERROR, SCSI_ADSENSE_NO_SENSE, 0); return; } RtlZeroMemory(pWkRtnParms, sizeof(MP_WorkRtnParms)); pWkRtnParms->pHBAExt = pHBAExt; pWkRtnParms->pLUExt = device_extension; pWkRtnParms->pSrb = pSrb; KEVENT wait_event; BOOLEAN wait_result = KeGetCurrentIrql() < DISPATCH_LEVEL; if (wait_result) { KeInitializeEvent(&wait_event, EVENT_TYPE::NotificationEvent, FALSE); pWkRtnParms->CallerWaitEvent = &wait_event; } // Queue work item, which will run in the System process. KLOCK_QUEUE_HANDLE lock_handle; KdPrint2(("PhDskMnt::ImScsiExtendDevice: Queuing work=0x%p\n", pWkRtnParms)); ImScsiAcquireLock(&device_extension->RequestListLock, &lock_handle, *LowestAssumedIrql); InsertTailList(&device_extension->RequestList, &pWkRtnParms->RequestListEntry); ImScsiReleaseLock(&lock_handle, LowestAssumedIrql); KeSetEvent(&device_extension->RequestEvent, (KPRIORITY)0, FALSE); *pResult = ResultQueued; // Indicate queuing. if (wait_result) { KeWaitForSingleObject(&wait_event, KWAIT_REASON::Executive, MODE::KernelMode, FALSE, NULL); } StoragePortNotification(BusChangeDetected, pHBAExt, extend_device_data->DeviceNumber.PathId); return; }
NTSTATUS ImScsiRemoveDevice( __in pHW_HBA_EXT pHBAExt, __in PDEVICE_NUMBER DeviceNumber, __inout __deref PKIRQL LowestAssumedIrql ) { PLIST_ENTRY list_ptr; NTSTATUS status; ULONG count = 0; KLOCK_QUEUE_HANDLE LockHandle; UCHAR pathId = DeviceNumber->PathId; KdPrint(("PhDskMnt::ImScsiRemoveDevice: PathId=%i, TargetId=%i, Lun=%i.\n", (int)DeviceNumber->PathId, (int)DeviceNumber->TargetId, (int)DeviceNumber->Lun)); ImScsiAcquireLock( // Serialize the linked list of LUN extensions. &pHBAExt->LUListLock, &LockHandle, *LowestAssumedIrql); for (list_ptr = pHBAExt->LUList.Flink; list_ptr != &pHBAExt->LUList; list_ptr = list_ptr->Flink ) { pHW_LU_EXTENSION object; object = CONTAINING_RECORD(list_ptr, HW_LU_EXTENSION, List); if ((DeviceNumber->LongNumber == IMSCSI_ALL_DEVICES) | (object->DeviceNumber.LongNumber == DeviceNumber->LongNumber)) { count++; KeSetEvent(&object->StopThread, (KPRIORITY)0, FALSE); KeSetEvent(&object->RequestEvent, (KPRIORITY)0, FALSE); } } ImScsiReleaseLock(&LockHandle, LowestAssumedIrql); if (count == 0) { KdPrint(("PhDskMnt::ImScsiRemoveDevice: Non-existing device.\n")); status = STATUS_OBJECT_NAME_NOT_FOUND; goto Done; } KdPrint(("PhDskMnt::ImScsiRemoveDevice: Found %i device(s).\n", count)); status = STATUS_SUCCESS; if (pathId == 0xFF) pathId = 0x00; StoragePortNotification(BusChangeDetected, pHBAExt, pathId); Done: KdPrint2(("PhDskMnt::ImScsiRemoveDevice: End: status=0x%X, *Result=%i\n", status)); return status; }
BOOLEAN MpHwStartIo( __in PVOID DeviceExtension, // Adapter device-object extension from port driver. __inout __deref PSCSI_REQUEST_BLOCK pSrb ) { KIRQL lowest_assumed_irql = PASSIVE_LEVEL; ResultType Result = ResultDone; pHW_HBA_EXT pHBAExt = (pHW_HBA_EXT)DeviceExtension; #ifdef USE_SCSIPORT UCHAR PathId = pSrb->PathId; UCHAR TargetId = pSrb->TargetId; UCHAR Lun = pSrb->Lun; #endif KdPrint2(("PhDskMnt::MpHwStartIo: pHBAExt = 0x%p, pSrb = 0x%p, Path=%i, Target=%i, Lun=%i, IRQL=%i\n", pHBAExt, pSrb, (int)pSrb->PathId, (int)pSrb->TargetId, (int)pSrb->Lun, KeGetCurrentIrql())); pSrb->SrbStatus = SRB_STATUS_PENDING; pSrb->ScsiStatus = SCSISTAT_GOOD; ImScsiCompletePendingSrbs(pHBAExt, &lowest_assumed_irql); _InterlockedExchangeAdd((volatile LONG *)&pHBAExt->SRBsSeen, 1); // Bump count of SRBs encountered. // Next, if true, will cause port driver to remove the associated LUNs if, for example, devmgmt.msc is asked "scan for hardware changes." //if (pHBAExt->bDontReport) //{ // Act as though the HBA/path is gone? // pSrb->SrbStatus = SRB_STATUS_NO_DEVICE; // goto done; //} switch (pSrb->Function) { case SRB_FUNCTION_IO_CONTROL: ScsiIoControl(pHBAExt, pSrb, &Result, &lowest_assumed_irql); break; case SRB_FUNCTION_EXECUTE_SCSI: if (pSrb->Cdb[0] == SCSIOP_REPORT_LUNS) { ScsiOpReportLuns(pHBAExt, pSrb, &lowest_assumed_irql); } else { ScsiExecute(pHBAExt, pSrb, &Result, &lowest_assumed_irql); } break; case SRB_FUNCTION_RESET_LOGICAL_UNIT: DbgPrint("PhDskMnt::MpHwStartIo: SRB_FUNCTION_RESET_LOGICAL_UNIT.\n"); pSrb->SrbStatus = ScsiResetLun(pHBAExt, pSrb); break; case SRB_FUNCTION_RESET_DEVICE: DbgPrint("PhDskMnt::MpHwStartIo: SRB_FUNCTION_RESET_DEVICE.\n"); pSrb->SrbStatus = ScsiResetDevice(pHBAExt, pSrb); break; case SRB_FUNCTION_RESET_BUS: DbgPrint("PhDskMnt::MpHwStartIo: SRB_FUNCTION_RESET_BUS.\n"); pSrb->SrbStatus = MpHwResetBus(pHBAExt, pSrb->PathId); break; case SRB_FUNCTION_PNP: ScsiPnP(pHBAExt, (PSCSI_PNP_REQUEST_BLOCK)pSrb, &lowest_assumed_irql); break; case SRB_FUNCTION_POWER: KdPrint(("PhDskMnt::MpHwStartIo: SRB_FUNCTION_POWER.\n")); // Do nothing. pSrb->SrbStatus = SRB_STATUS_SUCCESS; break; case SRB_FUNCTION_SHUTDOWN: KdPrint(("PhDskMnt::MpHwStartIo: SRB_FUNCTION_SHUTDOWN.\n")); // Do nothing. pSrb->SrbStatus = SRB_STATUS_SUCCESS; break; default: KdPrint(("PhDskMnt::MpHwStartIo: Unknown pSrb Function = 0x%X\n", pSrb->Function)); //StorPortLogError(pHBAExt, pSrb, pSrb->PathId, pSrb->TargetId, pSrb->Lun, SP_PROTOCOL_ERROR, 0x0200 | pSrb->Cdb[0]); ScsiSetCheckCondition(pSrb, SRB_STATUS_ERROR, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ADSENSE_ILLEGAL_COMMAND, 0); break; } // switch (pSrb->Function) if (Result == ResultDone) { // Complete now? #ifdef USE_SCSIPORT KdPrint2(("PhDskMnt::MpHwStartIo sending 'RequestComplete', 'NextRequest' and 'NextLuRequest' to ScsiPort.\n")); ScsiPortNotification(RequestComplete, pHBAExt, pSrb); ScsiPortNotification(NextRequest, pHBAExt); ScsiPortNotification(NextLuRequest, pHBAExt, 0, 0, 0); #endif #ifdef USE_STORPORT KdPrint2(("PhDskMnt::MpHwStartIo sending 'RequestComplete' to port StorPort.\n")); StorPortNotification(RequestComplete, pHBAExt, pSrb); #endif } else { #ifdef USE_SCSIPORT _InterlockedExchangeAdd((volatile LONG*)&pHBAExt->WorkItems, 1); KdPrint2(("PhDskMnt::MpHwStartIo sending 'RequestTimerCall' and 'NextLuRequest' to ScsiPort.\n")); ScsiPortNotification(RequestTimerCall, pHBAExt, MpHwTimer, (ULONG)1); ScsiPortNotification(NextLuRequest, pHBAExt, PathId, TargetId, Lun); ScsiPortNotification(NextLuRequest, pHBAExt, 0, 0, 0); #endif } KdPrint2(("PhDskMnt::MpHwStartIo End.\n")); return TRUE; } // End MpHwStartIo().
NTSTATUS AWEAllocSetInformation(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION io_stack = IoGetCurrentIrpStackLocation(Irp); POBJECT_CONTEXT context = io_stack->FileObject->FsContext2; PAGED_CODE(); KdPrint2(("AWEAlloc: SetFileInformation: %u.\n", io_stack->Parameters.SetFile.FileInformationClass)); switch (io_stack->Parameters.SetFile.FileInformationClass) { case FileAllocationInformation: case FileEndOfFileInformation: { NTSTATUS status; PFILE_END_OF_FILE_INFORMATION feof_info = (PFILE_END_OF_FILE_INFORMATION) Irp->AssociatedIrp.SystemBuffer; if (io_stack->Parameters.SetFile.Length < sizeof(FILE_END_OF_FILE_INFORMATION)) { Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_BUFFER_TOO_SMALL; } status = AWEAllocTryAcquireProtection(context, TRUE); if (!NT_SUCCESS(status)) { DbgPrint("AWEAlloc: Page table busy.\n"); Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } status = AWEAllocSetSize(context, &Irp->IoStatus, &feof_info->EndOfFile); AWEAllocReleaseProtection(context, TRUE); IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } case FilePositionInformation: { PFILE_POSITION_INFORMATION position_info = (PFILE_POSITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer; if (io_stack->Parameters.SetFile.Length < sizeof(FILE_POSITION_INFORMATION)) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_PARAMETER; } io_stack->FileObject->CurrentByteOffset = position_info->CurrentByteOffset; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } case FileBasicInformation: case FileDispositionInformation: case FileValidDataLengthInformation: Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; default: KdPrint(("AWEAlloc: Unsupported SetFile.FileInformationClass: %u\n", io_stack->Parameters.SetFile.FileInformationClass)); Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_DEVICE_REQUEST; } }