📄 vdiskmp.c
字号:
// 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 + -