📄 vdiskmp.c
字号:
Srb->SrbStatus = SRB_STATUS_SUCCESS;
break;
}
case SCSIOP_REQUEST_SENSE:
IF_SCSI(KdPrint(("VdiskMpStartIo: SCSIOP_REQUEST_SENSE\r\n"));)
// Try to build the sense buffer
if ((Srb->DataBuffer != NULL) && (Srb->DataTransferLength >= sizeof (SENSE_DATA)) )
{
RtlCopyMemory( Srb->DataBuffer, &(Lun->SenseData), sizeof(SENSE_DATA) );
// All OK
Srb->SrbStatus = SRB_STATUS_SUCCESS;
Srb->DataTransferLength = sizeof(SENSE_DATA);
}
else
// Fail the request.
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
break;
case SCSIOP_INQUIRY:
IF_SCSI(KdPrint(("VdiskMpStartIo : SCSIOP_INQUIRY\r\r\n"));)
IF_SCSI(KdPrint(("VdiskMpStartIo : This must not be called by VSPORT- "
"VdiskMpInquiry will be called instead\r\r\n"));)
// Zero the INQUIRY data
RtlZeroMemory(Srb->DataBuffer, Srb->DataTransferLength);
// Process it
VdiskInquiry((PINQUIRYDATA)Srb->DataBuffer);
// Return SUCCESS
Srb->SrbStatus = SRB_STATUS_SUCCESS;
break;
case SCSIOP_READ:
case SCSIOP_WRITE:
// Check ReadOnly flag
if ((Srb->Cdb[0] == SCSIOP_WRITE) && (Lun->Flags & VDISK_LUN_READ_ONLY))
{
KdPrint(("VdiskMpStartIo : Can't write. Disk is READ_ONLY Flags 0x%X\r\n",
Lun->Flags));
// Return sense data
VdiskFillSenseData(&Lun->SenseData, Srb, SCSI_ADWRITE_PROTECT);
break;
}
// Get start sector from CDB
Start = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
(((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 ) |
(((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 ) |
(((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24 );
// Get maximimal sector of the disk
MaxSector = Lun->DiskSize;
// Calc sectors count
BlockCount = (USHORT)((Srb->DataTransferLength + 512 - 1 ) / 512);
// Check Lun flags
if( Lun->Flags & VDISK_LUN_SHUTDOWN )
{
KdPrint(("VdiskMpStartIo : Lun 0x%X shutdown. Can't read %u sectors from %u\r\n",
Lun, BlockCount, Start));
// Return sense data
// Do not return "no media" status if the underlying volume is dismounted,
// since this status is IoIsErrorUserInduced and the OS will try to show
// a popup during shutdown, which will hang
if( Lun->Flags & VDISK_LUN_DISMOUNT )
// Emulate device being disappeared
Srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
else
// CHECK CONDITION with no media
VdiskFillSenseData(&Lun->SenseData, Srb, SCSI_ADSENSE_NO_MEDIA_IN_DEVICE);
break;
}
// Check sectors range and correct sector count
if ((Start + BlockCount >= MaxSector) || (Start >= MaxSector))
if (Start >= MaxSector)
{
KdPrint(("VdiskMpStartIo : Error in sector's number %d\r\n", Start));
// Clear. Nothing transferred.
Srb->DataTransferLength = 0;
VdiskFillSenseData(&Lun->SenseData, Srb, SCSI_ADSENSE_ILLEGAL_BLOCK);
break;
}
else
// lower sector's count
BlockCount = (USHORT)(MaxSector-Start);
// Request is the SRB_EXTENSION
Request = (PVDISK_LUN_REQUEST)Srb->SrbExtension;
// Check pointer
if (Request == NULL)
{
KdPrint(("VdiskMpStartIo : Error: SRB_EXTENSION is NULL\r\n"));
// Clear. Nothing transferred.
Srb->DataTransferLength = 0;
VdiskFillSenseData(&Lun->SenseData, Srb, SCSI_ADSENSE_NO_SENSE);
break;
}
// Set up the SRB extension
Request->ParamTransferBuffer = (ULONG)Srb->DataBuffer;
if ((PVOID)Request->ParamTransferBuffer == NULL)
{
// VSPORT wrong buffer
// Clear. Nothing transferred.
Srb->DataTransferLength = 0;
VdiskFillSenseData(&Lun->SenseData, Srb, SCSI_ADSENSE_NO_SENSE);
break;
}
// Request haven't completed yet
Srb->SrbStatus = SRB_STATUS_PENDING;
// Fill the request's paremeters
Request->RequestCode = (Srb->Cdb[0] == SCSIOP_READ) ? VDISK_REQUEST_READ:VDISK_REQUEST_WRITE;
Request->Offset.QuadPart = Start * 512;
Request->ParamTransferLen = BlockCount;
Request->ParamTransferSrb = (ULONG)Srb;
// Submit operation. It's DPC_LEVEL now.
VdiskRequestSubmit(Request, Lun);
IF_1(KdPrint(("VdiskMpStartIo : SCSIOP_%s submitted %u sectors from %u\r\n",
(Srb->Cdb[0]==SCSIOP_READ)?"READ":"WRITE", BlockCount, Start));)
break;
case SCSIOP_MODE_SENSE:
IF_SCSI(KdPrint(("VdiskMpStartIo : SCSIOP_MODE_SENSE\r\n"));)
Srb->SrbStatus = SRB_STATUS_SUCCESS;
Srb->DataTransferLength = sizeof (MODE_PARAMETER_HEADER);
if (Lun->Flags & VDISK_LUN_READ_ONLY)
{
// Device is write-protected, set bit in mode sense buffer
((PMODE_PARAMETER_HEADER)Srb->DataBuffer)->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT;
}
// All other fields are 0
break;
case SCSIOP_REPORT_LUNS:
// Cdb[6]...Cdb[9] - Buffer length (Big endian)
// If SCSIOP_REPORT_LUNS command is supported in the VdiskMpInquiry so we don't need to support it there.
KdPrint(("VdiskMpStartIo : SCSIOP_REPORT_LUNS. Fail it. It is supported in the Inquiry LUN\r\n"));
#ifdef DEBUGLEVEL_SCSI
goto NotSupported;
case SCSIOP_MODE_SELECT:
KdPrint(("VdiskMpStartIo : SCSIOP_MODE_SELECT\r\n"));
goto NotSupported;
// Windows XP sends IOCTLs below
case SCSIOP_LOAD_UNLOAD:
KdPrint(("VdiskMpStartIo : SCSIOP_LOAD_UNLOAD\r\n"));
goto NotSupported;
case SCSIOP_SYNCHRONIZE_CACHE:
KdPrint(("VdiskMpStartIo : SCSIOP_SYNCHRONIZE_CACHE\r\n"));
NotSupported:
#endif
default:
KdPrint(("VdiskMpStartIo : CDB Command 0x%X (%u) isn't supported.\r\n",
Srb->Cdb[0], Srb->Cdb[0]));
// Return upsupported operation.
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
break;
}
break;
case SRB_FUNCTION_ABORT_COMMAND:
IF_SCSI(KdPrint(("VdiskMpStartIo : ABORT_COMMAND is not supported\r\n"));)
// We do not allow aborting.
Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
break;
case SRB_FUNCTION_IO_CONTROL:
// NT doesn't have this IOCTL:
//if (IOCTL_STORAGE_PREDICT_FAILURE == ((PSRB_IO_CONTROL)Srb->DataBuffer)->ControlCode)
// KdPrint(("VdiskMpStartIo : IOCTL_STORAGE_PREDICT_FAILURE detected\r\n"));
// Fail the request.
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
break;
default:
KdPrint(("VdiskMpStartIo : SCSI Function %u(0x%X) isn't supported. Error.\r\n",
Srb->Function, Srb->Function));
// Fail the request.
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
break;
}
Failed:
if (Srb->SrbStatus != SRB_STATUS_PENDING)
{
IF_1(KdPrint(("VdiskMpStartIo : Request completed. SrbStatus=0x%X\r\n", Srb->SrbStatus));)
// Complete or fail the SRB on error
VsPortCompleteRequest(DeviceExtension, Srb);
}
// LUN ready for next request.
VsPortNextLunRequest(DeviceExtension, 0, TargetId, LunId);
}
///////////////////////////////////////////////////////////////////////////////
// Function fills the inquiry buffer
//
static VOID VdiskInquiry(PINQUIRYDATA InquiryData)
{
ULONG Index;
ASSERT(InquiryData);
// Set HiSupport bit (we support REPORT LUNs)
((PUCHAR)InquiryData)[3] = ((PUCHAR)InquiryData)[3] | 0x10;
// Build the INQUIRY data
InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
// Set vendor ID
RtlCopyMemory(InquiryData->VendorId, "SCI INC ", 8);
// Set product ID
RtlCopyMemory(InquiryData->ProductId, "VIRTUAL DISK ", 16);
// Set revision level
RtlCopyMemory(InquiryData->ProductRevisionLevel, "0003", 4);
// Clear this out for now; future information will go here.
for ( Index = 0; Index < 20; Index++ )
InquiryData->VendorSpecific[ Index ] = ' ';
}
///////////////////////////////////////////////////////////////////////////////
// VSPORT calls this function to investigate LUN existence
//
static UCHAR VdiskMpInquiry(IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK InquirySrb)
{
KdPrint(("VdiskMpInquiry enter...\r\n"));
// Support for SCSI-3 REPORT LUN command
if( InquirySrb->Cdb[0] == SCSIOP_REPORT_LUNS )
{
if(InquirySrb->DataTransferLength < 16)
{
KdPrint(("VdiskMpInquiry: SCSIOP_REPORT_LUNS query passed a small buffer. Fail it.\r\n"));
// Too small
InquirySrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
}
else
{
PULONG DataBuffer = (PULONG)InquirySrb->DataBuffer;
ULONG Supremum = (ULONG)InquirySrb->DataBuffer+(ULONG)InquirySrb->DataTransferLength;
ULONG Lun;
// Number_of_LUNs * 8 is in the first 4 bytes and big endian
*DataBuffer++ = VdiskChangeBytes(NUMBER_OF_LUNS * 8);
// Reserved room
*DataBuffer++ = 0;
// Put numbers of supported LUNs.
// We just put there every LUN which we can have, but we can read Registry and put only available LUNs
for( Lun=0; (Lun<NUMBER_OF_LUNS) && ((ULONG)DataBuffer+7<Supremum); Lun++)
{
// Lower byte is reported LUN number
*DataBuffer++ = Lun;
// The others bytes are reserved
*DataBuffer++ = 0;
}
KdPrint(("VdiskMpInquiry: %d LUNs reported because output buffer size is %d.\r\n", Lun, InquirySrb->DataTransferLength));
// Return SUCCESS
InquirySrb->SrbStatus = SRB_STATUS_SUCCESS;
}
return InquirySrb->SrbStatus;
}
// Check the LUN existence and start the LUN's thread
if ( (InquirySrb->TargetId < NUMBER_OF_TARGETS) && (InquirySrb->Lun < NUMBER_OF_LUNS) &&
NT_SUCCESS(VdiskInquiryLun(DeviceExtension, InquirySrb->TargetId, InquirySrb->Lun)))
{
// LUN already filled in the
KdPrint(("VdiskMpInquiry: Reqistry scanned ok.\r\n"));
// Zero the INQUIRY data
RtlZeroMemory(InquirySrb->DataBuffer, InquirySrb->DataTransferLength);
// Fill in the INQUIRY data buffer
VdiskInquiry((PINQUIRYDATA)InquirySrb->DataBuffer);
// Return SUCCESS
InquirySrb->SrbStatus = SRB_STATUS_SUCCESS;
}
else
{
KdPrint(("VdiskMpInquiry: This target and Lun is empty.\r\n"));
InquirySrb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
}
return InquirySrb->SrbStatus;
}
///////////////////////////////////////////////////////////////////////////////
//
static ULONG VdiskMpNewDevice(PVOID DeviceExtension, PVOID InitializationContext,
PCHAR ArgumentString,
PVSP_CONFIGURATION_INFORMATION ConfigInfo,
#ifdef VSPORT_PNP
PCM_RESOURCE_LIST AllocatedResources,
PCM_RESOURCE_LIST AllocatedResourcesTranslated,
#endif
PBOOLEAN Again)
{
ULONG i;
KdPrint(("VdiskMpNewDevice enter...\r\n"));
// Fill the configuration information values
ConfigInfo->MaximumTransferLength = 0x10000;
ConfigInfo->NumberOfBuses = NUMBER_OF_BUSES;
ConfigInfo->MaximumNumberOfTargets = NUMBER_OF_TARGETS;
#ifdef VSPORT_PNP
ConfigInfo->PortWmiContext = &VdiskMpWmiAdapter;
ConfigInfo->LunWmiContext = &VdiskMpWmiLun;
#endif
// VsPort will call SRB_FUNCTION_SHUTDOWN
ConfigInfo->CachesData = TRUE;
// For all buses
for ( i = 0; i < NUMBER_OF_BUSES; i++ )
ConfigInfo->InitiatorBusId[i] = INITIATOR_ID;
// The ONLY device
*Again = FALSE;
return SP_RETURN_FOUND;
UNREFERENCED_PARAMETER(ArgumentString);
UNREFERENCED_PARAMETER(InitializationContext);
UNREFERENCED_PARAMETER(DeviceExtension);
#ifdef VSPORT_PNP
UNREFERENCED_PARAMETER(AllocatedResources);
UNREFERENCED_PARAMETER(AllocatedResourcesTranslated);
#endif
}
///////////////////////////////////////////////////////////////////////////////
//
static BOOLEAN VdiskMpInitialize(PVOID DeviceExtension)
{
KdPrint(("VdiskMpInitialize enter... DevExt 0x%X\r\n", DeviceExtension));
ASSERT(DeviceExtension);
// Zeror Luns
RtlZeroMemory( DeviceExtension, sizeof(VDISK_DEVICE_EXTENSION) );
// Initialize the device extension
KeInitializeSpinLock(&(((PVDISK_DEVICE_EXTENSION)DeviceExtension)->SpinLock));
return TRUE;
}
#ifdef VSPORT_PNP
///////////////////////////////////////////////////////////////////////////////
// It calls when SCSI adapter unloaded (See VspDevPnp IRP_MN_QUERY_REMOVE_DEVICE)
// We need to check all LUNs and check leaks
static VOID VdiskMpStopDevice(IN PVOID DeviceExtension)
{
// device count
ULONG Index;
KdPrint(("VdiskMpStopDevice enter...\r\n"));
ASSERT(DeviceExtension);
for (Index=0; Index < NUMBER_OF_TARGETS * NUMBER_OF_LUNS; Index++)
if (((PVDISK_DEVICE_EXTENSION)DeviceExtension)->Luns[Index] != NULL)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -