summaryrefslogtreecommitdiff
path: root/storage/class
diff options
context:
space:
mode:
authorkarlf <[email protected]>2016-08-11 13:28:13 -0700
committerkarlf <[email protected]>2016-08-11 13:28:13 -0700
commit96eb96dfb613e4c745db6bd1f53a92fe7e2290fc (patch)
treead5f3ede5cbcd6b598677ce41bcf8318471bdd92 /storage/class
parent687b274aa38fd05c8c26e3068932121876d7f745 (diff)
Updated for "Windows 10 Anniversary Update" (Version 1607)
Diffstat (limited to 'storage/class')
-rw-r--r--storage/class/cdrom/cdrom.sln18
-rw-r--r--storage/class/cdrom/src/cdrom.infbin10520 -> 8312 bytes
-rw-r--r--storage/class/cdrom/src/cdrom.vcxproj4
-rw-r--r--storage/class/cdrom/src/cdrom.vcxproj.Filters8
-rw-r--r--storage/class/cdrom/src/ioctl.c3
-rw-r--r--storage/class/classpnp/classpnp.sln18
-rw-r--r--storage/class/classpnp/src/autorun.c26
-rw-r--r--storage/class/classpnp/src/class.c55
-rw-r--r--storage/class/classpnp/src/classlog.mof3
-rw-r--r--storage/class/classpnp/src/classp.h89
-rw-r--r--storage/class/classpnp/src/classpnp.vcxproj4
-rw-r--r--storage/class/classpnp/src/classpnp.vcxproj.Filters8
-rw-r--r--storage/class/classpnp/src/classwmi.c20
-rw-r--r--storage/class/classpnp/src/clntirp.c192
-rw-r--r--storage/class/classpnp/src/retry.c26
-rw-r--r--storage/class/classpnp/src/utils.c249
-rw-r--r--storage/class/classpnp/src/xferpkt.c31
-rw-r--r--storage/class/disk/disk.sln18
-rw-r--r--storage/class/disk/src/disk.c21
-rw-r--r--storage/class/disk/src/disk.vcxproj4
-rw-r--r--storage/class/disk/src/disk.vcxproj.Filters8
-rw-r--r--storage/class/disk/src/geometry.c4
-rw-r--r--storage/class/disk/src/pnp.c3
23 files changed, 542 insertions, 270 deletions
diff --git a/storage/class/cdrom/cdrom.sln b/storage/class/cdrom/cdrom.sln
index 813369c9..4516f3dc 100644
--- a/storage/class/cdrom/cdrom.sln
+++ b/storage/class/cdrom/cdrom.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0
MinimumVisualStudioVersion = 12.0
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdrom", "src\cdrom.vcxproj", "{5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdrom", "src\cdrom.vcxproj", "{9DB6E759-C294-4E18-9013-82FD8F3DD5E6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -13,14 +13,14 @@ Global
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Debug|Win32.ActiveCfg = Debug|Win32
- {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Debug|Win32.Build.0 = Debug|Win32
- {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Release|Win32.ActiveCfg = Release|Win32
- {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Release|Win32.Build.0 = Release|Win32
- {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Debug|x64.ActiveCfg = Debug|x64
- {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Debug|x64.Build.0 = Debug|x64
- {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Release|x64.ActiveCfg = Release|x64
- {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Release|x64.Build.0 = Release|x64
+ {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Debug|Win32.Build.0 = Debug|Win32
+ {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Release|Win32.ActiveCfg = Release|Win32
+ {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Release|Win32.Build.0 = Release|Win32
+ {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Debug|x64.ActiveCfg = Debug|x64
+ {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Debug|x64.Build.0 = Debug|x64
+ {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Release|x64.ActiveCfg = Release|x64
+ {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/storage/class/cdrom/src/cdrom.inf b/storage/class/cdrom/src/cdrom.inf
index a1ba9f7f..d74fe65b 100644
--- a/storage/class/cdrom/src/cdrom.inf
+++ b/storage/class/cdrom/src/cdrom.inf
Binary files differ
diff --git a/storage/class/cdrom/src/cdrom.vcxproj b/storage/class/cdrom/src/cdrom.vcxproj
index 1b8b4bda..689c9716 100644
--- a/storage/class/cdrom/src/cdrom.vcxproj
+++ b/storage/class/cdrom/src/cdrom.vcxproj
@@ -19,13 +19,13 @@
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
- <ProjectGuid>{5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}</ProjectGuid>
+ <ProjectGuid>{9DB6E759-C294-4E18-9013-82FD8F3DD5E6}</ProjectGuid>
<RootNamespace>$(MSBuildProjectName)</RootNamespace>
<KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
<SupportsPackaging>false</SupportsPackaging>
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
- <SampleGuid>{1D0354B6-7638-4B49-A326-3F635DF4792D}</SampleGuid>
+ <SampleGuid>{E2CAD978-F695-4642-9CD1-65CB518B0B80}</SampleGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
diff --git a/storage/class/cdrom/src/cdrom.vcxproj.Filters b/storage/class/cdrom/src/cdrom.vcxproj.Filters
index 984e47ff..57895acd 100644
--- a/storage/class/cdrom/src/cdrom.vcxproj.Filters
+++ b/storage/class/cdrom/src/cdrom.vcxproj.Filters
@@ -3,19 +3,19 @@
<ItemGroup>
<Filter Include="Source Files">
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
- <UniqueIdentifier>{F4624455-84A0-4D68-9FDA-5A45BDDF16E9}</UniqueIdentifier>
+ <UniqueIdentifier>{1BE21169-AD4D-4A1B-AACD-6310066933B0}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
- <UniqueIdentifier>{59782596-7387-4C2F-8B3F-14DD7DBBE39E}</UniqueIdentifier>
+ <UniqueIdentifier>{9B550B9E-2283-4A6B-BAC8-52E0EAB6DD60}</UniqueIdentifier>
</Filter>
<Filter Include="Resource Files">
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
- <UniqueIdentifier>{F55549B9-4C00-441C-8960-79D8E04B2640}</UniqueIdentifier>
+ <UniqueIdentifier>{B3F87DD6-6AE2-4B7C-9C6F-6BC20F347A17}</UniqueIdentifier>
</Filter>
<Filter Include="Driver Files">
<Extensions>inf;inv;inx;mof;mc;</Extensions>
- <UniqueIdentifier>{BE2B60C1-58DD-4635-A2B4-E75CEC446355}</UniqueIdentifier>
+ <UniqueIdentifier>{4F903A62-C105-4A95-AB1A-2EB0F3AE253F}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
diff --git a/storage/class/cdrom/src/ioctl.c b/storage/class/cdrom/src/ioctl.c
index 49eeba49..590f1419 100644
--- a/storage/class/cdrom/src/ioctl.c
+++ b/storage/class/cdrom/src/ioctl.c
@@ -4150,9 +4150,10 @@ Return Value:
driveLetterName.MaximumLength = sizeof(driveLetterNameBuffer);
driveLetterName.Length = 0;
- queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
+ queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK;
queryTable[0].Name = valueName;
queryTable[0].EntryContext = &driveLetterName;
+ queryTable[0].DefaultType = (REG_SZ << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;
status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
L"\\Registry\\Machine\\System\\DISK", // why hard coded?
diff --git a/storage/class/classpnp/classpnp.sln b/storage/class/classpnp/classpnp.sln
index b11f5768..8078e6e1 100644
--- a/storage/class/classpnp/classpnp.sln
+++ b/storage/class/classpnp/classpnp.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0
MinimumVisualStudioVersion = 12.0
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "classpnp", "src\classpnp.vcxproj", "{427E597B-35E8-4D6C-8AA5-35A4519B33D5}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "classpnp", "src\classpnp.vcxproj", "{CAE2DAC6-A407-41A6-A943-11156A103D14}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -13,14 +13,14 @@ Global
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Debug|Win32.ActiveCfg = Debug|Win32
- {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Debug|Win32.Build.0 = Debug|Win32
- {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Release|Win32.ActiveCfg = Release|Win32
- {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Release|Win32.Build.0 = Release|Win32
- {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Debug|x64.ActiveCfg = Debug|x64
- {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Debug|x64.Build.0 = Debug|x64
- {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Release|x64.ActiveCfg = Release|x64
- {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Release|x64.Build.0 = Release|x64
+ {CAE2DAC6-A407-41A6-A943-11156A103D14}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CAE2DAC6-A407-41A6-A943-11156A103D14}.Debug|Win32.Build.0 = Debug|Win32
+ {CAE2DAC6-A407-41A6-A943-11156A103D14}.Release|Win32.ActiveCfg = Release|Win32
+ {CAE2DAC6-A407-41A6-A943-11156A103D14}.Release|Win32.Build.0 = Release|Win32
+ {CAE2DAC6-A407-41A6-A943-11156A103D14}.Debug|x64.ActiveCfg = Debug|x64
+ {CAE2DAC6-A407-41A6-A943-11156A103D14}.Debug|x64.Build.0 = Debug|x64
+ {CAE2DAC6-A407-41A6-A943-11156A103D14}.Release|x64.ActiveCfg = Release|x64
+ {CAE2DAC6-A407-41A6-A943-11156A103D14}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/storage/class/classpnp/src/autorun.c b/storage/class/classpnp/src/autorun.c
index 4dba537b..f0a88414 100644
--- a/storage/class/classpnp/src/autorun.c
+++ b/storage/class/classpnp/src/autorun.c
@@ -804,6 +804,7 @@ ClasspInternalSetMediaChangeState(
MEDIA_CHANGE_DETECTION_STATE oldMediaState;
PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
CLASS_MEDIA_CHANGE_CONTEXT mcnContext;
+ PIO_WORKITEM workItem;
if (!((NewState >= MediaUnknown) && (NewState <= MediaUnavailable))) {
return;
@@ -837,6 +838,25 @@ ClasspInternalSetMediaChangeState(
return;
}
+
+ //
+ // Inform PartMgr that the media changed. It will need to propagate
+ // DO_VERIFY_VOLUME to each partition. Ensure that only one work item
+ // updates the disk's properties at any given time.
+ //
+ if (InterlockedCompareExchange((volatile LONG *)&FdoExtension->PrivateFdoData->UpdateDiskPropertiesWorkItemActive, 1, 0) == 0) {
+
+ workItem = IoAllocateWorkItem(FdoExtension->DeviceObject);
+
+ if (workItem) {
+
+ IoQueueWorkItem(workItem, ClasspUpdateDiskProperties, DelayedWorkQueue, workItem);
+
+ } else {
+
+ InterlockedExchange((volatile LONG *)&FdoExtension->PrivateFdoData->UpdateDiskPropertiesWorkItemActive, 0);
+ }
+ }
if(info->MediaChangeDetectionDisableCount != 0) {
#if DBG
@@ -2595,8 +2615,8 @@ ClasspMediaChangeDeviceInstanceOverride(
RtlZeroMemory(&queryTable[0], sizeof(queryTable));
- queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
- queryTable[0].DefaultType = REG_DWORD;
+ queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK;
+ queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;
queryTable[0].DefaultLength = 0;
if (i==0) {
@@ -3001,7 +3021,7 @@ ClasspIsMediaChangeDisabledForClass(
parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
parameters[0].Name = L"Autorun";
parameters[0].EntryContext = &mcnRegistryValue;
- parameters[0].DefaultType = REG_DWORD;
+ parameters[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD;
parameters[0].DefaultData = &mcnRegistryValue;
parameters[0].DefaultLength = sizeof(ULONG);
diff --git a/storage/class/classpnp/src/class.c b/storage/class/classpnp/src/class.c
index 6113cd7e..5e7f00f1 100644
--- a/storage/class/classpnp/src/class.c
+++ b/storage/class/classpnp/src/class.c
@@ -1955,13 +1955,6 @@ NTSTATUS ClassPnpStartDevice(IN PDEVICE_OBJECT DeviceObject)
}
- // Initialize performance counter frequency
- KeQueryPerformanceCounter(&(fdoExtension->PrivateFdoData->PerfCounterFrequency));
-
- if (fdoExtension->PrivateFdoData->PerfCounterFrequency.QuadPart == 0) {
- fdoExtension->PrivateFdoData->PerfCounterFrequency.QuadPart = 1;
- }
-
/*
* Anchor the FDO in our static list.
* Pnp is synchronized, so we shouldn't need any synchronization here.
@@ -2244,6 +2237,16 @@ NTSTATUS ClassPnpStartDevice(IN PDEVICE_OBJECT DeviceObject)
UNREFERENCED_PARAMETER(legacyErrorHandling);
#endif
+
+ //
+ // Get the copy offload max target duration value.
+ // This function will set the default value if one hasn't been
+ // specified in the registry.
+ //
+ ClasspGetCopyOffloadMaxDuration(DeviceObject,
+ REG_DISK_CLASS_CONTROL,
+ &(fdoExtension->PrivateFdoData->CopyOffloadMaxTargetDuration));
+
}
}
@@ -2409,6 +2412,7 @@ NTSTATUS ClassReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
if (isRemoved) {
Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Irp->IoStatus.Information = 0;
ClassReleaseRemoveLock(DeviceObject, Irp);
ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
status = STATUS_DEVICE_DOES_NOT_EXIST;
@@ -2451,6 +2455,7 @@ NTSTATUS ClassReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
_Analysis_assume_(status != STATUS_PENDING);
if (!NT_SUCCESS(status)){
NT_ASSERT(Irp->IoStatus.Status == status);
+ Irp->IoStatus.Information = 0;
ClassReleaseRemoveLock(DeviceObject, Irp);
ClassCompleteRequest (DeviceObject, Irp, IO_NO_INCREMENT);
}
@@ -2575,8 +2580,7 @@ NTSTATUS ClassReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
ClasspMarkIrpAsIdle(Irp, FALSE);
status = ServiceTransferRequest(DeviceObject, Irp, FALSE);
if (fdoData->IdlePrioritySupported == TRUE) {
- fdoData->LastIoTime = ClasspGetCurrentTime(NULL);
- fdoData->IdleTicks = 0;
+ fdoData->LastNonIdleIoTime = ClasspGetCurrentTime();
}
ClassReleaseRemoveLock(DeviceObject, (PVOID)&uniqueAddr);
@@ -7274,6 +7278,7 @@ ClassDeviceControl(
NTSTATUS status;
ULONG modifiedIoControlCode = 0;
+ GUID activityId = {0};
//
@@ -7457,9 +7462,11 @@ ClassDeviceControl(
driveLetterName.Length = 0;
queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED |
- RTL_QUERY_REGISTRY_DIRECT;
+ RTL_QUERY_REGISTRY_DIRECT |
+ RTL_QUERY_REGISTRY_TYPECHECK;
queryTable[0].Name = valueName;
queryTable[0].EntryContext = &driveLetterName;
+ queryTable->DefaultType = (REG_SZ << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;
status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
L"\\Registry\\Machine\\System\\DISK",
@@ -8550,7 +8557,7 @@ ClassDeviceControl(
// only process Trim action in class layer if possible.
case DeviceDsmAction_Trim: {
- status = ClasspDeviceTrimProcess(DeviceObject, Irp, srb);
+ status = ClasspDeviceTrimProcess(DeviceObject, Irp, &activityId, srb);
break;
}
@@ -9451,10 +9458,10 @@ ClassQueryTimeOutRegistryValue(
RtlZeroMemory(parameters,
(sizeof(RTL_QUERY_REGISTRY_TABLE)*2));
- parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK;
parameters[0].Name = L"TimeOutValue";
parameters[0].EntryContext = &timeOut;
- parameters[0].DefaultType = REG_DWORD;
+ parameters[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD;
parameters[0].DefaultData = &zero;
parameters[0].DefaultLength = sizeof(ULONG);
@@ -12589,10 +12596,10 @@ ClasspScanForSpecialInRegistry(
// Setup the structure to read
//
- queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK;
queryTable[0].Name = CLASSP_REG_HACK_VALUE_NAME;
queryTable[0].EntryContext = &deviceHacks;
- queryTable[0].DefaultType = REG_DWORD;
+ queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD;
queryTable[0].DefaultData = &deviceHacks;
queryTable[0].DefaultLength = 0;
@@ -13369,7 +13376,7 @@ Arguments:
DeviceObject - Supplies the device object associated with this request
Irp - The IRP to be processed
- Srb - An SRB that can be optinally used to process this request
+ Srb - An SRB that can be optimally used to process this request
Return Value:
@@ -15608,12 +15615,18 @@ Return Value:
--*/
{
- NT_ASSERT(
- OffloadWriteContext->TotalSectorsProcessedSuccessfully <=
- OffloadWriteContext->TotalRequestSizeSectors);
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = OffloadWriteContext->Fdo->DeviceExtension;
+ PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
- // Time taken in 100 ns units
+ //
+ // Time taken in 100ns units.
+ //
ULONGLONG durationIn100ns = (KeQueryInterruptTime() - OffloadWriteContext->OperationStartTime);
+ ULONGLONG maxTargetDuration = fdoData->CopyOffloadMaxTargetDuration * 10ULL * 1000 * 1000;
+
+ NT_ASSERT(
+ OffloadWriteContext->TotalSectorsProcessedSuccessfully <=
+ OffloadWriteContext->TotalRequestSizeSectors);
if (OffloadWriteContext->TotalSectorsProcessedSuccessfully == OffloadWriteContext->TotalRequestSizeSectors) {
@@ -15627,7 +15640,7 @@ Return Value:
// Since we don't want a layered timeout mechanism (e.g. guest and parent OS in Hyper-V scenarios)
// to cause a SCSI timeout for the higher layer token operations.
//
- if (MAX_TARGET_DURATION <= durationIn100ns) {
+ if (maxTargetDuration <= durationIn100ns) {
TracePrint((TRACE_LEVEL_WARNING,
TRACE_FLAG_IOCTL,
diff --git a/storage/class/classpnp/src/classlog.mof b/storage/class/classpnp/src/classlog.mof
index b82d2e81..2443193f 100644
--- a/storage/class/classpnp/src/classlog.mof
+++ b/storage/class/classpnp/src/classlog.mof
@@ -1,3 +1,6 @@
+#pragma autorecover
+#pragma namespace("\\\\.\\Root\\WMI")
+
[WMI, guid("F903D6EC-8647-438f-9E42-891F4733EDAF")]
class MSStorageDriver_ScsiRequestBlock {
diff --git a/storage/class/classpnp/src/classp.h b/storage/class/classpnp/src/classp.h
index e0046be8..d7d57e9d 100644
--- a/storage/class/classpnp/src/classp.h
+++ b/storage/class/classpnp/src/classp.h
@@ -74,7 +74,6 @@ Revision History:
#define WPP_CONTROL_GUIDS WPP_CONTROL_GUIDS_NORMAL_FLAGS(WPP_GUID_CLASSPNP)
#endif
-
/*
* IA64 requires 8-byte alignment for pointers, but the IA64 NT kernel expects 16-byte alignment
*/
@@ -113,6 +112,7 @@ extern ULONG ClassMaxInterleavePerCriticalIo;
#define CLASSP_REG_DISABLE_D3COLD (L"DisableD3Cold")
#define CLASSP_REG_QERR_OVERRIDE_MODE (L"QERROverrideMode")
#define CLASSP_REG_LEGACY_ERROR_HANDLING (L"LegacyErrorHandling")
+#define CLASSP_REG_COPY_OFFLOAD_MAX_TARGET_DURATION (L"CopyOffloadMaxTargetDuration")
#define CLASS_PERF_RESTORE_MINIMUM (0x10)
#define CLASS_ERROR_LEVEL_1 (0x4)
@@ -146,6 +146,7 @@ extern ULONG ClassMaxInterleavePerCriticalIo;
#define NUM_MODESENSE_RETRIES 1
#define NUM_MODESELECT_RETRIES 1
#define NUM_DRIVECAPACITY_RETRIES 1
+#define NUM_THIN_PROVISIONING_RETRIES 32
#if (NTDDI_VERSION >= NTDDI_WINBLUE)
@@ -194,7 +195,7 @@ extern ULONG ClassMaxInterleavePerCriticalIo;
#define MAX_RECEIVE_TOKEN_INFORMATION_PARAMETER_DATA_LENGTH MAXULONG
#define MAX_TOKEN_TRANSFER_SIZE MAXULONGLONG
#define MAX_NUMBER_BLOCKS_PER_BLOCK_DEVICE_RANGE_DESCRIPTOR MAXULONG
-#define MAX_TARGET_DURATION (4ULL * 10 * 1000 * 1000) // 4sec in 100ns units
+#define DEFAULT_MAX_TARGET_DURATION 4 // 4sec
#define DEFAULT_MAX_NUMBER_BYTES_PER_SYNC_WRITE_USING_TOKEN (64ULL * 1024 * 1024) // 64MB
#define MAX_NUMBER_BYTES_PER_SYNC_WRITE_USING_TOKEN (256ULL * 1024 * 1024) // 256MB
#define MIN_TOKEN_LIST_IDENTIFIERS 256
@@ -231,6 +232,11 @@ extern ULONG DiskIdleTimeoutInMS;
extern CONST LARGE_INTEGER Magic10000;
#define SHIFT10000 13
+//
+// Constant to help wih various time conversions
+//
+#define CONST_MSECS_PER_SEC 1000
+
#define Convert100nsToMilliseconds(LARGE_INTEGER) \
( \
RtlExtendedMagicDivide((LARGE_INTEGER), Magic10000, SHIFT10000) \
@@ -494,7 +500,8 @@ typedef struct _TRANSFER_PACKET {
* Stuff for retrying the transfer.
*/
#if (NTDDI_VERSION >= NTDDI_WINBLUE)
- USHORT NumRetries; // Total number of retries remaining.
+ UCHAR NumRetries; // Total number of retries remaining.
+ UCHAR NumThinProvisioningRetries; //Number of retries carried out so far for a request failed with THIN_PROVISIONING_SOFT_THRESHOLD_ERROR
UCHAR NumIoTimeoutRetries; // Number of retries remaining for a timed-out request.
UCHAR TimedOut; // Indicates if this packet has timed-out.
#else
@@ -637,6 +644,13 @@ typedef struct _PNL_SLIST_HEADER {
//
struct _CLASS_PRIVATE_FDO_DATA {
+ //
+ // The amount of time allowed for a target to complete a copy offload
+ // operation, in seconds. Default is 4s, but it can be modified via
+ // registry key.
+ //
+ ULONG CopyOffloadMaxTargetDuration;
+
#if (NTDDI_VERSION >= NTDDI_WIN8)
@@ -882,40 +896,35 @@ struct _CLASS_PRIVATE_FDO_DATA {
#endif
//
- // Timer interval for sending low priority I/O
- //
- USHORT IdleTimerInterval;
-
- //
- // Idle counts required to process idle request
+ // Idle duration required to process idle request
// to avoid starvation
//
- USHORT StarvationCount;
+ USHORT StarvationDuration;
//
- // Idle timer tick count
+ // Idle I/O count
//
- ULONG IdleTimerTicks;
+ ULONG IdleIoCount;
//
- // Idle timer tick count
+ // Flag to indicate timer status
//
- ULONG IdleTicks;
+ LONG IdleTimerStarted;
//
- // Idle I/O count
+ // Time when the Idle timer was started
//
- ULONG IdleIoCount;
+ LARGE_INTEGER AntiStarvationStartTime;
//
- // Flag to indicate timer status
+ // Normal priority I/O time
//
- LONG IdleTimerStarted;
+ LARGE_INTEGER LastNonIdleIoTime;
//
- // Normal priority I/O time
+ // Time when the last IO of any priority completed.
//
- LARGE_INTEGER LastIoTime;
+ LARGE_INTEGER LastIoCompletionTime;
//
// Count of active normal priority I/O
@@ -941,9 +950,6 @@ struct _CLASS_PRIVATE_FDO_DATA {
ULONG MaxPowerOperationRetryCount;
PIRP PowerProcessIrp;
- // Counter frequency : Currently used for KeQueryPerferformanceCounter
- LARGE_INTEGER PerfCounterFrequency;
-
//
// Indicates legacy error handling should be used.
// This means:
@@ -1176,15 +1182,16 @@ typedef struct _IO_RETRIED_LOG_MESSAGE_CONTEXT {
#define MINIMUM_RETRY_UNITS ((LONGLONG)32)
#define MODE_PAGE_DATA_SIZE 192
-#define CLASS_IDLE_INTERVAL 50 // 50 milliseconds
+#define CLASS_IDLE_INTERVAL_MIN 12 // 12 milliseconds
+#define CLASS_IDLE_INTERVAL 12 // 12 milliseconds
#define CLASS_STARVATION_INTERVAL 500 // 500 milliseconds
-#define CLASS_IDLE_TIMER_TICKS 4
//
// Value of 50 milliseconds in 100 nanoseconds units
//
#define FIFTY_MS_IN_100NS_UNITS 50 * 100
+
/*
* Simple singly-linked-list queuing macros, with no synchronization.
*/
@@ -1245,21 +1252,15 @@ ClasspIsIdleRequest(
return ((BOOLEAN)Irp->Tail.Overlay.DriverContext[1]);
}
-extern BOOLEAN UseQPCTime;
-
__inline
LARGE_INTEGER
ClasspGetCurrentTime(
- PLARGE_INTEGER Frequency
+ VOID
)
{
LARGE_INTEGER currentTime;
- if (UseQPCTime) {
- currentTime = KeQueryPerformanceCounter(Frequency);
- } else {
- currentTime.QuadPart = (LONGLONG)KeQueryUnbiasedInterruptTime();
- }
+ currentTime.QuadPart = KeQueryUnbiasedInterruptTimePrecise((ULONG64*)&currentTime.QuadPart);
return currentTime;
}
@@ -1267,16 +1268,10 @@ ClasspGetCurrentTime(
__inline
ULONGLONG
ClasspTimeDiffToMs(
- PCLASS_PRIVATE_FDO_DATA FdoData,
ULONGLONG TimeDiff
)
{
- if (UseQPCTime) {
- TimeDiff *= 1000;
- TimeDiff /= FdoData->PerfCounterFrequency.QuadPart;
- } else {
- TimeDiff /= (10 * 1000);
- }
+ TimeDiff /= (10 * 1000);
return TimeDiff;
}
@@ -1839,6 +1834,7 @@ NTSTATUS ClasspDeviceLBProvisioningProperty(
NTSTATUS ClasspDeviceTrimProcess(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp,
+ _In_ PGUID ActivityId,
_Inout_ PSCSI_REQUEST_BLOCK Srb
);
@@ -1906,6 +1902,14 @@ ClasspGetMaximumTokenListIdentifier(
_Out_ PULONG MaximumListIdentifier
);
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+ClasspGetCopyOffloadMaxDuration(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_z_ PWSTR RegistryPath,
+ _Out_ PULONG MaxDuration
+ );
+
_IRQL_requires_max_(APC_LEVEL)
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_same_
@@ -2595,6 +2599,11 @@ Return Value:
}
+BOOLEAN
+ClasspIsThinProvisioningError (
+ _In_ PSCSI_REQUEST_BLOCK _Srb
+ );
+
__inline
BOOLEAN
ClasspLowerLayerNotSupport (
diff --git a/storage/class/classpnp/src/classpnp.vcxproj b/storage/class/classpnp/src/classpnp.vcxproj
index 20ea07c2..c2802197 100644
--- a/storage/class/classpnp/src/classpnp.vcxproj
+++ b/storage/class/classpnp/src/classpnp.vcxproj
@@ -19,12 +19,12 @@
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
- <ProjectGuid>{427E597B-35E8-4D6C-8AA5-35A4519B33D5}</ProjectGuid>
+ <ProjectGuid>{CAE2DAC6-A407-41A6-A943-11156A103D14}</ProjectGuid>
<RootNamespace>$(MSBuildProjectName)</RootNamespace>
<SupportsPackaging>false</SupportsPackaging>
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
- <SampleGuid>{F2A79FAF-7AB2-460E-A8F9-E0CB6AE58519}</SampleGuid>
+ <SampleGuid>{58F97C0C-9D73-4882-B4FA-BBEAE3EA4E10}</SampleGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
diff --git a/storage/class/classpnp/src/classpnp.vcxproj.Filters b/storage/class/classpnp/src/classpnp.vcxproj.Filters
index de33c904..93c2a79b 100644
--- a/storage/class/classpnp/src/classpnp.vcxproj.Filters
+++ b/storage/class/classpnp/src/classpnp.vcxproj.Filters
@@ -3,19 +3,19 @@
<ItemGroup>
<Filter Include="Source Files">
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
- <UniqueIdentifier>{E57AA4D3-2361-468E-BADF-7E50D1657C78}</UniqueIdentifier>
+ <UniqueIdentifier>{EC5C82CA-040D-44DB-91A3-D25A1FF34443}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
- <UniqueIdentifier>{73F07EE3-6460-42CC-9827-F4EB5CBD6FFA}</UniqueIdentifier>
+ <UniqueIdentifier>{88553D70-9C9C-49F9-B2D5-19552AB34B09}</UniqueIdentifier>
</Filter>
<Filter Include="Resource Files">
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
- <UniqueIdentifier>{01AD74A8-90EE-49F4-B392-6C515177B2CB}</UniqueIdentifier>
+ <UniqueIdentifier>{92330849-35A6-4C9A-9499-F2492A79CD86}</UniqueIdentifier>
</Filter>
<Filter Include="Driver Files">
<Extensions>inf;inv;inx;mof;mc;</Extensions>
- <UniqueIdentifier>{F1A14E0E-14F3-4FBA-B152-C150E51DFCB6}</UniqueIdentifier>
+ <UniqueIdentifier>{128D6F0C-829B-4E8A-A01D-4859DCC86D60}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
diff --git a/storage/class/classpnp/src/classwmi.c b/storage/class/classpnp/src/classwmi.c
index 1df85512..1b1eeeee 100644
--- a/storage/class/classpnp/src/classwmi.c
+++ b/storage/class/classpnp/src/classwmi.c
@@ -40,10 +40,6 @@ Revision History:
#include "classwmi.tmh"
#endif
-const UCHAR wmiInternalMOF[] = {
-#include "classlog.x"
-};
-
#define TIME_STRING_LENGTH 25
BOOLEAN
@@ -95,15 +91,11 @@ ClassFindInternalGuid(
GUIDREGINFO wmiClassGuids[] =
{
{
- MSWmi_MofDataGuid, 1, 0
- },
- {
MSStorageDriver_ClassErrorLogGuid, 1, 0
}
};
-#define MSWmi_MofData_GUID_Index 0
-#define MSStorageDriver_ClassErrorLogGuid_Index 1
+#define MSStorageDriver_ClassErrorLogGuid_Index 0
#define NUM_CLASS_WMI_GUIDS (sizeof(wmiClassGuids) / sizeof(GUIDREGINFO))
@@ -820,15 +812,7 @@ Return Value:
ULONG sizeNeeded = 0, i;
PFUNCTIONAL_DEVICE_EXTENSION fdoExt = DeviceObject->DeviceExtension;
- if (GuidIndex == MSWmi_MofData_GUID_Index) {
- sizeNeeded = sizeof(wmiInternalMOF);
- if (BufferAvail >= sizeNeeded) {
- RtlMoveMemory(Buffer, wmiInternalMOF, sizeof(wmiInternalMOF));
- status = STATUS_SUCCESS;
- } else {
- status = STATUS_BUFFER_TOO_SMALL;
- }
- } else if (GuidIndex == MSStorageDriver_ClassErrorLogGuid_Index) {
+ if (GuidIndex == MSStorageDriver_ClassErrorLogGuid_Index) {
//
// NOTE - ClassErrorLog is still using SCSI_REQUEST_BLOCK and will not be
diff --git a/storage/class/classpnp/src/clntirp.c b/storage/class/classpnp/src/clntirp.c
index d615dce1..c0fbcb1a 100644
--- a/storage/class/classpnp/src/clntirp.c
+++ b/storage/class/classpnp/src/clntirp.c
@@ -31,8 +31,7 @@ Revision History:
VOID
ClasspStartIdleTimer(
- IN PCLASS_PRIVATE_FDO_DATA FdoData,
- IN ULONGLONG IdleInterval
+ IN PCLASS_PRIVATE_FDO_DATA FdoData
);
VOID
@@ -48,6 +47,7 @@ ClasspServiceIdleRequest(
BOOLEAN PostToDpc
);
+
PIRP
ClasspDequeueIdleRequest(
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
@@ -165,7 +165,6 @@ Routine Description:
Arguments:
FdoExtension - Pointer to the device extension
- IdleInterval - Timer interval
Return Value:
@@ -207,7 +206,7 @@ ClasspInitializeIdleTimer(
CLASSP_REG_IDLE_INTERVAL_NAME,
&idleInterval);
- if ((idleInterval < CLASS_IDLE_TIMER_TICKS) || (idleInterval > USHORT_MAX)) {
+ if ((idleInterval < CLASS_IDLE_INTERVAL_MIN) || (idleInterval > USHORT_MAX)) {
//
// If the interval is too low or too high, reset it to the default value.
//
@@ -220,18 +219,8 @@ ClasspInitializeIdleTimer(
KeInitializeDpc(&fdoData->IdleDpc, ClasspIdleTimerDpc, FdoExtension);
InitializeListHead(&fdoData->IdleIrpList);
fdoData->IdleTimerStarted = FALSE;
- fdoData->IdleTimerInterval = (USHORT) (idleInterval / CLASS_IDLE_TIMER_TICKS);
- fdoData->StarvationCount = CLASS_STARVATION_INTERVAL / fdoData->IdleTimerInterval;
-
- //
- // Due to the coarseness of the idle timer frequency, some variability in
- // the idle interval will be tolerated such that it is the desired idle
- // interval on average.
- fdoData->IdleInterval =
- (USHORT)(idleInterval - (fdoData->IdleTimerInterval / 2));
-
- fdoData->IdleTimerTicks = 0;
- fdoData->IdleTicks = 0;
+ fdoData->StarvationDuration = CLASS_STARVATION_INTERVAL;
+ fdoData->IdleInterval = (USHORT)(idleInterval);
fdoData->IdleIoCount = 0;
fdoData->ActiveIoCount = 0;
fdoData->ActiveIdleIoCount = 0;
@@ -263,8 +252,6 @@ Arguments:
FdoData - Pointer to the private fdo data
- IdleInterval - Amount of time since the completion of the last non-idle request
-
Return Value:
None
@@ -272,8 +259,7 @@ Return Value:
--*/
VOID
ClasspStartIdleTimer(
- IN PCLASS_PRIVATE_FDO_DATA FdoData,
- IN ULONGLONG IdleInterval
+ IN PCLASS_PRIVATE_FDO_DATA FdoData
)
{
LARGE_INTEGER dueTime;
@@ -287,15 +273,9 @@ ClasspStartIdleTimer(
if (!timerStarted) {
//
- // Reset the anti-starvation timer tick counter and set the idle tick
- // counter according to the actual amount of idle time. The latter is
- // important to do to ensure that if the idle queue drains and the timer
- // has to be stopped and started on the arrival of the next idle request,
- // those requests don't get delayed unnecessarily due to IdleTicks not
- // reflecting actual idle time.
+ // Reset the anti-starvation start time.
//
- FdoData->IdleTimerTicks = 0;
- FdoData->IdleTicks = (ULONG)(IdleInterval / FdoData->IdleTimerInterval);
+ FdoData->AntiStarvationStartTime = ClasspGetCurrentTime();
//
// convert milliseconds to a relative 100ns
@@ -305,11 +285,11 @@ ClasspStartIdleTimer(
//
// multiply the period
//
- dueTime.QuadPart = Int32x32To64(FdoData->IdleTimerInterval, mstotimer);
+ dueTime.QuadPart = Int32x32To64(FdoData->IdleInterval, mstotimer);
KeSetTimerEx(&FdoData->IdleTimer,
dueTime,
- FdoData->IdleTimerInterval,
+ FdoData->IdleInterval,
&FdoData->IdleDpc);
}
return;
@@ -369,36 +349,27 @@ Return Value:
--*/
ULONGLONG
ClasspGetIdleTime (
- IN PCLASS_PRIVATE_FDO_DATA FdoData
+ IN PCLASS_PRIVATE_FDO_DATA FdoData,
+ IN LARGE_INTEGER CurrentTime
)
{
ULONGLONG idleTime;
- LARGE_INTEGER currentTime;
NTSTATUS status;
//
- // If there are any outstanding non-idle requests, then there has been no
- // idle time.
- //
- if (FdoData->ActiveIoCount > 0) {
- return 0;
- }
-
- //
// Get the time difference between current time and last I/O
// complete time.
//
- currentTime = ClasspGetCurrentTime(NULL);
- status = RtlULongLongSub((ULONGLONG)currentTime.QuadPart,
- (ULONGLONG)FdoData->LastIoTime.QuadPart,
+ status = RtlULongLongSub((ULONGLONG)CurrentTime.QuadPart,
+ (ULONGLONG)FdoData->LastNonIdleIoTime.QuadPart,
&idleTime);
if (NT_SUCCESS(status)) {
//
// Convert the time to milliseconds.
//
- idleTime = ClasspTimeDiffToMs(FdoData, idleTime);
+ idleTime = ClasspTimeDiffToMs(idleTime);
} else {
//
// Failed to get time difference, assume enough time passed.
@@ -411,58 +382,57 @@ ClasspGetIdleTime (
/*++
-ClasspIdleTicksSufficient
+ClasspIdleDurationSufficient
Routine Description:
- This routine whether enough idle ticks have occurred since the completion of
- the last non-idle request.
+ This routine computes whether enough idle duration has elapsed since the
+ completion of the last non-idle request.
Arguments:
FdoData - Pointer to the private fdo data
+ CurrentTimeIn - If CurrentTimeIn is non-NULL
+ - contents are set to NULL if the time is not updated.
+ - time is updated otherwise
+
Return Value:
- TRUE if sufficient idle ticks have expired to issue the next idle request.
+ TRUE if sufficient idle duration has elapsed to issue the next idle request.
--*/
LOGICAL
-ClasspIdleTicksSufficient (
- IN PCLASS_PRIVATE_FDO_DATA FdoData
+ClasspIdleDurationSufficient (
+ IN PCLASS_PRIVATE_FDO_DATA FdoData,
+ OUT LARGE_INTEGER** CurrentTimeIn
)
{
ULONGLONG idleInterval;
+ LARGE_INTEGER CurrentTime;
//
- // If it has been more than enough idle timer ticks since the completion of
- // the last non-idle request, enough idle time has passed.
- //
-
- if (FdoData->IdleTicks > CLASS_IDLE_TIMER_TICKS) {
- return TRUE;
- }
-
- //
- // If there have not been enough timer ticks, then there has not been
- // enough idle time.
+ // If there are any outstanding non-idle requests, then there has been no
+ // idle time.
//
- if (FdoData->IdleTicks < CLASS_IDLE_TIMER_TICKS) {
+ if (FdoData->ActiveIoCount > 0) {
+ if (CurrentTimeIn != NULL) {
+ *CurrentTimeIn = NULL;
+ }
return FALSE;
}
//
- // IdleTicks can reach CLASS_IDLE_TIMER_TICKS before FdoData->IdleInterval
- // worth of time elapses from the completion of the last non-idle request.
- // This can happen because when the idle timer is running, the last non-idle
- // request can complete at any time in the middle of the timer period (half
- // on average) so on the next timer expiration, IdleTicks will transition
- // 0->1 without its full time having passed since the completion of the last
- // non-idle request. So when IdleTicks is exactly CLASS_IDLE_TIMER_TICKS,
- // explicitly check whether an idle request should be issued now or on the
- // next timer expiration.
+ // Check whether an idle request should be issued now or on the next timer
+ // expiration.
//
- idleInterval = ClasspGetIdleTime(FdoData);
+
+ CurrentTime = ClasspGetCurrentTime();
+ idleInterval = ClasspGetIdleTime(FdoData, CurrentTime);
+
+ if (CurrentTimeIn != NULL) {
+ **CurrentTimeIn = CurrentTime;
+ }
if (idleInterval >= FdoData->IdleInterval) {
return TRUE;
@@ -478,14 +448,8 @@ ClasspIdleTimerDpc
Routine Description:
Timer dpc function. This function will be called once every
- IdleInterval. This will increment the IdleTicks and
- if it goes above 1 (i.e., disk is in idle state) then
- it will service an idle request.
-
- This function will increment IdleTimerTicks if the IdleTicks
- does not go above 1 (i.e., disk is not in idle state). When it
- reaches the starvation idle count (1 second) it will process
- one idle request.
+ IdleInterval. An idle request will be queued if sufficient idle time
+ has elapsed since the last non-idle request.
Arguments:
@@ -509,6 +473,10 @@ ClasspIdleTimerDpc(
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Context;
PCLASS_PRIVATE_FDO_DATA fdoData;
+ ULONGLONG idleTime;
+ NTSTATUS status;
+ LARGE_INTEGER currentTime;
+ LARGE_INTEGER* pCurrentTime;
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument1);
@@ -521,11 +489,10 @@ ClasspIdleTimerDpc(
fdoData = fdoExtension->PrivateFdoData;
- if ((fdoData->ActiveIoCount <= 0) &&
- (++fdoData->IdleTicks >= CLASS_IDLE_TIMER_TICKS)) {
+ if (fdoData->ActiveIoCount <= 0) {
//
- // If there are max active idle request, do not issue another one here.
+ // If there are max active idle requests, do not issue another one here.
//
if (fdoData->ActiveIdleIoCount >= fdoData->IdleActiveIoMax) {
return;
@@ -536,22 +503,48 @@ ClasspIdleTimerDpc(
// request has completed.
//
- if (ClasspIdleTicksSufficient(fdoData)) {
+ pCurrentTime = &currentTime;
+ if (ClasspIdleDurationSufficient(fdoData, &pCurrentTime)) {
//
// We are going to issue an idle request so reset the anti-starvation
// timer counter.
+ // If we are here (Idle duration is sufficient), pCurrentTime is
+ // expected to be set.
//
- fdoData->IdleTimerTicks = 0;
+ NT_ASSERT(pCurrentTime != NULL);
+ fdoData->AntiStarvationStartTime = *pCurrentTime;
ClasspServiceIdleRequest(fdoExtension, FALSE);
}
return;
}
//
+ // Get the time difference between current time and last I/O
+ // complete time.
+ //
+
+ currentTime = ClasspGetCurrentTime();
+ status = RtlULongLongSub((ULONGLONG)currentTime.QuadPart,
+ (ULONGLONG)fdoData->AntiStarvationStartTime.QuadPart,
+ &idleTime);
+
+ if (NT_SUCCESS(status)) {
+ //
+ // Convert the time to milliseconds.
+ //
+ idleTime = ClasspTimeDiffToMs(idleTime);
+ } else {
+ //
+ // Failed to get time difference, assume enough time passed.
+ //
+ idleTime = fdoData->StarvationDuration;
+ }
+
+ //
// If the timer is running then there must be at least one idle priority I/O pending
//
- if (++fdoData->IdleTimerTicks >= fdoData->StarvationCount) {
- fdoData->IdleTimerTicks = 0;
+ if (idleTime >= fdoData->StarvationDuration) {
+ fdoData->AntiStarvationStartTime = currentTime;
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_TIMER, "ClasspIdleTimerDpc: Starvation timer. Send one idle request\n"));
ClasspServiceIdleRequest(fdoExtension, FALSE);
}
@@ -588,24 +581,18 @@ ClasspEnqueueIdleRequest(
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
KIRQL oldIrql;
BOOLEAN issueRequest = TRUE;
- ULONGLONG idleInterval;
+ LARGE_INTEGER currentTime;
+ LARGE_INTEGER* pCurrentTime;
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_TIMER, "ClasspEnqueueIdleRequest: Queue idle request %p\n", Irp));
IoMarkIrpPending(Irp);
//
- // Get the time difference between current time and last non-idle request
- // complete time. If the there has been enough idle time, then issue the
- // request (unless other factors prevent us from doing so below) and set the
- // idle time such that we starting the timer below, it would start off with
- // enough idle ticks.
+ // Reset issueRequest if the idle duration is not sufficient.
//
- idleInterval = ClasspGetIdleTime(fdoData);
-
- if (idleInterval >= fdoData->IdleInterval) {
- idleInterval = fdoData->IdleTimerInterval * CLASS_IDLE_TIMER_TICKS;
- } else {
+ pCurrentTime = &currentTime;
+ if (ClasspIdleDurationSufficient(fdoData, &pCurrentTime) == FALSE) {
issueRequest = FALSE;
}
@@ -617,7 +604,6 @@ ClasspEnqueueIdleRequest(
issueRequest = FALSE;
}
- TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_TIMER, "ClasspEnqueueIdleRequest: Diff time %I64d\n", idleInterval));
KeAcquireSpinLock(&fdoData->IdleListLock, &oldIrql);
if (IsListEmpty(&fdoData->IdleIrpList)) {
@@ -628,7 +614,7 @@ ClasspEnqueueIdleRequest(
fdoData->IdleIoCount++;
if (!fdoData->IdleTimerStarted) {
- ClasspStartIdleTimer(fdoData, idleInterval);
+ ClasspStartIdleTimer(fdoData);
}
if (fdoData->IdleIoCount != 1) {
@@ -699,6 +685,8 @@ ClasspDequeueIdleRequest(
}
KeReleaseSpinLock(&fdoData->IdleListLock, oldIrql);
+
+
return irp;
}
@@ -736,7 +724,7 @@ ClasspCompleteIdleRequest(
if ((fdoData->IdleIoCount > 0) &&
(fdoData->ActiveIdleIoCount < fdoData->IdleActiveIoMax) &&
(fdoData->ActiveIoCount <= 0) &&
- (ClasspIdleTicksSufficient(fdoData))) {
+ (ClasspIdleDurationSufficient(fdoData, NULL))) {
TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_TIMER, "ClasspCompleteIdleRequest: Service next idle reqeusts\n"));
ClasspServiceIdleRequest(FdoExtension, TRUE);
}
@@ -779,5 +767,3 @@ ClasspServiceIdleRequest(
return;
}
-
-
diff --git a/storage/class/classpnp/src/retry.c b/storage/class/classpnp/src/retry.c
index 1a74c0b2..9b732bec 100644
--- a/storage/class/classpnp/src/retry.c
+++ b/storage/class/classpnp/src/retry.c
@@ -458,28 +458,40 @@ BOOLEAN RetryTransferPacket(PTRANSFER_PACKET Pkt)
PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
PCDB pCdb = SrbGetCdb(Pkt->Srb);
- TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "retrying failed transfer (pkt=%ph, op=%s)", Pkt, DBGGETSCSIOPSTR(Pkt->Srb)));
+ if(ClasspIsThinProvisioningError((PSCSI_REQUEST_BLOCK)Pkt->Srb) &&
+ (pCdb != NULL) && IS_SCSIOP_READWRITE(pCdb->CDB10.OperationCode)) {
- NT_ASSERT(Pkt->NumRetries > 0 || Pkt->RetryHistory);
- Pkt->NumRetries--;
+ if(Pkt->NumThinProvisioningRetries >= NUM_THIN_PROVISIONING_RETRIES) {
+ //We've already retried this the maximum times. Bail out.
+ return TRUE;
+ }
+ Pkt->NumThinProvisioningRetries++;
+ }
+ else {
+ NT_ASSERT(Pkt->NumRetries > 0 || Pkt->RetryHistory);
+ Pkt->NumRetries--;
+ }
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "retrying failed transfer (pkt=%ph, op=%s)", Pkt, DBGGETSCSIOPSTR(Pkt->Srb)));
if (!fdoData->DisableThrottling) {
//
// If this is the last retry, then turn off disconnect, sync transfer,
// and tagged queuing. On all other retries, leave the original settings.
+ // Do not apply this for thin provisioning soft threshold errors, since
+ // they should succeed as soon as they're retried on the right IT nexus.
//
- if (Pkt->NumRetries == 0) {
+ if ((Pkt->NumRetries == 0) && !ClasspIsThinProvisioningError((PSCSI_REQUEST_BLOCK)Pkt->Srb)) {
scaleDown = TRUE;
}
#if (NTDDI_VERSION >= NTDDI_WINBLUE)
//
// If this request previously timed-out and there are no more retries left
- // for timed-out requests then we should also apply the scale down.
+ // for timed-out requests, then we should also apply the scale down.
//
- if (Pkt->TimedOut &&
- Pkt->NumIoTimeoutRetries == 0) {
+ if (Pkt->TimedOut && Pkt->NumIoTimeoutRetries == 0) {
scaleDown = TRUE;
}
#endif
diff --git a/storage/class/classpnp/src/utils.c b/storage/class/classpnp/src/utils.c
index 20917d83..323d7449 100644
--- a/storage/class/classpnp/src/utils.c
+++ b/storage/class/classpnp/src/utils.c
@@ -118,10 +118,10 @@ VOID ClassGetDeviceParameter(
defaultParameterValue = *ParameterValue;
- queryTable->Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+ queryTable->Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK;
queryTable->Name = ParameterName;
queryTable->EntryContext = ParameterValue;
- queryTable->DefaultType = REG_DWORD;
+ queryTable->DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;
queryTable->DefaultData = NULL;
queryTable->DefaultLength = 0;
@@ -181,10 +181,10 @@ VOID ClassGetDeviceParameter(
defaultParameterValue = *ParameterValue;
- queryTable->Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+ queryTable->Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK;
queryTable->Name = ParameterName;
queryTable->EntryContext = ParameterValue;
- queryTable->DefaultType = REG_DWORD;
+ queryTable->DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;
queryTable->DefaultData = NULL;
queryTable->DefaultLength = 0;
@@ -1569,7 +1569,7 @@ ClassReadCapacity16 (
FdoExtension->LowerLayerSupport->AccessAlignment.LowerLayerSupported = Supported;
to indicate that info has been cached.
- NOTE: some future processes may use this funciton to send the command anyway, it will be caller's decision
+ NOTE: some future processes may use this function to send the command anyway, it will be caller's decision
on checking 'AccessAlignment.LowerLayerSupported' in case the cached info is good enough.
*/
{
@@ -1638,7 +1638,7 @@ ClassReadCapacity16 (
//prepare the Srb
if (NT_SUCCESS(status))
{
-
+
SrbSetTimeOutValue(Srb, FdoExtension->TimeOutValue);
SrbSetRequestTag(Srb, SP_UNTAGGED);
SrbSetRequestAttribute(Srb, SRB_SIMPLE_TAG_REQUEST);
@@ -1745,7 +1745,7 @@ NTSTATUS ClasspAccessAlignmentProperty(
//
// Request validation.
- // Note that InputBufferLength and IsFdo have been validated beforing entering this routine.
+ // Note that InputBufferLength and IsFdo have been validated before entering this routine.
//
if (KeGetCurrentIrql() >= DISPATCH_LEVEL) {
@@ -1814,7 +1814,7 @@ NTSTATUS ClasspAccessAlignmentProperty(
} else {
information = 0;
}
- goto Exit;
+
} else {
// case 2: the request is supported and it completes successfully
// case 3: the request is supported by lower stack but other failure status is returned.
@@ -1823,8 +1823,11 @@ NTSTATUS ClasspAccessAlignmentProperty(
information = (ULONG)Irp->IoStatus.Information;
- goto Exit;
}
+
+
+ goto Exit;
+
break;
}
@@ -1851,7 +1854,7 @@ NTSTATUS ClasspAccessAlignmentProperty(
}
case Supported: {
- NT_ASSERT(FALSE); // this case is handled at the begining of the function.
+ NT_ASSERT(FALSE); // this case is handled at the beginning of the function.
status = STATUS_INTERNAL_ERROR;
break;
}
@@ -3154,6 +3157,8 @@ DeviceProcessDsmTrimRequest(
_In_ ULONG DataSetRangesCount,
_In_ ULONG UnmapGranularity,
_In_ ULONG SrbFlags,
+ _In_ PIRP Irp,
+ _In_ PGUID ActivityId,
_Inout_ PSCSI_REQUEST_BLOCK Srb
)
/*++
@@ -3199,8 +3204,11 @@ Return Value:
ULONGLONG maxLbaCount;
ULONGLONG maxParameterListLength;
- UNREFERENCED_PARAMETER(UnmapGranularity);
+ UNREFERENCED_PARAMETER(UnmapGranularity);
+ UNREFERENCED_PARAMETER(ActivityId);
+ UNREFERENCED_PARAMETER(Irp);
+
//
// The given LBA ranges are in DEVICE_DATA_SET_RANGE format and need to be converted into UNMAP Block Descriptors.
// The UNMAP command is able to carry 0xFFFF bytes (0xFFF8 in reality as there are 8 bytes of header plus n*16 bytes of Block Descriptors) of data.
@@ -3320,6 +3328,7 @@ Return Value:
blockDescrIndex = 0;
lbaCount = 0;
+
while (!allDataSetRangeFullyConverted) {
//
@@ -3348,8 +3357,8 @@ Return Value:
//
// Send the UNMAP command when the buffer is full or when all input entries are converted.
//
- if ( (blockDescrIndex == maxBlockDescrCount) || // Buffer full or block descriptor count reached
- (lbaCount == maxLbaCount) || // Block LBA count reached
+ if ((blockDescrIndex == maxBlockDescrCount) || // Buffer full or block descriptor count reached
+ (lbaCount == maxLbaCount) || // Block LBA count reached
allDataSetRangeFullyConverted) { // All DataSetRanges have been converted
USHORT transferSize;
@@ -3457,6 +3466,7 @@ Exit:
NTSTATUS ClasspDeviceTrimProcess(
_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp,
+ _In_ PGUID ActivityId,
_Inout_ PSCSI_REQUEST_BLOCK Srb
)
/*
@@ -3483,6 +3493,7 @@ NTSTATUS ClasspDeviceTrimProcess(
CLASS_VPD_B0_DATA blockLimitsData;
ULONG generationCount;
+
if ( (DeviceObject->DeviceType != FILE_DEVICE_DISK) ||
(TEST_FLAG(DeviceObject->Characteristics, FILE_FLOPPY_DISKETTE)) ||
(fdoExtension->FunctionSupportInfo->LowerLayerSupport.TrimProcess == Supported) ) {
@@ -3511,6 +3522,7 @@ NTSTATUS ClasspDeviceTrimProcess(
goto Exit;
}
+
//
// If the caller has not set the "entire dataset range" flag then at least
// one dataset range should be specified. However, if the caller *has* set
@@ -3703,6 +3715,8 @@ NTSTATUS ClasspDeviceTrimProcess(
dataSetRangesCount,
granularityInBlocks,
srbFlags,
+ Irp,
+ ActivityId,
Srb);
} else {
// DSM IOCTL should be completed as not supported
@@ -3736,6 +3750,8 @@ Exit:
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = status;
+
+
ClassReleaseRemoveLock(DeviceObject, Irp);
ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
@@ -6725,7 +6741,7 @@ Return Value:
//
// Indicate that there is NO call-back routine.
//
- queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK;
//
// The value to query.
@@ -6736,7 +6752,7 @@ Return Value:
// Where to put the value, the type of the value, default value and length.
//
queryTable[0].EntryContext = &value;
- queryTable[0].DefaultType = REG_DWORD;
+ queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD;
queryTable[0].DefaultData = &value;
queryTable[0].DefaultLength = sizeof(value);
@@ -6765,6 +6781,99 @@ Return Value:
return status;
}
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+ClasspGetCopyOffloadMaxDuration(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_z_ PWSTR RegistryPath,
+ _Out_ PULONG MaxDuration
+ )
+
+ /*++
+
+ Routine Description:
+
+ This routine returns the maximum time (in seconds) that a Copy Offload
+ operation should take to complete by a target.
+
+ Arguments:
+
+ DeviceObject - The device handling the request.
+ RegistryPath - The absolute registry path under which MaxDuration resides.
+ MaxDuration - Returns the value being queried, in seconds.
+
+ Return Value:
+
+ STATUS_SUCCESS or appropriate error status returned by Registry API.
+
+ --*/
+
+{
+ RTL_QUERY_REGISTRY_TABLE queryTable[2];
+ ULONG value = 0;
+ NTSTATUS status;
+
+ TracePrint((TRACE_LEVEL_VERBOSE,
+ TRACE_FLAG_PNP,
+ "ClasspGetCopyOffloadMaxDuration (%p): Entering function.\n",
+ DeviceObject));
+
+ //
+ // Zero the table entries.
+ //
+ RtlZeroMemory(queryTable, sizeof(queryTable));
+
+ //
+ // The query table has two entries. One for CopyOffloadMaxDuration and
+ // the second which is the 'NULL' terminator.
+ //
+ // Indicate that there is NO call-back routine.
+ //
+ queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK;
+
+ //
+ // The value to query.
+ //
+ queryTable[0].Name = CLASSP_REG_COPY_OFFLOAD_MAX_TARGET_DURATION;
+
+ //
+ // Where to put the value, the type of the value, default value and length.
+ //
+ queryTable[0].EntryContext = &value;
+ queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;
+ queryTable[0].DefaultData = &value;
+ queryTable[0].DefaultLength = sizeof(value);
+
+ //
+ // Try to get the max target duration.
+ //
+ status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+ RegistryPath,
+ queryTable,
+ NULL,
+ NULL);
+
+ //
+ // Don't allow the user to set the value to lower than the default (4s) so
+ // they don't break ODX functionality if they accidentally set it too low.
+ //
+ if (NT_SUCCESS(status) &&
+ value > DEFAULT_MAX_TARGET_DURATION) {
+ *MaxDuration = value;
+ } else {
+ *MaxDuration = DEFAULT_MAX_TARGET_DURATION;
+ }
+
+ TracePrint((TRACE_LEVEL_VERBOSE,
+ TRACE_FLAG_PNP,
+ "ClasspGetCopyOffloadMaxDuration (%p): Exiting function with status %x (Max Duration %u seconds).\n",
+ DeviceObject,
+ status,
+ *MaxDuration));
+
+ return status;
+}
+
_IRQL_requires_max_(APC_LEVEL)
_IRQL_requires_min_(PASSIVE_LEVEL)
@@ -8205,7 +8314,7 @@ ClassDeviceHwFirmwareIsPortDriverSupported(
/*
Routine Description:
- This function informs the caller whether the port driver supports hardware firmware requests.
+ This function informs the caller whether the port driver supports hardware firmware requests.
Arguments:
DeviceObject: The target object.
@@ -8343,10 +8452,15 @@ Exit_Firmware_Get_Info:
//
// Firmware information is already cached in classpnp. Return a copy.
//
+ KLOCK_QUEUE_HANDLE lockHandle;
+ KeAcquireInStackQueuedSpinLock(&fdoExtension->FunctionSupportInfo->SyncLock, &lockHandle);
+
ULONG dataLength = min(irpStack->Parameters.DeviceIoControl.OutputBufferLength, fdoExtension->FunctionSupportInfo->HwFirmwareInfo->Size);
memcpy(Irp->AssociatedIrp.SystemBuffer, fdoExtension->FunctionSupportInfo->HwFirmwareInfo, dataLength);
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+
Irp->IoStatus.Information = dataLength;
}
@@ -8426,6 +8540,8 @@ ClassDeviceHwFirmwareDownloadProcess(
PIRP irp2 = NULL;
PIO_STACK_LOCATION newStack = NULL;
PCDB cdb = NULL;
+ BOOLEAN lockHeld = FALSE;
+ KLOCK_QUEUE_HANDLE lockHandle;
//
@@ -8521,6 +8637,13 @@ ClassDeviceHwFirmwareDownloadProcess(
}
//
+ // Acquire the SyncLock to ensure the HwFirmwareInfo pointer doesn't change
+ // while we're dereferencing it.
+ //
+ lockHeld = TRUE;
+ KeAcquireInStackQueuedSpinLock(&fdoExtension->FunctionSupportInfo->SyncLock, &lockHandle);
+
+ //
// Validate the device support
//
if ((fdoExtension->FunctionSupportInfo->HwFirmwareInfo->SupportUpgrade == FALSE) ||
@@ -8573,6 +8696,14 @@ ClassDeviceHwFirmwareDownloadProcess(
//
bufferSize = ALIGN_UP_BY(firmwareDownload->BufferSize, fdoExtension->FunctionSupportInfo->HwFirmwareInfo->ImagePayloadAlignment);
+ //
+ // We're done accessing HwFirmwareInfo at this point so we can release
+ // the SyncLock.
+ //
+ NT_ASSERT(lockHeld);
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+ lockHeld = FALSE;
+
#pragma prefast(suppress:6014, "The allocated memory that firmwareImageBuffer points to will be freed in ClassHwFirmwareDownloadComplete().")
firmwareImageBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, bufferSize, CLASSPNP_POOL_TAG_FIRMWARE);
@@ -8586,6 +8717,10 @@ ClassDeviceHwFirmwareDownloadProcess(
RtlCopyMemory(firmwareImageBuffer, firmwareDownload->ImageBuffer, (ULONG)firmwareDownload->BufferSize);
} else {
+ NT_ASSERT(lockHeld);
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+ lockHeld = FALSE;
+
firmwareImageBuffer = firmwareDownload->ImageBuffer;
bufferSize = (ULONG)firmwareDownload->BufferSize;
}
@@ -8654,7 +8789,7 @@ ClassDeviceHwFirmwareDownloadProcess(
SrbSetCdbLength(Srb, CDB10GENERIC_LENGTH);
cdb = SrbGetCdb(Srb);
cdb->WRITE_BUFFER.OperationCode = SCSIOP_WRITE_DATA_BUFF;
- cdb->WRITE_BUFFER.Mode = 0x0E;
+ cdb->WRITE_BUFFER.Mode = SCSI_WRITE_BUFFER_MODE_DOWNLOAD_MICROCODE_WITH_OFFSETS_SAVE_DEFER_ACTIVATE;
cdb->WRITE_BUFFER.ModeSpecific = 0; //Reserved for Mode 0x0E
cdb->WRITE_BUFFER.BufferID = firmwareDownload->Slot;
@@ -8713,6 +8848,15 @@ ClassDeviceHwFirmwareDownloadProcess(
Exit_Firmware_Download:
//
+ // Release the SyncLock if it's still held.
+ // This should only happen in the failure path.
+ //
+ if (lockHeld) {
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+ lockHeld = FALSE;
+ }
+
+ //
// Firmware Download request will be failed.
//
NT_ASSERT(!NT_SUCCESS(status));
@@ -8751,6 +8895,8 @@ ClassDeviceHwFirmwareActivateProcess(
BOOLEAN passDown = FALSE;
PCDB cdb = NULL;
ULONG i;
+ BOOLEAN lockHeld = FALSE;
+ KLOCK_QUEUE_HANDLE lockHandle;
//
@@ -8845,6 +8991,13 @@ ClassDeviceHwFirmwareActivateProcess(
}
//
+ // Acquire the SyncLock to ensure the HwFirmwareInfo pointer doesn't change
+ // while we're dereferencing it.
+ //
+ lockHeld = TRUE;
+ KeAcquireInStackQueuedSpinLock(&fdoExtension->FunctionSupportInfo->SyncLock, &lockHandle);
+
+ //
// Validate the device support
//
if (fdoExtension->FunctionSupportInfo->HwFirmwareInfo->SupportUpgrade == FALSE) {
@@ -8870,6 +9023,14 @@ ClassDeviceHwFirmwareActivateProcess(
}
//
+ // We're done accessing HwFirmwareInfo at this point so we can release
+ // the SyncLock.
+ //
+ NT_ASSERT(lockHeld);
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+ lockHeld = FALSE;
+
+ //
// Process the request by translating it into WRITE BUFFER command.
//
//
@@ -8878,7 +9039,7 @@ ClassDeviceHwFirmwareActivateProcess(
SrbSetCdbLength(Srb, CDB10GENERIC_LENGTH);
cdb = SrbGetCdb(Srb);
cdb->WRITE_BUFFER.OperationCode = SCSIOP_WRITE_DATA_BUFF;
- cdb->WRITE_BUFFER.Mode = 0x0F;
+ cdb->WRITE_BUFFER.Mode = SCSI_WRITE_BUFFER_MODE_ACTIVATE_DEFERRED_MICROCODE;
cdb->WRITE_BUFFER.ModeSpecific = 0; //Reserved for Mode 0x0F
cdb->WRITE_BUFFER.BufferID = firmwareActivate->Slot; //NOTE: this field will be ignored by SCSI device.
@@ -8912,6 +9073,15 @@ ClassDeviceHwFirmwareActivateProcess(
Exit_Firmware_Activate:
//
+ // Release the SyncLock if it's still held.
+ // This should only happen in the failure path.
+ //
+ if (lockHeld) {
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+ lockHeld = FALSE;
+ }
+
+ //
// Firmware Activate request will be failed.
//
NT_ASSERT(!NT_SUCCESS(status));
@@ -8930,3 +9100,46 @@ Exit_Firmware_Activate:
return status;
}
+
+BOOLEAN
+ClasspIsThinProvisioningError (
+ _In_ PSCSI_REQUEST_BLOCK Srb
+ )
+/*++
+
+Routine Description:
+
+ This routine checks whether the completed SRB Srb was completed with a thin provisioning
+ soft threshold error.
+
+Arguments:
+
+ Srb - the SRB to be checked.
+
+Return Value:
+
+ BOOLEAN
+
+--*/
+{
+ if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
+ PVOID senseBuffer = SrbGetSenseInfoBuffer(Srb);
+ if (senseBuffer) {
+ UCHAR senseKey = 0;
+ UCHAR addlSenseCode = 0;
+ UCHAR addlSenseCodeQual = 0;
+ BOOLEAN validSense = ScsiGetSenseKeyAndCodes(senseBuffer,
+ SrbGetSenseInfoBufferLength(Srb),
+ SCSI_SENSE_OPTIONS_NONE,
+ &senseKey,
+ &addlSenseCode,
+ &addlSenseCodeQual);
+
+ return (validSense
+ && (senseKey == SCSI_SENSE_UNIT_ATTENTION)
+ && (addlSenseCode == SCSI_ADSENSE_LB_PROVISIONING)
+ && (addlSenseCodeQual == SCSI_SENSEQ_SOFT_THRESHOLD_REACHED));
+ }
+ }
+ return FALSE;
+}
diff --git a/storage/class/classpnp/src/xferpkt.c b/storage/class/classpnp/src/xferpkt.c
index db728770..e66918b0 100644
--- a/storage/class/classpnp/src/xferpkt.c
+++ b/storage/class/classpnp/src/xferpkt.c
@@ -700,6 +700,7 @@ PTRANSFER_PACKET DequeueFreeTransferPacketEx(
}
+
/*
* SetupReadWriteTransferPacket
*
@@ -824,6 +825,7 @@ VOID SetupReadWriteTransferPacket( PTRANSFER_PACKET Pkt,
Pkt->SyncEventPtr = NULL;
Pkt->CompleteOriginalIrpWhenLastPacketCompletes = TRUE;
Pkt->NumIoTimeoutRetries = fdoData->MaxNumberOfIoRetries;
+ Pkt->NumThinProvisioningRetries = 0;
if (pCdb) {
@@ -927,6 +929,8 @@ NTSTATUS TransferPktComplete(IN PDEVICE_OBJECT NullFdo, IN PIRP Irp, IN PVOID Co
BOOLEAN packetDone = FALSE;
BOOLEAN idleRequest = FALSE;
ULONG transferLength;
+ LARGE_INTEGER completionTime;
+ ULONGLONG lastIoCompletionTime;
UNREFERENCED_PARAMETER(NullFdo);
@@ -938,14 +942,31 @@ NTSTATUS TransferPktComplete(IN PDEVICE_OBJECT NullFdo, IN PIRP Irp, IN PVOID Co
HISTORYLOGRETURNEDPACKET(pkt);
+ completionTime = ClasspGetCurrentTime();
+
+ //
+ // Record the time at which the last IO completed while snapping the old
+ // value to be used later. This can occur on multiple threads and hence
+ // could be overwritten with an older value. This is OK because this value
+ // is maintained as a heuristic.
+ //
+
+#ifdef _WIN64
+ lastIoCompletionTime = ReadULong64NoFence((volatile ULONG64*)&fdoData->LastIoCompletionTime.QuadPart);
+ WriteULong64NoFence((volatile ULONG64*)&fdoData->LastIoCompletionTime.QuadPart,
+ completionTime.QuadPart);
+#else
+ lastIoCompletionTime = InterlockedExchangeNoFence64((volatile LONG64*)&fdoData->LastIoCompletionTime.QuadPart,
+ completionTime.QuadPart);
+#endif
+
if (fdoData->IdlePrioritySupported == TRUE) {
idleRequest = ClasspIsIdleRequest(pkt->OriginalIrp);
if (idleRequest) {
InterlockedDecrement(&fdoData->ActiveIdleIoCount);
NT_ASSERT(fdoData->ActiveIdleIoCount >= 0);
} else {
- fdoData->LastIoTime = ClasspGetCurrentTime(NULL);
- fdoData->IdleTicks = 0;
+ fdoData->LastNonIdleIoTime = completionTime;
InterlockedDecrement(&fdoData->ActiveIoCount);
NT_ASSERT(fdoData->ActiveIoCount >= 0);
}
@@ -979,6 +1000,7 @@ NTSTATUS TransferPktComplete(IN PDEVICE_OBJECT NullFdo, IN PIRP Irp, IN PVOID Co
InterlockedExchangeAdd((PLONG)&pkt->OriginalIrp->IoStatus.Information,
(LONG)transferLength);
+
if ((pkt->InLowMemRetry) ||
(pkt->DriverUsesStartIO && pkt->LowMemRetry_remainingBufLen > 0)) {
packetDone = StepLowMemRetry(pkt);
@@ -1028,6 +1050,7 @@ NTSTATUS TransferPktComplete(IN PDEVICE_OBJECT NullFdo, IN PIRP Irp, IN PVOID Co
ClassReleaseQueue(pkt->Fdo);
}
+
if (NT_SUCCESS(Irp->IoStatus.Status)){
/*
* The error was recovered above in the InterpretTransferPacketError() call.
@@ -1741,7 +1764,6 @@ Return Value:
Pkt->ContinuationRoutine = ClasspPopulateTokenTransferPacketDone;
Pkt->ContinuationContext = OffloadReadContext;
-
TracePrint((TRACE_LEVEL_VERBOSE,
TRACE_FLAG_IOCTL,
"ClasspSetupPopulateTokenTransferPacket (%p): Exiting function with Irp %p\n",
@@ -1839,7 +1861,6 @@ Return Value:
Pkt->ContinuationRoutine = ClasspReceivePopulateTokenInformationTransferPacketDone;
Pkt->ContinuationContext = OffloadReadContext;
-
TracePrint((TRACE_LEVEL_VERBOSE,
TRACE_FLAG_IOCTL,
"ClasspSetupReceivePopulateTokenInformationTransferPacket (%p): Exiting function with Irp %p\n",
@@ -1941,7 +1962,6 @@ Return Value:
Pkt->ContinuationRoutine = ClasspWriteUsingTokenTransferPacketDone;
Pkt->ContinuationContext = OffloadWriteContext;
-
TracePrint((TRACE_LEVEL_VERBOSE,
TRACE_FLAG_IOCTL,
"ClasspSetupWriteUsingTokenTransferPacket (%p): Exiting function with Irp %p\n",
@@ -2040,7 +2060,6 @@ Return Value:
Pkt->ContinuationRoutine = ClasspReceiveWriteUsingTokenInformationTransferPacketDone;
Pkt->ContinuationContext = OffloadWriteContext;
-
TracePrint((TRACE_LEVEL_VERBOSE,
TRACE_FLAG_IOCTL,
"ClasspSetupReceiveWriteUsingTokenInformationTransferPacket (%p): Exiting function with Irp %p\n",
diff --git a/storage/class/disk/disk.sln b/storage/class/disk/disk.sln
index 3632e931..26ff24dd 100644
--- a/storage/class/disk/disk.sln
+++ b/storage/class/disk/disk.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0
MinimumVisualStudioVersion = 12.0
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "disk", "src\disk.vcxproj", "{0900F953-9DAF-4C58-9137-45A2DEC9C62C}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "disk", "src\disk.vcxproj", "{C4E8B1CC-0131-442C-8EB8-8E84F938878A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -13,14 +13,14 @@ Global
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Debug|Win32.ActiveCfg = Debug|Win32
- {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Debug|Win32.Build.0 = Debug|Win32
- {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Release|Win32.ActiveCfg = Release|Win32
- {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Release|Win32.Build.0 = Release|Win32
- {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Debug|x64.ActiveCfg = Debug|x64
- {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Debug|x64.Build.0 = Debug|x64
- {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Release|x64.ActiveCfg = Release|x64
- {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Release|x64.Build.0 = Release|x64
+ {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Debug|Win32.Build.0 = Debug|Win32
+ {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Release|Win32.ActiveCfg = Release|Win32
+ {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Release|Win32.Build.0 = Release|Win32
+ {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Debug|x64.ActiveCfg = Debug|x64
+ {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Debug|x64.Build.0 = Debug|x64
+ {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Release|x64.ActiveCfg = Release|x64
+ {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/storage/class/disk/src/disk.c b/storage/class/disk/src/disk.c
index 3d4d19b4..05f0d6d3 100644
--- a/storage/class/disk/src/disk.c
+++ b/storage/class/disk/src/disk.c
@@ -1550,6 +1550,7 @@ Return Value:
PIO_STACK_LOCATION irpSp = NULL;
PSTOR_ADDR_BTL8 storAddrBtl8;
PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
+ NTSTATUS SyncCacheStatus = STATUS_SUCCESS;
//
// Fill in the srb fields appropriately
@@ -1623,7 +1624,7 @@ Return Value:
TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushDispatch: sending sync cache\n"));
- ClassSendSrbSynchronous(Fdo, srb, NULL, 0, TRUE);
+ SyncCacheStatus = ClassSendSrbSynchronous(Fdo, srb, NULL, 0, TRUE);
}
//
@@ -1669,7 +1670,7 @@ Return Value:
irpSp->MajorFunction = IRP_MJ_SCSI;
irpSp->Parameters.Scsi.Srb = srb;
- IoSetCompletionRoutine(FlushContext->CurrIrp, DiskFlushComplete, NULL, TRUE, TRUE, TRUE);
+ IoSetCompletionRoutine(FlushContext->CurrIrp, DiskFlushComplete, (PVOID)SyncCacheStatus, TRUE, TRUE, TRUE);
TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushDispatch: sending srb flush on irp %p\n", FlushContext->CurrIrp));
@@ -1700,7 +1701,9 @@ Arguments:
Fdo - The device object which requested the completion routine
Irp - The irp that is being completed
- Context - The flush group context
+ Context - If disk had write cache enabled and SYNC CACHE command was sent as 1st part of FLUSH processing
+ then context must carry the completion status of SYNC CACHE request,
+ else context must be set to STATUS_SUCCESS.
Return Value:
@@ -1713,8 +1716,7 @@ Return Value:
NTSTATUS status;
PFUNCTIONAL_DEVICE_EXTENSION fdoExt;
PDISK_DATA diskData;
-
- UNREFERENCED_PARAMETER(Context);
+ NTSTATUS SyncCacheStatus = (NTSTATUS) Context;
TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DiskFlushComplete: %p %p\n", Fdo, Irp));
@@ -1742,6 +1744,15 @@ Return Value:
NT_ASSERT(status != STATUS_MORE_PROCESSING_REQUIRED);
//
+ // If sync cache failed earlier, final status of the flush request needs to be failure
+ // even if SRB_FUNCTION_FLUSH srb request succeeded
+ //
+ if (NT_SUCCESS(status) &&
+ (!NT_SUCCESS(SyncCacheStatus))) {
+ Irp->IoStatus.Status = status = SyncCacheStatus;
+ }
+
+ //
// Complete the flush requests tagged to this one
//
diff --git a/storage/class/disk/src/disk.vcxproj b/storage/class/disk/src/disk.vcxproj
index 1f52e370..bc5efddb 100644
--- a/storage/class/disk/src/disk.vcxproj
+++ b/storage/class/disk/src/disk.vcxproj
@@ -19,12 +19,12 @@
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
- <ProjectGuid>{0900F953-9DAF-4C58-9137-45A2DEC9C62C}</ProjectGuid>
+ <ProjectGuid>{C4E8B1CC-0131-442C-8EB8-8E84F938878A}</ProjectGuid>
<RootNamespace>$(MSBuildProjectName)</RootNamespace>
<SupportsPackaging>false</SupportsPackaging>
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
- <SampleGuid>{6222553B-2B65-4267-9522-973010FB316D}</SampleGuid>
+ <SampleGuid>{1257A10C-96B8-46FB-9FFD-6726981343C7}</SampleGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
diff --git a/storage/class/disk/src/disk.vcxproj.Filters b/storage/class/disk/src/disk.vcxproj.Filters
index 1a2af052..5c982e78 100644
--- a/storage/class/disk/src/disk.vcxproj.Filters
+++ b/storage/class/disk/src/disk.vcxproj.Filters
@@ -3,19 +3,19 @@
<ItemGroup>
<Filter Include="Source Files">
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
- <UniqueIdentifier>{9D58AF57-E3D3-492B-A93C-CD4BD860C101}</UniqueIdentifier>
+ <UniqueIdentifier>{5312DB94-F2AD-4908-9DC6-C3525D0469E6}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
- <UniqueIdentifier>{5021C225-A54E-4A00-A24F-A0AEC3B6B92A}</UniqueIdentifier>
+ <UniqueIdentifier>{1EA3AD8C-6E4B-4964-A3D1-62178CDEC868}</UniqueIdentifier>
</Filter>
<Filter Include="Resource Files">
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
- <UniqueIdentifier>{2092A6B9-C332-464C-B263-00060DE1B3E0}</UniqueIdentifier>
+ <UniqueIdentifier>{2A5B4A49-7B7B-4C84-9F4D-4B3B50FFA526}</UniqueIdentifier>
</Filter>
<Filter Include="Driver Files">
<Extensions>inf;inv;inx;mof;mc;</Extensions>
- <UniqueIdentifier>{2F3C9ECA-BD6F-472C-915B-51096E28B70C}</UniqueIdentifier>
+ <UniqueIdentifier>{48E85F2C-8024-453C-8D4D-AFA7E6BB0AB7}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
diff --git a/storage/class/disk/src/geometry.c b/storage/class/disk/src/geometry.c
index 911a33a4..a852c092 100644
--- a/storage/class/disk/src/geometry.c
+++ b/storage/class/disk/src/geometry.c
@@ -1358,8 +1358,8 @@ Return Value:
// ISSUE-2000/5/24-henrygab - figure out if there's a way to keep
// removals from happening while doing this.
//
-
- for(deviceObject = DriverObject->DeviceObject, unmatchedDiskCount = 0;
+ unmatchedDiskCount = 0;
+ for(deviceObject = DriverObject->DeviceObject;
deviceObject != NULL;
#pragma prefast(suppress:28175, "Need to access the opaque field to scan through the list of disks")
deviceObject = deviceObject->NextDevice) {
diff --git a/storage/class/disk/src/pnp.c b/storage/class/disk/src/pnp.c
index bb3a33c5..5eb333e7 100644
--- a/storage/class/disk/src/pnp.c
+++ b/storage/class/disk/src/pnp.c
@@ -122,9 +122,10 @@ Return Value:
LEAVE;
}
- queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK;
queryTable[0].Name = L"RootPartitionMountable";
queryTable[0].EntryContext = &(rootPartitionMountable);
+ queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE;
#pragma prefast(suppress:6309, "We don't have QueryRoutine so Context doesn't make any sense")
status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,