⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vdiskmp.c

📁 SCSI 的虚拟磁盘驱动 需要 windows DDK 很易懂的 DDK 文件结构
💻 C
📖 第 1 页 / 共 5 页
字号:
        // Points to the source or destination buffer to transfer data
        Buf = (PVOID)Request->ParamTransferBuffer;
        // If buffer address is wrong
        if (Buf == NULL)
        {
            KdPrint(("VdiskRequestExecute: Buffer address is wrong!\r\n"));
            Status = STATUS_INVALID_PARAMETER;
            goto Exit;
        }
        // If Storage not allocated
        if (Storage == NULL)
        {
            KdPrint(("VdiskRequestExecute: STATUS_INSUFFICIENT_RESOURCES\r\n"));
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto Exit;
        }
        ASSERT(Storage->FileHandle);
        // Check buffer pointer. It must be aligned.
        if ((ULONG)Buf & (Lun->AlignmentInfo.AlignmentRequirement))
        {
            ULONG BufferSize;
            ULONG RestBufferSize;
            ULONG Offset;
            RestBufferSize = Request->ParamTransferLen*512;
            // Transfer installments of user's buffer
            for (Offset=0; Offset < Request->ParamTransferLen * 512; Offset += PAGE_SIZE)
            {
                if (RestBufferSize <= PAGE_SIZE)
                {
                    // User's buffer is small - read full buffer
                    BufferSize = RestBufferSize;
                }
                else
                {
                    // If user's buffer is bigger then PAGE_SIZE
                    // read page by page
                    BufferSize = PAGE_SIZE;
                }
                IF_1(KdPrint(("VdiskRequestExecute: Buffer 0x%X BufferSize 0x%X!\r\n", 
                    (PUCHAR)Buf+Offset, BufferSize));)
                if (Request->RequestCode==VDISK_REQUEST_WRITE)
                {
                    // Copy data from the user's buffer to the aligned buffer
                    RtlCopyMemory(Lun->AlignedBuf, (PUCHAR)Buf+Offset, BufferSize);
                }
                // Read data from file
                // Uses aligned buffer!
                Status = TransferFunc(Storage->FileHandle, NULL, NULL, NULL, &Iosb,
                                        Lun->AlignedBuf, BufferSize, &Request->Offset,
                                        NULL);
                if (NT_SUCCESS(Status))
                {
                    if (Request->RequestCode==VDISK_REQUEST_READ)
                        // Copy data from the aligned buffer to the user's buffer
                        RtlCopyMemory((PUCHAR)Buf+Offset, Lun->AlignedBuf, BufferSize);
                    // Reduce count of bytes
                    RestBufferSize-=BufferSize;
                    // Return transferred data length
                    ((PSCSI_REQUEST_BLOCK)Request->ParamTransferSrb)->DataTransferLength = Offset + BufferSize;        
                }
                else
                  break;
            } // for
        }
        else
        {
            IF_1(KdPrint(("VdiskRequestExecute: Aligment isn't needed. Buffer 0x%X BufferSize 0x%X!\r\n", 
                    (PUCHAR)Buf, Request->ParamTransferLen * 512));)
            // Read or write data of the file
            // Attention! ZwWriteFile and ZwReadFile isn't fast operation. 
            //            Its are used to simplify this example.
            //            So VspLunTickHandler() resets SCSI bus if its delay.
            Status = TransferFunc(Storage->FileHandle, NULL, NULL, NULL, &Iosb, Buf,
                                    Request->ParamTransferLen * 512, &Request->Offset,
                                    NULL);
            IF_1(KdPrint(("VdiskRequestExecute: Transfer completed. Buffer 0x%X\r\n", (PUCHAR)Buf));)
            // Return transferred data length
            ((PSCSI_REQUEST_BLOCK)Request->ParamTransferSrb)->DataTransferLength = Iosb.Information;        
        }
        // For READ and WRITE next code is identical
        ((PSCSI_REQUEST_BLOCK)Request->ParamTransferSrb)->SrbStatus = SRB_STATUS_SUCCESS;
Exit:
        //  Check status
        if (!NT_SUCCESS(Status))
        {
            KdPrint(("VdiskRequestExecute: Error 0x%X during transfer data!\r\n", Status));
            // If operation was attempted to a volume after it was dismounted
            // block others operation
            if( Status == STATUS_TOO_LATE )
                Lun->Flags |= ( VDISK_LUN_SHUTDOWN | VDISK_LUN_DISMOUNT );
            ((PSCSI_REQUEST_BLOCK)Request->ParamTransferSrb)->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
            // Return sense data
            VdiskFillSenseData(&Lun->SenseData,
                        (PSCSI_REQUEST_BLOCK)Request->ParamTransferSrb, SCSI_ADSENSE_NO_SENSE);
		}
        else
        {
            IF_1(KdPrint(("VdiskRequestExecute: Data has been transferred.\r\n"));)
        }
        // Call completion
        VsPortCompleteRequest(Lun->DeviceExtension, (PSCSI_REQUEST_BLOCK)Request->ParamTransferSrb);
        break;
    // No default case
	}
	return (Request->RequestCode == VDISK_REQUEST_SHUTDOWN) ? TRUE : FALSE;
}

///////////////////////////////////////////////////////////////////////////////
// The system thread function 
// Context is the PVDISK_LUN_EXTENSION
static VOID VdiskRequestThread(PVOID Context)
{
	PVDISK_LUN_REQUEST Request;
    VDISK_LUN_REQUEST ShutdownRequest;
	KIRQL Irql;
	BOOLEAN Continue = TRUE;
    PVDISK_LUN_EXTENSION Lun = (PVDISK_LUN_EXTENSION)Context;
    LIST_ENTRY ListEntry;
    PVOID Events[2];
    NTSTATUS WaitStatus;
    THREAD_STORAGE Storage;
    KdPrint(("VdiskRequestThread enter...\r\n"));
    ASSERT(Lun);
    // Set the threads default priority.
    KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
    Events[0] = &Lun->RequestQueueEvent;
    Events[1] = &Lun->ShutdownEvent;
    ShutdownRequest.RequestCode = VDISK_REQUEST_SHUTDOWN;
    RtlZeroMemory(&Storage, sizeof (THREAD_STORAGE));
	while (Continue)
	{
        // Wait till some request will arrive
        WaitStatus = KeWaitForMultipleObjects(2, Events, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
        // If RequestQueueEvent signalted
        if (WaitStatus==0) for(;;)
        {
            IF_1(KdPrint(("VdiskRequestThread : Event has been signalted\r\n"));)
			// Take the lock and pick the first request from the queue
			KeAcquireSpinLock(&Lun->RequestQueueLock, &Irql);
			if (IsListEmpty(((PLIST_ENTRY)&Lun->RequestQueue)))
			{
                IF_1(KdPrint(("VdiskRequestThread : No more requests\r\n"));)
                // No more requests
				Request = NULL;
				// Reset the event
				KeResetEvent(&Lun->RequestQueueEvent);
			}
			else
			{
				// Take the request
				Request = CONTAINING_RECORD(
                    Lun->RequestQueue.Flink, VDISK_LUN_REQUEST, Entry);
				// Remove request from list
                RemoveEntryList(&(Request->Entry));
			}
			KeReleaseSpinLock(&Lun->RequestQueueLock, Irql);
            if (Request != NULL)
            {
                // Execute the request
                if (VdiskRequestExecute(Request, Lun, &Storage))
                {
				    // Thread will shutdown
                    KdPrint(("VdiskRequestThread : Thread will shutdown\r\n"));
				    Continue = FALSE;
                }
            }
            else
                // Return to waiting
				break;
        // If ShutdownEvent signalted
		}
        else if (WaitStatus == 1)
        {
    		KdPrint(("VdiskRequestThread : Shutdown detected for Lun (%u,%u)\r\n", 
                        Lun->TargetId, Lun->LunId));
            VdiskRequestExecute(&ShutdownRequest, NULL, &Storage);
            Continue = FALSE;
        }
	}
    KdPrint(("VdiskRequestThread : Thread finished\r\n"));
    // Done
    PsTerminateSystemThread(STATUS_SUCCESS);
}
    
///////////////////////////////////////////////////////////////////////////////
// Submits the request to the system thread
// Request will be executed asynchronously
static VOID VdiskRequestSubmit(PVDISK_LUN_REQUEST Request, PVDISK_LUN_EXTENSION Lun)
{
	KIRQL Irql;
    // Put the request on the list and signal the event
	KeAcquireSpinLock(&Lun->RequestQueueLock, &Irql);
	InsertTailList(&Lun->RequestQueue, &(Request->Entry));
	KeSetEvent(&Lun->RequestQueueEvent, IO_NO_INCREMENT, FALSE);
	KeReleaseSpinLock(&Lun->RequestQueueLock, Irql);
}

///////////////////////////////////////////////////////////////////////////////
// Submits the request to the system thread
// Request will be executed asynchronously
static VOID VdiskRequestDeleteAll(PVDISK_LUN_EXTENSION Lun)
{
	KIRQL Irql;
	PVDISK_LUN_REQUEST Request;
    KdPrint(("VdiskRequestDeleteAll: enter...\r\n"));
	// Check pointer
	ASSERT(Lun);
	// Check sign
	ASSERT(Lun->Sign == VDISK_LUN_SIGN);
	// Check initialization
	ASSERT(Lun->DeviceExtension);
    // Function must be called only when thread is working
    ASSERT((Lun->Flags & VDISK_LUN_THREAD_FINISHED) == 0);

    while (TRUE)
    {
        // Put the request on the list and signal the event
    	KeAcquireSpinLock(&Lun->RequestQueueLock, &Irql);
	    if (IsListEmpty(((PLIST_ENTRY)&(Lun->RequestQueue))))
        {
            KdPrint(("VdiskRequestDeleteAll: No more requests\r\n"));
		    // No more requests
		    Request = NULL;
		    // Reset the event
		    KeResetEvent(&Lun->RequestQueueEvent);
	    }
        else
        {
            KdPrint(("VdiskRequestDeleteAll: %X %X", &Lun->RequestQueue, Lun->RequestQueue.Flink));
            ASSERT(Lun->RequestQueue.Flink);
            // Take the request
		    Request = CONTAINING_RECORD(Lun->RequestQueue.Flink, VDISK_LUN_REQUEST, Entry);
		    // Remove request from list
            RemoveEntryList(&(Request->Entry));
	    }
	    KeReleaseSpinLock(&Lun->RequestQueueLock, Irql);
       	if (Request!=NULL)
        {
            switch (Request->RequestCode)
            {
            case VDISK_REQUEST_WRITE:
	        case VDISK_REQUEST_READ:
                KdPrint(("VdiskRequestDeleteAll: Deleted Srb 0x%X!\r\n",
                    Request->ParamTransferSrb));
                ((PSCSI_REQUEST_BLOCK)Request->ParamTransferSrb)->DataTransferLength = 0;        
			    ((PSCSI_REQUEST_BLOCK)Request->ParamTransferSrb)->SrbStatus = SRB_STATUS_BUS_RESET;
                KdPrint(("VdiskRequestDeleteAll: Call completion\r\n"));
                // Call completion
                VsPortCompleteRequest(Lun->DeviceExtension, (PSCSI_REQUEST_BLOCK)Request->ParamTransferSrb);
            default:
                KdPrint(("VdiskRequestDeleteAll: Strange request code!\r\n"));
            }
        }
        else
            break;
    } // while
    KdPrint(("VdiskRequestDeleteAll: finish...\r\n"));
}

// Fills the SENSE INFO for a CHECK CONDITION failure
static VOID VdiskFillSenseData(PSENSE_DATA SenseData, PSCSI_REQUEST_BLOCK Srb, ULONG Asc)
{
    ASSERT(SenseData);
    ASSERT(Srb);
    KdPrint(("VdiskFillSenseData : enter\r\n"));
    Srb->SrbStatus = SRB_STATUS_ERROR;
    // This is CHECK CONDITION
    Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
    SenseData->AdditionalSenseCode = (UCHAR)Asc;
    // Invent the sense key code based on additional sense code
    switch( Asc )
    {
    case SCSI_ADSENSE_ILLEGAL_BLOCK:
        SenseData->SenseKey = SCSI_SENSE_ILLEGAL_REQUEST;
        break;
    case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
        SenseData->SenseKey = SCSI_SENSE_NOT_READY;
        break;
    case SCSI_ADSENSE_NO_SENSE:
        SenseData->SenseKey = SCSI_SENSE_MEDIUM_ERROR;
        break;
    case SCSI_ADWRITE_PROTECT:
        SenseData->SenseKey = SCSI_SENSE_DATA_PROTECT;
        break;
    }
    SenseData->ErrorCode = 0x70;
    SenseData->Valid = 1;
    SenseData->AdditionalSenseLength = 0xb;
    SenseData->AdditionalSenseCodeQualifier = 0;
    KdPrint(("VdiskFillSenseData: %08lx %08lx\r\n", SenseData->SenseKey, Asc));
    // SRB_FLAGS_DISABLE_AUTOSENSE indicates that request-sense information 
    // should not be returned.
    if( (Srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE) == 0 )
    {
        KdPrint(("VdiskFillSenseData : SenseInfoBuffer is valid\r\n"));
        // Auto-sense needed
        // Note: MapBuffer MUST be TRUE
        if( Srb->SenseInfoBuffer != NULL )
            RtlCopyMemory(Srb->SenseInfoBuffer, SenseData, sizeof(SENSE_DATA));
        // Set flag
        Srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
    }
}

#ifdef VSPORT_PNP

// WMI routines

///////////////////////////////////////////////////////////////////////////////
// WMI callback to query the adapter data block
static NTSTATUS VdiskMpWmiAdapterQueryDataBlock(PVOID DeviceOrLunExtension,
                                                        PVSPORT_WMI_REQUEST Request,
                                                        ULONG BufferAvail, PUCHAR Buffer)
{
    NTSTATUS Status;
    ULONG DataSize;
    DataSize = 0;
    KdPrint(("VdiskMpWmiAdapterQueryDataBlock: enter for adapter %p\r\n",
                                                                    DeviceOrLunExtension));
    // Check the GuidIndex
    if( Request->Guid

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -