ReactOS 0.4.15-dev-6068-g8061a6f
utils.c File Reference
#include "classp.h"
#include "debug.h"
#include <ntiologc.h>
Include dependency graph for utils.c:

Go to the source code of this file.

Macros

#define FIRMWARE_ACTIVATE_TIMEOUT_VALUE   30
 

Functions

BOOLEAN ClasspMyStringMatches (_In_opt_z_ PCHAR StringToMatch, _In_z_ PCHAR TargetString)
 
 _IRQL_requires_max_ (PASSIVE_LEVEL)
 
VOID ClasspPerfIncrementErrorCount (IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
 
VOID ClasspPerfIncrementSuccessfulIo (IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
 
PMDL ClasspBuildDeviceMdl (PVOID Buffer, ULONG BufferLen, BOOLEAN WriteToDevice)
 
PMDL BuildDeviceInputMdl (PVOID Buffer, ULONG BufferLen)
 
VOID ClasspFreeDeviceMdl (PMDL Mdl)
 
VOID FreeDeviceInputMdl (PMDL Mdl)
 
NTSTATUS ClasspDuidGetDeviceIdProperty (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
 
NTSTATUS ClasspDuidGetDeviceProperty (PDEVICE_OBJECT DeviceObject, PIRP Irp)
 
NTSTATUS ClasspDuidGetDriveLayout (PDEVICE_OBJECT DeviceObject, PIRP Irp)
 
NTSTATUS ClasspDuidQueryProperty (PDEVICE_OBJECT DeviceObject, PIRP Irp)
 
NTSTATUS ClasspWriteCacheProperty (_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
 
ULONG ClasspCalculateLogicalSectorSize (_In_ PDEVICE_OBJECT Fdo, _In_ ULONG BytesPerBlockInBigEndian)
 
NTSTATUS InterpretReadCapacity16Data (_Inout_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _In_ PREAD_CAPACITY16_DATA ReadCapacity16Data)
 
NTSTATUS ClassReadCapacity16 (_Inout_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _Inout_ PSCSI_REQUEST_BLOCK Srb)
 
NTSTATUS ClasspAccessAlignmentProperty (_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
 
static NTSTATUS IncursSeekPenalty (_In_ USHORT MediumRotationRate, _In_ PBOOLEAN IncursSeekPenalty)
 
NTSTATUS ClasspDeviceMediaTypeProperty (_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
 
NTSTATUS ClasspDeviceGetBlockDeviceCharacteristicsVPDPage (_In_ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension, _In_ PSCSI_REQUEST_BLOCK Srb)
 
NTSTATUS ClasspDeviceSeekPenaltyProperty (_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
 
NTSTATUS ClasspDeviceGetLBProvisioningVPDPage (_In_ PDEVICE_OBJECT DeviceObject, _Inout_opt_ PSCSI_REQUEST_BLOCK Srb)
 
NTSTATUS ClasspDeviceGetBlockLimitsVPDPage (_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _Inout_bytecount_(SrbSize) PSCSI_REQUEST_BLOCK Srb, _In_ ULONG SrbSize, _Out_ PCLASS_VPD_B0_DATA BlockLimitsData)
 
NTSTATUS ClasspDeviceTrimProperty (_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
 
NTSTATUS ClasspDeviceLBProvisioningProperty (_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
 
VOID ConvertDataSetRangeToUnmapBlockDescr (_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _In_ PUNMAP_BLOCK_DESCRIPTOR BlockDescr, _Inout_ PULONG CurrentBlockDescrIndex, _In_ ULONG MaxBlockDescrIndex, _Inout_ PULONGLONG CurrentLbaCount, _In_ ULONGLONG MaxLbaCount, _Inout_ PDEVICE_DATA_SET_RANGE DataSetRange)
 
NTSTATUS DeviceProcessDsmTrimRequest (_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _In_ PDEVICE_DATA_SET_RANGE DataSetRanges, _In_ ULONG DataSetRangesCount, _In_ ULONG UnmapGranularity, _In_ ULONG SrbFlags, _In_ PIRP Irp, _In_ PGUID ActivityId, _Inout_ PSCSI_REQUEST_BLOCK Srb)
 
NTSTATUS ClasspDeviceTrimProcess (_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PGUID ActivityId, _Inout_ PSCSI_REQUEST_BLOCK Srb)
 
NTSTATUS GetLBAStatus (_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _In_ PSCSI_REQUEST_BLOCK Srb, _In_ ULONGLONG StartingLBA, _Inout_ PLBA_STATUS_LIST_HEADER LBAStatusHeader, _In_ ULONG LBAStatusSize, _In_ BOOLEAN ConsolidateableBlocksOnly)
 
NTSTATUS ClasspDeviceGetLBAStatus (_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
 
NTSTATUS ClasspDeviceGetLBAStatusWorker (_In_ PDEVICE_OBJECT DeviceObject, _In_ PCLASS_VPD_B0_DATA BlockLimitsData, _In_ ULONGLONG StartingOffset, _In_ ULONGLONG LengthInBytes, _Out_ PDEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT DsmOutput, _Inout_ PULONG DsmOutputLength, _Inout_ PSCSI_REQUEST_BLOCK Srb, _In_ BOOLEAN ConsolidateableBlocksOnly, _In_ ULONG OutputVersion, _Out_ PBOOLEAN BlockLimitsDataMayHaveChanged)
 
NTSTATUS ClassGetLBProvisioningLogPage (_In_ PDEVICE_OBJECT DeviceObject, _In_ PSCSI_REQUEST_BLOCK Srb, _In_ ULONG LogPageSize, _Inout_ PLOG_PAGE_LOGICAL_BLOCK_PROVISIONING LogPage)
 
NTSTATUS ClassInterpretLBProvisioningLogPage (_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG LogPageSize, _In_ PLOG_PAGE_LOGICAL_BLOCK_PROVISIONING LogPage, _In_ ULONG ResourcesSize, _Out_ PSTORAGE_LB_PROVISIONING_MAP_RESOURCES Resources)
 
NTSTATUS ClassGetLBProvisioningResources (_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PSCSI_REQUEST_BLOCK Srb, _In_ ULONG ResourcesSize, _Inout_ PSTORAGE_LB_PROVISIONING_MAP_RESOURCES Resources)
 
NTSTATUS ClassDeviceGetLBProvisioningResources (_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
 
 _Function_class_ (IO_WORKITEM_ROUTINE)
 
NTSTATUS ClasspLogSystemEventWithDeviceNumber (_In_ PDEVICE_OBJECT DeviceObject, _In_ NTSTATUS IoErrorCode)
 
VOID ClassQueueThresholdEventWorker (_In_ PDEVICE_OBJECT DeviceObject)
 
VOID ClassQueueResourceExhaustionEventWorker (_In_ PDEVICE_OBJECT DeviceObject)
 
VOID ClassQueueCapacityChangedEventWorker (_In_ PDEVICE_OBJECT DeviceObject)
 
VOID ClassQueueProvisioningTypeChangedEventWorker (_In_ PDEVICE_OBJECT DeviceObject)
 
VOID ClasspQueueLogIOEventWithContextWorker (_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG SenseBufferSize, _In_ PVOID SenseData, _In_ UCHAR SrbStatus, _In_ UCHAR ScsiStatus, _In_ ULONG ErrorCode, _In_ ULONG CdbLength, _In_opt_ PCDB Cdb, _In_opt_ PTRANSFER_PACKET Pkt)
 
static BOOLEAN ValidPersistentReserveScope (UCHAR Scope)
 
static BOOLEAN ValidPersistentReserveType (UCHAR Type)
 
NTSTATUS ClasspPersistentReserve (_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
 
NTSTATUS ClasspPriorityHint (PDEVICE_OBJECT DeviceObject, PIRP Irp)
 
VOID ClasspConvertToScsiRequestBlock (_Out_ PSCSI_REQUEST_BLOCK Srb, _In_ PSTORAGE_REQUEST_BLOCK SrbEx)
 
 _IRQL_requires_max_ (APC_LEVEL)
 
_IRQL_requires_same_ NTSTATUS ClasspGetTokenOperationCommandBufferLength (_In_ PDEVICE_OBJECT Fdo, _In_ ULONG ServiceAction, _Inout_ PULONG CommandBufferLength, _Out_opt_ PULONG TokenOperationBufferLength, _Out_opt_ PULONG ReceiveTokenInformationBufferLength)
 
_IRQL_requires_same_ NTSTATUS ClasspGetTokenOperationDescriptorLimits (_In_ PDEVICE_OBJECT Fdo, _In_ ULONG ServiceAction, _In_ ULONG MaxParameterBufferLength, _Out_ PULONG MaxBlockDescriptorsCount, _Out_ PULONGLONG MaxBlockDescriptorsLength)
 
_IRQL_requires_same_ PUCHAR ClasspBinaryToAscii (_In_reads_(Length) PUCHAR HexBuffer, _In_ ULONG Length, _Inout_ PULONG UpdateLength)
 
_IRQL_requires_same_ NTSTATUS ClasspStorageEventNotification (_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp)
 
VOID ClasspZeroQERR (_In_ PDEVICE_OBJECT DeviceObject)
 
NTSTATUS ClasspGetHwFirmwareInfo (_In_ PDEVICE_OBJECT DeviceObject)
 
__inline BOOLEAN ClassDeviceHwFirmwareIsPortDriverSupported (_In_ PDEVICE_OBJECT DeviceObject)
 
NTSTATUS ClassDeviceHwFirmwareGetInfoProcess (_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
 
_IRQL_requires_same_ _IRQL_requires_max_ (DISPATCH_LEVEL)
 
NTSTATUS ClassDeviceHwFirmwareDownloadProcess (_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
 
NTSTATUS ClassDeviceHwFirmwareActivateProcess (_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
 
BOOLEAN ClasspIsThinProvisioningError (_In_ PSCSI_REQUEST_BLOCK Srb)
 

Macro Definition Documentation

◆ FIRMWARE_ACTIVATE_TIMEOUT_VALUE

#define FIRMWARE_ACTIVATE_TIMEOUT_VALUE   30

Definition at line 37 of file utils.c.

Function Documentation

◆ _Function_class_()

_Function_class_ ( IO_WORKITEM_ROUTINE  )

Definition at line 5136 of file utils.c.

5157{
5159 PIO_WORKITEM workItem = (PIO_WORKITEM)Context;
5163 ULONG resourcesSize = sizeof(STORAGE_LB_PROVISIONING_MAP_RESOURCES);
5164 PIO_ERROR_LOG_PACKET errorLogEntry = NULL;
5165 ULONG logEntrySize = sizeof(IO_ERROR_LOG_PACKET);
5166 PWCHAR stringIndex = NULL;
5167 LONG stringSize = 0;
5168 ULONG srbSize;
5169
5170 //
5171 // Allocate an SRB for getting the LBP log page.
5172 //
5173 if ((fdoExtension->AdapterDescriptor != NULL) &&
5174 (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK)) {
5176 } else {
5177 srbSize = sizeof(SCSI_REQUEST_BLOCK);
5178 }
5179
5180 srb = ExAllocatePoolWithTag(NonPagedPoolNx,
5181 srbSize,
5182 'ACcS');
5183 if (srb != NULL) {
5184
5185 //
5186 // Try to get the LBP resources from the device so we can report them in
5187 // the system event log.
5188 //
5190 srb,
5191 resourcesSize,
5192 &resources);
5193
5194 //
5195 // We need to allocate enough space for 3 insertion strings:
5196 // The first is a ULONG representing the disk number in decimal, which means
5197 // a max of 10 digits, plus one for the NULL character.
5198 // The second and third are ULONGLONGs representing the used and available
5199 // bytes, which means a max of 20 digits, plus one for the NULL character.
5200 // Make sure we do not exceed the max error log size or the max size of a
5201 // UCHAR since the size gets truncated to a UCHAR when we pass it to
5202 // IoAllocateErrorLogEntry().
5203 //
5204 logEntrySize = sizeof(IO_ERROR_LOG_PACKET) + (11 * sizeof(WCHAR)) + (2 * (21 * sizeof(WCHAR)));
5205 logEntrySize = min(logEntrySize, ERROR_LOG_MAXIMUM_SIZE);
5206 logEntrySize = min(logEntrySize, MAXUCHAR);
5207
5208 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(DeviceObject, (UCHAR)logEntrySize);
5209 if (errorLogEntry != NULL)
5210 {
5211 //
5212 // There are two event IDs we can use here. Both use the disk number,
5213 // but one reports the available and used bytes while the other does not.
5214 // We fall back on the latter if we failed to obtain the available and
5215 // used byte counts from the LBP log page.
5216 //
5217 // The event insertion strings need to be in this order:
5218 // 1. The disk number. (Both event IDs use this.)
5219 // 2. Bytes used.
5220 // 3. Bytes available.
5221 //
5222
5223 RtlZeroMemory(errorLogEntry, logEntrySize);
5224 errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
5225
5226 stringIndex = (PWCHAR)((ULONG_PTR)errorLogEntry + sizeof(IO_ERROR_LOG_PACKET));
5227 stringSize = logEntrySize - sizeof(IO_ERROR_LOG_PACKET);
5228
5229 //
5230 // Add the disk number to the insertion strings.
5231 //
5232 status = RtlStringCbPrintfW(stringIndex, stringSize, L"%d", fdoExtension->DeviceNumber);
5233
5234 if (NT_SUCCESS(status) )
5235 {
5236 errorLogEntry->NumberOfStrings++;
5237
5238 if (resources.UsedMappingResourcesValid &&
5239 resources.AvailableMappingResourcesValid)
5240 {
5241 //
5242 // Add the used mapping resources to the insertion strings.
5243 //
5244 stringIndex += (wcslen(stringIndex) + 1);
5245 stringSize -= (LONG)(wcslen(stringIndex) + 1) * sizeof(WCHAR);
5246
5247 status = RtlStringCbPrintfW(stringIndex, stringSize, L"%I64u", resources.UsedMappingResources);
5248
5249 if (NT_SUCCESS(status))
5250 {
5251 errorLogEntry->NumberOfStrings++;
5252
5253 //
5254 // Add the available mapping resources to the insertion strings.
5255 //
5256 stringIndex += (wcslen(stringIndex) + 1);
5257 stringSize -= (LONG)(wcslen(stringIndex) + 1) * sizeof(WCHAR);
5258
5259 status = RtlStringCbPrintfW(stringIndex, stringSize, L"%I64u", resources.AvailableMappingResources);
5260
5261 if (NT_SUCCESS(status))
5262 {
5263 errorLogEntry->NumberOfStrings++;
5264 }
5265 }
5266 }
5267 else
5268 {
5269 TracePrint((TRACE_LEVEL_WARNING,
5270 TRACE_FLAG_GENERAL,
5271 "ClassLogThresholdEvent: DO (%p), Used and available mapping resources were unavailable.\n",
5272 DeviceObject));
5273 }
5274 }
5275
5276 //
5277 // If we were able to successfully assemble all 3 insertion strings,
5278 // then we can use one of the "extended" event IDs. Otherwise, use the basic
5279 // event ID, which only requires the disk number.
5280 //
5281 if (errorLogEntry->NumberOfStrings == 3)
5282 {
5283 if (resources.UsedMappingResourcesScope == LOG_PAGE_LBP_RESOURCE_SCOPE_DEDICATED_TO_LUN &&
5284 resources.AvailableMappingResourcesScope == LOG_PAGE_LBP_RESOURCE_SCOPE_DEDICATED_TO_LUN) {
5285
5287
5288 } else if (resources.UsedMappingResourcesScope == LOG_PAGE_LBP_RESOURCE_SCOPE_DEDICATED_TO_LUN &&
5289 resources.AvailableMappingResourcesScope == LOG_PAGE_LBP_RESOURCE_SCOPE_NOT_DEDICATED_TO_LUN) {
5290
5292
5293 } else if (resources.UsedMappingResourcesScope == LOG_PAGE_LBP_RESOURCE_SCOPE_NOT_DEDICATED_TO_LUN &&
5294 resources.AvailableMappingResourcesScope == LOG_PAGE_LBP_RESOURCE_SCOPE_DEDICATED_TO_LUN) {
5295
5297
5298 } else if (resources.UsedMappingResourcesScope == LOG_PAGE_LBP_RESOURCE_SCOPE_NOT_DEDICATED_TO_LUN &&
5299 resources.AvailableMappingResourcesScope == LOG_PAGE_LBP_RESOURCE_SCOPE_NOT_DEDICATED_TO_LUN) {
5300
5302
5303 } else {
5304
5306 }
5307 }
5308 else
5309 {
5311 }
5312
5313 //
5314 // Write the error log packet to the system error logging thread.
5315 // It will be freed automatically.
5316 //
5317 IoWriteErrorLogEntry(errorLogEntry);
5318
5319 TracePrint((TRACE_LEVEL_INFORMATION,
5320 TRACE_FLAG_GENERAL,
5321 "ClassLogThresholdEvent: DO (%p), Soft threshold notification logged.\n",
5322 DeviceObject));
5323 }
5324 else
5325 {
5326 TracePrint((TRACE_LEVEL_ERROR,
5327 TRACE_FLAG_GENERAL,
5328 "ClassLogThresholdEvent: DO (%p), Failed to allocate memory for error log entry.\n",
5329 DeviceObject));
5330 }
5331 } else {
5332 TracePrint((TRACE_LEVEL_ERROR,
5333 TRACE_FLAG_GENERAL,
5334 "ClassLogThresholdEvent: DO (%p), Failed to allocate memory for SRB.\n",
5335 DeviceObject));
5336 }
5337
5338
5339 //
5340 // Clear the soft threshold event pending flag so that another can be queued.
5341 //
5342 InterlockedExchange((PLONG)&(fdoExtension->FunctionSupportInfo->LBProvisioningData.SoftThresholdEventPending), 0);
5343
5345
5346 FREE_POOL(srb);
5347
5348 if (workItem != NULL) {
5349 IoFreeWorkItem(workItem);
5350 }
5351}
#define InterlockedExchange
Definition: armddk.h:54
LONG NTSTATUS
Definition: precomp.h:26
#define FREE_POOL(_PoolPtr)
Definition: cdrom.h:782
struct _FUNCTIONAL_DEVICE_EXTENSION * PFUNCTIONAL_DEVICE_EXTENSION
#define CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE
Definition: classpnp.h:695
#define NULL
Definition: types.h:112
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
VOID NTAPI ClassReleaseRemoveLock(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PIRP Tag)
Definition: lock.c:251
NTSTATUS ClassGetLBProvisioningResources(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PSCSI_REQUEST_BLOCK Srb, _In_ ULONG ResourcesSize, _Inout_ PSTORAGE_LB_PROVISIONING_MAP_RESOURCES Resources)
Definition: utils.c:4958
struct _SCSI_REQUEST_BLOCK SCSI_REQUEST_BLOCK
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
FxCmResList * resources
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
VOID NTAPI IoFreeWorkItem(IN PIO_WORKITEM IoWorkItem)
Definition: iowork.c:64
#define min(a, b)
Definition: monoChain.cc:55
struct _STORAGE_LB_PROVISIONING_MAP_RESOURCES STORAGE_LB_PROVISIONING_MAP_RESOURCES
#define IO_WARNING_SOFT_THRESHOLD_REACHED_EX_LUN_POOL
Definition: ntiologc.h:108
#define IO_WARNING_SOFT_THRESHOLD_REACHED_EX
Definition: ntiologc.h:106
#define IO_WARNING_SOFT_THRESHOLD_REACHED_EX_POOL_POOL
Definition: ntiologc.h:110
#define IO_WARNING_SOFT_THRESHOLD_REACHED_EX_POOL_LUN
Definition: ntiologc.h:109
#define IO_WARNING_SOFT_THRESHOLD_REACHED_EX_LUN_LUN
Definition: ntiologc.h:107
#define IO_WARNING_SOFT_THRESHOLD_REACHED
Definition: ntiologc.h:105
VOID NTAPI IoWriteErrorLogEntry(IN PVOID ElEntry)
Definition: error.c:628
PVOID NTAPI IoAllocateErrorLogEntry(IN PVOID IoObject, IN UCHAR EntrySize)
Definition: error.c:528
NTSTRSAFEVAPI RtlStringCbPrintfW(_Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,...)
Definition: ntstrsafe.h:1173
#define L(x)
Definition: ntvdm.h:50
long LONG
Definition: pedump.c:60
#define LOG_PAGE_LBP_RESOURCE_SCOPE_NOT_DEDICATED_TO_LUN
Definition: scsi.h:3364
#define LOG_PAGE_LBP_RESOURCE_SCOPE_DEDICATED_TO_LUN
Definition: scsi.h:3363
#define SRB_TYPE_STORAGE_REQUEST_BLOCK
Definition: srb.h:655
#define STATUS_SUCCESS
Definition: shellext.h:65
#define TRACE_LEVEL_WARNING
Definition: storswtr.h:28
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
#define TRACE_LEVEL_INFORMATION
Definition: storswtr.h:29
NTSTATUS ErrorCode
Definition: iotypes.h:2007
USHORT NumberOfStrings
Definition: iotypes.h:2004
Definition: ps.c:97
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
int32_t * PLONG
Definition: typedefs.h:58
uint16_t * PWCHAR
Definition: typedefs.h:56
uint32_t ULONG
Definition: typedefs.h:59
#define MAXUCHAR
Definition: umtypes.h:117
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
#define ERROR_LOG_MAXIMUM_SIZE
Definition: iotypes.h:2042
struct _IO_WORKITEM * PIO_WORKITEM
Definition: iotypes.h:506
struct _IO_ERROR_LOG_PACKET * PIO_ERROR_LOG_PACKET
struct _IO_ERROR_LOG_PACKET IO_ERROR_LOG_PACKET
unsigned char UCHAR
Definition: xmlstorage.h:181
__wchar_t WCHAR
Definition: xmlstorage.h:180

◆ _IRQL_requires_max_() [1/3]

_IRQL_requires_max_ ( APC_LEVEL  )

Definition at line 6894 of file utils.c.

6924{
6926 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
6928 PIO_STACK_LOCATION irpStack;
6929 ULONG length;
6931 PDEVICE_COPY_OFFLOAD_DESCRIPTOR copyOffloadDescr = (PDEVICE_COPY_OFFLOAD_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
6932
6934
6935 PAGED_CODE();
6936
6937 fdoExtension = DeviceObject->DeviceExtension;
6938 query = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer;
6940 length = 0;
6941 information = 0;
6942
6943 TracePrint((TRACE_LEVEL_VERBOSE,
6944 TRACE_FLAG_IOCTL,
6945 "ClasspDeviceCopyOffloadProperty (%p): Entering function.\n",
6946 DeviceObject));
6947
6948 //
6949 // Check proper query type.
6950 //
6951 if (query->QueryType == PropertyExistsQuery) {
6952
6953 //
6954 // In order to maintain consistency with the how the rest of the properties
6955 // are handled, we shall always return success for PropertyExistsQuery.
6956 //
6958 goto __ClasspDeviceCopyOffloadProperty_Exit;
6959
6960 } else if (query->QueryType != PropertyStandardQuery) {
6961
6962 TracePrint((TRACE_LEVEL_ERROR,
6963 TRACE_FLAG_IOCTL,
6964 "ClasspDeviceCopyOffloadProperty (%p): Unsupported query type %x for Copy Offload property.\n",
6966 query->QueryType));
6967
6969 goto __ClasspDeviceCopyOffloadProperty_Exit;
6970 }
6971
6972 //
6973 // Request validation.
6974 // Note that InputBufferLength and IsFdo have been validated beforing entering this routine.
6975 //
6976
6978
6980
6981 TracePrint((TRACE_LEVEL_ERROR,
6982 TRACE_FLAG_IOCTL,
6983 "ClasspDeviceCopyOffloadProperty (%p): Query property for Copy Offload called at incorrect IRQL.\n",
6984 DeviceObject));
6985
6987 goto __ClasspDeviceCopyOffloadProperty_Exit;
6988 }
6989
6990 length = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
6991
6992 if (length < sizeof(DEVICE_COPY_OFFLOAD_DESCRIPTOR)) {
6993
6994 if (length >= sizeof(STORAGE_DESCRIPTOR_HEADER)) {
6995
6996 TracePrint((TRACE_LEVEL_WARNING,
6997 TRACE_FLAG_IOCTL,
6998 "ClasspDeviceCopyOffloadProperty (%p): Length %u specified for Copy Offload property enough only for header.\n",
7000 length));
7001
7003 copyOffloadDescr->Version = sizeof(DEVICE_COPY_OFFLOAD_DESCRIPTOR);
7004 copyOffloadDescr->Size = sizeof(DEVICE_COPY_OFFLOAD_DESCRIPTOR);
7005
7007 goto __ClasspDeviceCopyOffloadProperty_Exit;
7008 }
7009
7010 TracePrint((TRACE_LEVEL_ERROR,
7011 TRACE_FLAG_IOCTL,
7012 "ClasspDeviceCopyOffloadProperty (%p): Incorrect length %u specified for Copy Offload property.\n",
7014 length));
7015
7017 goto __ClasspDeviceCopyOffloadProperty_Exit;
7018 }
7019
7020 if (!fdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockDeviceRODLimits) {
7021
7022 TracePrint((TRACE_LEVEL_ERROR,
7023 TRACE_FLAG_IOCTL,
7024 "ClasspDeviceCopyOffloadProperty (%p): Command not supported on this device.\n",
7025 DeviceObject));
7026
7028 goto __ClasspDeviceCopyOffloadProperty_Exit;
7029 }
7030
7031 if (!NT_SUCCESS(fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.CommandStatus)) {
7032
7033 status = fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.CommandStatus;
7034
7035 TracePrint((TRACE_LEVEL_ERROR,
7036 TRACE_FLAG_IOCTL,
7037 "ClasspDeviceCopyOffloadProperty (%p): VPD retrieval had failed with %x.\n",
7039 status));
7040
7041 goto __ClasspDeviceCopyOffloadProperty_Exit;
7042 }
7043
7044 //
7045 // Fill in the output buffer. All data is copied from the FDO extension where we
7046 // cached Block Limits and Block Device Token Limits info when the device was first initialized.
7047 //
7048 RtlZeroMemory(copyOffloadDescr, length);
7049 copyOffloadDescr->Version = 1;
7050 copyOffloadDescr->Size = sizeof(DEVICE_COPY_OFFLOAD_DESCRIPTOR);
7051 copyOffloadDescr->MaximumTokenLifetime = fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumInactivityTimer;
7052 copyOffloadDescr->DefaultTokenLifetime = fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.DefaultInactivityTimer;
7053 copyOffloadDescr->MaximumTransferSize = fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumTokenTransferSize;
7054 copyOffloadDescr->OptimalTransferCount = fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.OptimalTransferCount;
7055 copyOffloadDescr->MaximumDataDescriptors = fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumRangeDescriptors;
7056
7057 if (NT_SUCCESS(fdoExtension->FunctionSupportInfo->BlockLimitsData.CommandStatus)) {
7058
7059 copyOffloadDescr->MaximumTransferLengthPerDescriptor = fdoExtension->FunctionSupportInfo->BlockLimitsData.MaximumTransferLength;
7060 copyOffloadDescr->OptimalTransferLengthPerDescriptor = fdoExtension->FunctionSupportInfo->BlockLimitsData.OptimalTransferLength;
7061 copyOffloadDescr->OptimalTransferLengthGranularity = fdoExtension->FunctionSupportInfo->BlockLimitsData.OptimalTransferLengthGranularity;
7062 }
7063
7066
7067__ClasspDeviceCopyOffloadProperty_Exit:
7068
7069 //
7070 // Set the size and status in IRP
7071 //
7072 Irp->IoStatus.Information = information;
7073 Irp->IoStatus.Status = status;
7074
7077
7078 TracePrint((TRACE_LEVEL_VERBOSE,
7079 TRACE_FLAG_IOCTL,
7080 "ClasspDeviceCopyOffloadProperty (%p): Exiting function with status %x.\n",
7082 status));
7083
7084 return status;
7085}
#define PAGED_CODE()
_In_ PSCSI_REQUEST_BLOCK Srb
Definition: cdrom.h:989
_In_ PIRP Irp
Definition: csq.h:116
static PDB_INFORMATION information
Definition: db.cpp:178
VOID NTAPI ClassCompleteRequest(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ CCHAR PriorityBoost)
Definition: lock.c:401
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
STORAGE_DESCRIPTOR_HEADER
Definition: ntddstor.h:560
struct _DEVICE_COPY_OFFLOAD_DESCRIPTOR DEVICE_COPY_OFFLOAD_DESCRIPTOR
struct _DEVICE_COPY_OFFLOAD_DESCRIPTOR * PDEVICE_COPY_OFFLOAD_DESCRIPTOR
struct _STORAGE_PROPERTY_QUERY * PSTORAGE_PROPERTY_QUERY
@ PropertyExistsQuery
Definition: ntddstor.h:506
@ PropertyStandardQuery
Definition: ntddstor.h:505
#define STATUS_DEVICE_FEATURE_NOT_SUPPORTED
Definition: ntstatus.h:985
#define STATUS_INVALID_LEVEL
Definition: ntstatus.h:564
#define STATUS_NOT_SUPPORTED
Definition: ntstatus.h:423
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define TRACE_LEVEL_VERBOSE
Definition: storswtr.h:30
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:3128
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2793
#define IO_NO_INCREMENT
Definition: iotypes.h:598
#define NT_ASSERT
Definition: rtlfuncs.h:3310

◆ _IRQL_requires_max_() [2/3]

_IRQL_requires_same_ _IRQL_requires_max_ ( DISPATCH_LEVEL  )

Definition at line 8503 of file utils.c.

8510{
8512
8513 PIRP originalIrp;
8514
8515 //
8516 // Free the allocated buffer for firmware image.
8517 //
8518 if (Context != NULL) {
8520 }
8521
8522 originalIrp = irpStack->Parameters.Others.Argument1;
8523
8524 NT_ASSERT(originalIrp != NULL);
8525
8526 originalIrp->IoStatus.Status = Irp->IoStatus.Status;
8527 originalIrp->IoStatus.Information = Irp->IoStatus.Information;
8528
8529 ClassReleaseRemoveLock(Fdo, originalIrp);
8531
8532 IoFreeIrp(Irp);
8533
8535
8536} // end ClassHwFirmwareDownloadComplete()
VOID NTAPI IoFreeIrp(IN PIRP Irp)
Definition: irp.c:1666
#define STATUS_MORE_PROCESSING_REQUIRED
Definition: shellext.h:68
IO_STATUS_BLOCK IoStatus
_Must_inspect_result_ _In_ WDFDEVICE Fdo
Definition: wdffdo.h:461
#define IO_DISK_INCREMENT
Definition: iotypes.h:600

◆ _IRQL_requires_max_() [3/3]

_IRQL_requires_max_ ( PASSIVE_LEVEL  )

Definition at line 71 of file utils.c.

80{
82 RTL_QUERY_REGISTRY_TABLE queryTable[2] = {0};
83 HANDLE deviceParameterHandle = NULL;
84 HANDLE deviceSubkeyHandle = NULL;
85 ULONG defaultParameterValue;
86
87 PAGED_CODE();
88
89 //
90 // open the given parameter
91 //
92
96 &deviceParameterHandle);
97
98 if (NT_SUCCESS(status) && (SubkeyName != NULL)) {
99
100 UNICODE_STRING subkeyName;
101 OBJECT_ATTRIBUTES objectAttributes = {0};
102
103 RtlInitUnicodeString(&subkeyName, SubkeyName);
104 InitializeObjectAttributes(&objectAttributes,
105 &subkeyName,
107 deviceParameterHandle,
108 NULL);
109
110 status = ZwOpenKey(&deviceSubkeyHandle,
111 KEY_READ,
112 &objectAttributes);
113 if (!NT_SUCCESS(status)) {
114 ZwClose(deviceParameterHandle);
115 }
116
117 }
118
119 if (NT_SUCCESS(status)) {
120
121 defaultParameterValue = *ParameterValue;
122
124 queryTable->Name = ParameterName;
125 queryTable->EntryContext = ParameterValue;
127 queryTable->DefaultData = NULL;
128 queryTable->DefaultLength = 0;
129
131 (PWSTR)(SubkeyName ?
132 deviceSubkeyHandle :
133 deviceParameterHandle),
134 queryTable,
135 NULL,
136 NULL);
137 if (!NT_SUCCESS(status)) {
138 *ParameterValue = defaultParameterValue; // use default value
139 }
140
141 //
142 // close what we open
143 //
144
145 if (SubkeyName) {
146 ZwClose(deviceSubkeyHandle);
147 }
148
149 ZwClose(deviceParameterHandle);
150 }
151
152 if (!NT_SUCCESS(status)) {
153
154 //
155 // Windows 2000 SP3 uses the driver-specific key, so look in there
156 //
157
160 KEY_READ,
161 &deviceParameterHandle);
162
163 if (NT_SUCCESS(status) && (SubkeyName != NULL)) {
164
165 UNICODE_STRING subkeyName;
166 OBJECT_ATTRIBUTES objectAttributes = {0};
167
168 RtlInitUnicodeString(&subkeyName, SubkeyName);
169 InitializeObjectAttributes(&objectAttributes,
170 &subkeyName,
172 deviceParameterHandle,
173 NULL);
174
175 status = ZwOpenKey(&deviceSubkeyHandle, KEY_READ, &objectAttributes);
176
177 if (!NT_SUCCESS(status)) {
178 ZwClose(deviceParameterHandle);
179 }
180 }
181
182 if (NT_SUCCESS(status)) {
183
184 defaultParameterValue = *ParameterValue;
185
187 queryTable->Name = ParameterName;
188 queryTable->EntryContext = ParameterValue;
190 queryTable->DefaultData = NULL;
191 queryTable->DefaultLength = 0;
192
194 (PWSTR)(SubkeyName ?
195 deviceSubkeyHandle :
196 deviceParameterHandle),
197 queryTable,
198 NULL,
199 NULL);
200 if (NT_SUCCESS(status)) {
201
202 //
203 // Migrate the value over to the device-specific key
204 //
205
206 ClassSetDeviceParameter(FdoExtension, SubkeyName, ParameterName, *ParameterValue);
207
208 } else {
209
210 //
211 // Use the default value
212 //
213
214 *ParameterValue = defaultParameterValue;
215 }
216
217 if (SubkeyName) {
218 ZwClose(deviceSubkeyHandle);
219 }
220
221 ZwClose(deviceParameterHandle);
222 }
223 }
224
225 return;
226
227} // end ClassGetDeviceParameter()
_In_opt_ PWSTR _In_ PWSTR ParameterName
Definition: cdrom.h:961
_In_opt_ PWSTR _In_ PWSTR _Inout_ PULONG ParameterValue
Definition: cdrom.h:963
_In_opt_ PWSTR SubkeyName
Definition: cdrom.h:960
@ FdoExtension
Definition: precomp.h:48
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
NTSYSAPI NTSTATUS WINAPI RtlQueryRegistryValues(ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID)
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
#define KEY_READ
Definition: nt_native.h:1023
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define RTL_QUERY_REGISTRY_REQUIRED
Definition: nt_native.h:132
#define RTL_QUERY_REGISTRY_DIRECT
Definition: nt_native.h:144
#define REG_NONE
Definition: nt_native.h:1492
#define RTL_REGISTRY_HANDLE
Definition: nt_native.h:168
NTSTATUS NTAPI IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject, IN ULONG DevInstKeyType, IN ACCESS_MASK DesiredAccess, OUT PHANDLE DevInstRegKey)
Definition: pnpmgr.c:1621
#define REG_DWORD
Definition: sdbapi.c:596
uint16_t * PWSTR
Definition: typedefs.h:56
#define PLUGPLAY_REGKEY_DRIVER
Definition: usbd.c:42
#define PLUGPLAY_REGKEY_DEVICE
Definition: iofuncs.h:2786
#define RTL_QUERY_REGISTRY_TYPECHECK
#define RTL_QUERY_REGISTRY_TYPECHECK_SHIFT

◆ BuildDeviceInputMdl()

PMDL BuildDeviceInputMdl ( PVOID  Buffer,
ULONG  BufferLen 
)

Definition at line 609 of file utils.c.

610{
611 return ClasspBuildDeviceMdl(Buffer, BufferLen, FALSE);
612}
Definition: bufpool.h:45
#define FALSE
Definition: types.h:117
PMDL ClasspBuildDeviceMdl(PVOID Buffer, ULONG BufferLen, BOOLEAN WriteToDevice)
Definition: utils.c:582

Referenced by ClasspModeSelect(), ClasspModeSense(), and ClassReadDriveCapacity().

◆ ClassDeviceGetLBProvisioningResources()

NTSTATUS ClassDeviceGetLBProvisioningResources ( _In_ PDEVICE_OBJECT  DeviceObject,
_Inout_ PIRP  Irp,
_Inout_ PSCSI_REQUEST_BLOCK  Srb 
)

Definition at line 5087 of file utils.c.

5113{
5116 PSTORAGE_LB_PROVISIONING_MAP_RESOURCES mapResources = (PSTORAGE_LB_PROVISIONING_MAP_RESOURCES)Irp->AssociatedIrp.SystemBuffer;
5117
5119 Srb,
5120 irpStack->Parameters.DeviceIoControl.OutputBufferLength,
5121 mapResources);
5122
5123 if (NT_SUCCESS(status)) {
5124 Irp->IoStatus.Information = mapResources->Size;
5125 } else {
5126 Irp->IoStatus.Information = 0;
5127 }
5128
5129 Irp->IoStatus.Status = status;
5132
5133 return status;
5134}
struct _STORAGE_LB_PROVISIONING_MAP_RESOURCES * PSTORAGE_LB_PROVISIONING_MAP_RESOURCES

Referenced by ClassDeviceControl().

◆ ClassDeviceHwFirmwareActivateProcess()

NTSTATUS ClassDeviceHwFirmwareActivateProcess ( _In_ PDEVICE_OBJECT  DeviceObject,
_Inout_ PIRP  Irp,
_Inout_ PSCSI_REQUEST_BLOCK  Srb 
)

Definition at line 8902 of file utils.c.

8907{
8909
8910#if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
8911
8912 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
8913 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
8914
8916 PSTORAGE_HW_FIRMWARE_ACTIVATE firmwareActivate = (PSTORAGE_HW_FIRMWARE_ACTIVATE)Irp->AssociatedIrp.SystemBuffer;
8917 BOOLEAN passDown = FALSE;
8918 PCDB cdb = NULL;
8919 ULONG i;
8920 BOOLEAN lockHeld = FALSE;
8921 KLOCK_QUEUE_HANDLE lockHandle;
8922
8923
8924 //
8925 // Input buffer is not big enough to contain required input information.
8926 //
8927 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_HW_FIRMWARE_ACTIVATE)) {
8928
8930 goto Exit_Firmware_Activate;
8931 }
8932
8933 //
8934 // Input buffer basic validation.
8935 //
8936 if ((firmwareActivate->Version < sizeof(STORAGE_HW_FIRMWARE_ACTIVATE)) ||
8937 (firmwareActivate->Size > irpStack->Parameters.DeviceIoControl.InputBufferLength)) {
8938
8940 goto Exit_Firmware_Activate;
8941 }
8942
8943 //
8944 // Only process the request for a supported port driver.
8945 //
8948 goto Exit_Firmware_Activate;
8949 }
8950
8951 //
8952 // Buffer "FunctionSupportInfo" is allocated during start device process. Following check defends against the situation
8953 // of receiving this IOCTL when the device is created but not started, or device start failed but did not get removed yet.
8954 //
8955 if (commonExtension->IsFdo && (fdoExtension->FunctionSupportInfo == NULL)) {
8956
8958 goto Exit_Firmware_Activate;
8959 }
8960
8961 //
8962 // Process the situation that request should be forwarded to lower level.
8963 //
8964 if (!commonExtension->IsFdo) {
8965 passDown = TRUE;
8966 }
8967
8968 if ((firmwareActivate->Flags & STORAGE_HW_FIRMWARE_REQUEST_FLAG_CONTROLLER) != 0) {
8969 passDown = TRUE;
8970 }
8971
8972 if (passDown) {
8973
8975
8977 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
8978 FREE_POOL(Srb);
8979 return status;
8980 }
8981
8982 //
8983 // If firmware information hasn't been cached in classpnp, retrieve it.
8984 //
8985 if (fdoExtension->FunctionSupportInfo->HwFirmwareInfo == NULL) {
8986 if (fdoExtension->FunctionSupportInfo->HwFirmwareGetInfoSupport == NotSupported) {
8988 goto Exit_Firmware_Activate;
8989 } else {
8990 //
8991 // If this is the first time of retrieving firmware information,
8992 // send request to lower level to get it.
8993 //
8995
8996 if (!NT_SUCCESS(status)) {
8997 goto Exit_Firmware_Activate;
8998 }
8999 }
9000 }
9001
9002 //
9003 // Fail the request if the firmware information cannot be retrieved.
9004 //
9005 if (fdoExtension->FunctionSupportInfo->HwFirmwareInfo == NULL) {
9006 if (fdoExtension->FunctionSupportInfo->HwFirmwareGetInfoSupport == NotSupported) {
9008 } else {
9010 }
9011
9012 goto Exit_Firmware_Activate;
9013 }
9014
9015 //
9016 // Acquire the SyncLock to ensure the HwFirmwareInfo pointer doesn't change
9017 // while we're dereferencing it.
9018 //
9019 lockHeld = TRUE;
9020 KeAcquireInStackQueuedSpinLock(&fdoExtension->FunctionSupportInfo->SyncLock, &lockHandle);
9021
9022 //
9023 // Validate the device support
9024 //
9025 if (fdoExtension->FunctionSupportInfo->HwFirmwareInfo->SupportUpgrade == FALSE) {
9027 goto Exit_Firmware_Activate;
9028 }
9029
9030 //
9031 // Check if the slot number is valid.
9032 //
9033 for (i = 0; i < fdoExtension->FunctionSupportInfo->HwFirmwareInfo->SlotCount; i++) {
9034 if (fdoExtension->FunctionSupportInfo->HwFirmwareInfo->Slot[i].SlotNumber == firmwareActivate->Slot) {
9035 break;
9036 }
9037 }
9038
9039 if (i >= fdoExtension->FunctionSupportInfo->HwFirmwareInfo->SlotCount) {
9040 //
9041 // Either the slot number is out of scope or the slot is read-only.
9042 //
9044 goto Exit_Firmware_Activate;
9045 }
9046
9047 //
9048 // We're done accessing HwFirmwareInfo at this point so we can release
9049 // the SyncLock.
9050 //
9051 NT_ASSERT(lockHeld);
9052 KeReleaseInStackQueuedSpinLock(&lockHandle);
9053 lockHeld = FALSE;
9054
9055 //
9056 // Process the request by translating it into WRITE BUFFER command.
9057 //
9058 //
9059 // Setup the CDB. This should be an untagged request.
9060 //
9062 cdb = SrbGetCdb(Srb);
9063 cdb->WRITE_BUFFER.OperationCode = SCSIOP_WRITE_DATA_BUFF;
9064 cdb->WRITE_BUFFER.Mode = SCSI_WRITE_BUFFER_MODE_ACTIVATE_DEFERRED_MICROCODE;
9065 cdb->WRITE_BUFFER.ModeSpecific = 0; //Reserved for Mode 0x0F
9066 cdb->WRITE_BUFFER.BufferID = firmwareActivate->Slot; //NOTE: this field will be ignored by SCSI device.
9067
9068 //
9069 // Set timeout value.
9070 //
9072
9073 //
9074 // This routine uses a completion routine - ClassIoComplete() so we don't want to release
9075 // the remove lock until then.
9076 //
9078 Srb,
9079 Irp,
9080 NULL,
9081 0,
9082 FALSE);
9083
9084 if (status != STATUS_PENDING) {
9085 //
9086 // If the irp cannot be sent down, the Srb has been freed. NULL it to prevent from freeing it again.
9087 //
9088 Srb = NULL;
9089
9090 goto Exit_Firmware_Activate;
9091 }
9092
9093 return status;
9094
9095Exit_Firmware_Activate:
9096
9097 //
9098 // Release the SyncLock if it's still held.
9099 // This should only happen in the failure path.
9100 //
9101 if (lockHeld) {
9102 KeReleaseInStackQueuedSpinLock(&lockHandle);
9103 lockHeld = FALSE;
9104 }
9105
9106 //
9107 // Firmware Activate request will be failed.
9108 //
9110
9111 Irp->IoStatus.Status = status;
9112
9113#else
9115 Irp->IoStatus.Status = status;
9116#endif // #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
9117
9120
9121 FREE_POOL(Srb);
9122 return status;
9123}
unsigned char BOOLEAN
#define CDB10GENERIC_LENGTH
Definition: cdrw_hw.h:831
#define SCSIOP_WRITE_DATA_BUFF
Definition: cdrw_hw.h:922
@ NotSupported
Definition: classpnp.h:734
SCSIPORT_API NTSTATUS NTAPI ClassSendSrbAsynchronous(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PSCSI_REQUEST_BLOCK Srb, _In_ PIRP Irp, _In_reads_bytes_opt_(BufferLength) __drv_aliasesMem PVOID BufferAddress, _In_ ULONG BufferLength, _In_ BOOLEAN WriteToDevice)
#define TRUE
Definition: types.h:120
NTSTATUS ClasspGetHwFirmwareInfo(_In_ PDEVICE_OBJECT DeviceObject)
Definition: utils.c:8190
#define FIRMWARE_ACTIVATE_TIMEOUT_VALUE
Definition: utils.c:37
__inline BOOLEAN ClassDeviceHwFirmwareIsPortDriverSupported(_In_ PDEVICE_OBJECT DeviceObject)
Definition: utils.c:8330
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
VOID FASTCALL KeAcquireInStackQueuedSpinLock(IN PKSPIN_LOCK SpinLock, IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:130
VOID FASTCALL KeReleaseInStackQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:166
if(dx< 0)
Definition: linetemp.h:194
#define IoCopyCurrentIrpStackLocationToNext(Irp)
Definition: ntifs_ex.h:413
#define IoCallDriver
Definition: irp.c:1225
#define STATUS_PENDING
Definition: ntstatus.h:82
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239
FORCEINLINE VOID SrbSetCdbLength(_In_ PVOID Srb, _In_ UCHAR CdbLength)
Definition: srbhelper.h:1093
FORCEINLINE VOID SrbSetTimeOutValue(_In_ PVOID Srb, _In_ ULONG TimeOutValue)
Definition: srbhelper.h:821
PDEVICE_OBJECT LowerDeviceObject
Definition: classpnp.h:598
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133
Definition: cdrw_hw.h:28
#define SrbGetCdb(srb)
Definition: usbstor.h:17

Referenced by ClassDeviceControl().

◆ ClassDeviceHwFirmwareDownloadProcess()

NTSTATUS ClassDeviceHwFirmwareDownloadProcess ( _In_ PDEVICE_OBJECT  DeviceObject,
_Inout_ PIRP  Irp,
_Inout_ PSCSI_REQUEST_BLOCK  Srb 
)

Definition at line 8541 of file utils.c.

8546{
8548
8549#if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
8550
8551 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
8552 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
8553
8555 PSTORAGE_HW_FIRMWARE_DOWNLOAD firmwareDownload = (PSTORAGE_HW_FIRMWARE_DOWNLOAD)Irp->AssociatedIrp.SystemBuffer;
8556 BOOLEAN passDown = FALSE;
8557 ULONG i;
8558 ULONG bufferSize = 0;
8559 PUCHAR firmwareImageBuffer = NULL;
8560 PIRP irp2 = NULL;
8561 PIO_STACK_LOCATION newStack = NULL;
8562 PCDB cdb = NULL;
8563 BOOLEAN lockHeld = FALSE;
8564 KLOCK_QUEUE_HANDLE lockHandle;
8565
8566
8567 //
8568 // Input buffer is not big enough to contain required input information.
8569 //
8570 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_HW_FIRMWARE_DOWNLOAD)) {
8571
8573 goto Exit_Firmware_Download;
8574 }
8575
8576 //
8577 // Input buffer basic validation.
8578 //
8579 if ((firmwareDownload->Version < sizeof(STORAGE_HW_FIRMWARE_DOWNLOAD)) ||
8580 (firmwareDownload->Size > irpStack->Parameters.DeviceIoControl.InputBufferLength) ||
8581 ((firmwareDownload->BufferSize + FIELD_OFFSET(STORAGE_HW_FIRMWARE_DOWNLOAD, ImageBuffer)) > firmwareDownload->Size)) {
8582
8584 goto Exit_Firmware_Download;
8585 }
8586
8587 //
8588 // Only process the request for a supported port driver.
8589 //
8592 goto Exit_Firmware_Download;
8593 }
8594
8595 //
8596 // Buffer "FunctionSupportInfo" is allocated during start device process. Following check defends against the situation
8597 // of receiving this IOCTL when the device is created but not started, or device start failed but did not get removed yet.
8598 //
8599 if (commonExtension->IsFdo && (fdoExtension->FunctionSupportInfo == NULL)) {
8600
8602 goto Exit_Firmware_Download;
8603 }
8604
8605 //
8606 // Process the situation that request should be forwarded to lower level.
8607 //
8608 if (!commonExtension->IsFdo) {
8609 passDown = TRUE;
8610 }
8611
8612 if ((firmwareDownload->Flags & STORAGE_HW_FIRMWARE_REQUEST_FLAG_CONTROLLER) != 0) {
8613 passDown = TRUE;
8614 }
8615
8616 if (passDown) {
8617
8619
8621 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
8622 FREE_POOL(Srb);
8623 return status;
8624 }
8625
8626 //
8627 // If firmware information hasn't been cached in classpnp, retrieve it.
8628 //
8629 if (fdoExtension->FunctionSupportInfo->HwFirmwareInfo == NULL) {
8630 if (fdoExtension->FunctionSupportInfo->HwFirmwareGetInfoSupport == NotSupported) {
8632 goto Exit_Firmware_Download;
8633 } else {
8634 //
8635 // If this is the first time of retrieving firmware information,
8636 // send request to lower level to get it.
8637 //
8639
8640 if (!NT_SUCCESS(status)) {
8641 goto Exit_Firmware_Download;
8642 }
8643 }
8644 }
8645
8646 //
8647 // Fail the request if the firmware information cannot be retrieved.
8648 //
8649 if (fdoExtension->FunctionSupportInfo->HwFirmwareInfo == NULL) {
8650 if (fdoExtension->FunctionSupportInfo->HwFirmwareGetInfoSupport == NotSupported) {
8652 } else {
8654 }
8655
8656 goto Exit_Firmware_Download;
8657 }
8658
8659 //
8660 // Acquire the SyncLock to ensure the HwFirmwareInfo pointer doesn't change
8661 // while we're dereferencing it.
8662 //
8663 lockHeld = TRUE;
8664 KeAcquireInStackQueuedSpinLock(&fdoExtension->FunctionSupportInfo->SyncLock, &lockHandle);
8665
8666 //
8667 // Validate the device support
8668 //
8669 if ((fdoExtension->FunctionSupportInfo->HwFirmwareInfo->SupportUpgrade == FALSE) ||
8670 (fdoExtension->FunctionSupportInfo->HwFirmwareInfo->ImagePayloadAlignment == 0)) {
8672 goto Exit_Firmware_Download;
8673 }
8674
8675 //
8676 // Check if the slot can be used to hold firmware image.
8677 //
8678 for (i = 0; i < fdoExtension->FunctionSupportInfo->HwFirmwareInfo->SlotCount; i++) {
8679 if (fdoExtension->FunctionSupportInfo->HwFirmwareInfo->Slot[i].SlotNumber == firmwareDownload->Slot) {
8680 break;
8681 }
8682 }
8683
8684 if ((i >= fdoExtension->FunctionSupportInfo->HwFirmwareInfo->SlotCount) ||
8685 (fdoExtension->FunctionSupportInfo->HwFirmwareInfo->Slot[i].ReadOnly == TRUE)) {
8686 //
8687 // Either the slot number is out of scope or the slot is read-only.
8688 //
8690 goto Exit_Firmware_Download;
8691 }
8692
8693 //
8694 // Buffer size and alignment validation.
8695 // Max Offset and Buffer Size can be represented by SCSI command is max value for 3 bytes.
8696 //
8697 if ((firmwareDownload->BufferSize == 0) ||
8698 ((firmwareDownload->BufferSize % fdoExtension->FunctionSupportInfo->HwFirmwareInfo->ImagePayloadAlignment) != 0) ||
8699 (firmwareDownload->BufferSize > fdoExtension->FunctionSupportInfo->HwFirmwareInfo->ImagePayloadMaxSize) ||
8700 (firmwareDownload->BufferSize > fdoExtension->AdapterDescriptor->MaximumTransferLength) ||
8701 ((firmwareDownload->Offset % fdoExtension->FunctionSupportInfo->HwFirmwareInfo->ImagePayloadAlignment) != 0) ||
8702 (firmwareDownload->Offset > 0xFFFFFF) ||
8703 (firmwareDownload->BufferSize > 0xFFFFFF)) {
8704
8706 goto Exit_Firmware_Download;
8707 }
8708
8709
8710 //
8711 // Process the request by translating it into WRITE BUFFER command.
8712 //
8713 if (((ULONG_PTR)firmwareDownload->ImageBuffer % fdoExtension->FunctionSupportInfo->HwFirmwareInfo->ImagePayloadAlignment) != 0) {
8714 //
8715 // Allocate buffer aligns to ImagePayloadAlignment to accommodate the alignment requirement.
8716 //
8717 bufferSize = ALIGN_UP_BY(firmwareDownload->BufferSize, fdoExtension->FunctionSupportInfo->HwFirmwareInfo->ImagePayloadAlignment);
8718
8719 //
8720 // We're done accessing HwFirmwareInfo at this point so we can release
8721 // the SyncLock.
8722 //
8723 NT_ASSERT(lockHeld);
8724 KeReleaseInStackQueuedSpinLock(&lockHandle);
8725 lockHeld = FALSE;
8726
8727#ifdef _MSC_VER
8728#pragma prefast(suppress:6014, "The allocated memory that firmwareImageBuffer points to will be freed in ClassHwFirmwareDownloadComplete().")
8729#endif
8730 firmwareImageBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, bufferSize, CLASSPNP_POOL_TAG_FIRMWARE);
8731
8732 if (firmwareImageBuffer == NULL) {
8734 goto Exit_Firmware_Download;
8735 }
8736
8737 RtlZeroMemory(firmwareImageBuffer, bufferSize);
8738
8739 RtlCopyMemory(firmwareImageBuffer, firmwareDownload->ImageBuffer, (ULONG)firmwareDownload->BufferSize);
8740
8741 } else {
8742 NT_ASSERT(lockHeld);
8743 KeReleaseInStackQueuedSpinLock(&lockHandle);
8744 lockHeld = FALSE;
8745
8746 firmwareImageBuffer = firmwareDownload->ImageBuffer;
8747 bufferSize = (ULONG)firmwareDownload->BufferSize;
8748 }
8749
8750 //
8751 // Allocate a new irp to send the WRITE BUFFER command down.
8752 // Similar process as IOCTL_STORAGE_CHECK_VERIFY.
8753 //
8754 irp2 = IoAllocateIrp((CCHAR)(DeviceObject->StackSize + 3), FALSE);
8755
8756 if (irp2 == NULL) {
8758
8759 if (firmwareImageBuffer != firmwareDownload->ImageBuffer) {
8760 FREE_POOL(firmwareImageBuffer);
8761 }
8762
8763 goto Exit_Firmware_Download;
8764 }
8765
8766 //
8767 // Make sure to acquire the lock for the new irp.
8768 //
8770
8771 irp2->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
8773
8774 //
8775 // Set the top stack location and shove the master Irp into the
8776 // top location
8777 //
8778 newStack = IoGetCurrentIrpStackLocation(irp2);
8779 newStack->Parameters.Others.Argument1 = Irp;
8780 newStack->DeviceObject = DeviceObject;
8781
8782 //
8783 // Stick the firmware download completion routine onto the stack
8784 // and prepare the irp for the port driver
8785 //
8787 ClassHwFirmwareDownloadComplete,
8788 (firmwareImageBuffer != firmwareDownload->ImageBuffer) ? firmwareImageBuffer : NULL,
8789 TRUE,
8790 TRUE,
8791 TRUE);
8792
8794 newStack = IoGetCurrentIrpStackLocation(irp2);
8795 newStack->DeviceObject = DeviceObject;
8796 newStack->MajorFunction = irpStack->MajorFunction;
8797 newStack->MinorFunction = irpStack->MinorFunction;
8798 newStack->Flags = irpStack->Flags;
8799
8800
8801 //
8802 // Mark the master irp as pending - whether the lower level
8803 // driver completes it immediately or not this should allow it
8804 // to go all the way back up.
8805 //
8807
8808 //
8809 // Setup the CDB.
8810 //
8812 cdb = SrbGetCdb(Srb);
8813 cdb->WRITE_BUFFER.OperationCode = SCSIOP_WRITE_DATA_BUFF;
8814 cdb->WRITE_BUFFER.Mode = SCSI_WRITE_BUFFER_MODE_DOWNLOAD_MICROCODE_WITH_OFFSETS_SAVE_DEFER_ACTIVATE;
8815 cdb->WRITE_BUFFER.ModeSpecific = 0; //Reserved for Mode 0x0E
8816 cdb->WRITE_BUFFER.BufferID = firmwareDownload->Slot;
8817
8818 cdb->WRITE_BUFFER.BufferOffset[0] = *((PCHAR)&firmwareDownload->Offset + 2);
8819 cdb->WRITE_BUFFER.BufferOffset[1] = *((PCHAR)&firmwareDownload->Offset + 1);
8820 cdb->WRITE_BUFFER.BufferOffset[2] = *((PCHAR)&firmwareDownload->Offset);
8821
8822 cdb->WRITE_BUFFER.ParameterListLength[0] = *((PCHAR)&bufferSize + 2);
8823 cdb->WRITE_BUFFER.ParameterListLength[1] = *((PCHAR)&bufferSize + 1);
8824 cdb->WRITE_BUFFER.ParameterListLength[2] = *((PCHAR)&bufferSize);
8825
8826 //
8827 // Send as a tagged command.
8828 //
8831
8832 //
8833 // Set timeout value.
8834 //
8835 SrbSetTimeOutValue(Srb, fdoExtension->TimeOutValue);
8836
8837 //
8838 // This routine uses a completion routine so we don't want to release
8839 // the remove lock until then.
8840 //
8842 Srb,
8843 irp2,
8844 firmwareImageBuffer,
8845 bufferSize,
8846 TRUE);
8847
8848 if (status != STATUS_PENDING) {
8849 //
8850 // If the new irp cannot be sent down, free allocated memory and bail out.
8851 //
8852 if (firmwareImageBuffer != firmwareDownload->ImageBuffer) {
8853 FREE_POOL(firmwareImageBuffer);
8854 }
8855
8856 //
8857 // If the irp cannot be sent down, the Srb has been freed. NULL it to prevent from freeing it again.
8858 //
8859 Srb = NULL;
8860
8862
8863 IoFreeIrp(irp2);
8864
8865 goto Exit_Firmware_Download;
8866 }
8867
8868 return status;
8869
8870Exit_Firmware_Download:
8871
8872 //
8873 // Release the SyncLock if it's still held.
8874 // This should only happen in the failure path.
8875 //
8876 if (lockHeld) {
8877 KeReleaseInStackQueuedSpinLock(&lockHandle);
8878 lockHeld = FALSE;
8879 }
8880
8881 //
8882 // Firmware Download request will be failed.
8883 //
8885
8886 Irp->IoStatus.Status = status;
8887
8888#else
8890 Irp->IoStatus.Status = status;
8891#endif // #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
8892
8895
8896 FREE_POOL(Srb);
8897
8898 return status;
8899}
#define ALIGN_UP_BY(size, align)
#define CLASSPNP_POOL_TAG_FIRMWARE
Definition: classp.h:198
#define ClassAcquireRemoveLock(devobj, tag)
Definition: classpnp.h:100
#define SRB_FLAGS_QUEUE_ACTION_ENABLE
Definition: srb.h:395
#define SRB_HEAD_OF_QUEUE_TAG_REQUEST
Definition: srb.h:424
#define SRB_FLAGS_NO_QUEUE_FREEZE
Definition: srb.h:404
size_t bufferSize
IoMarkIrpPending(Irp)
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:498
#define PCHAR
Definition: match.c:90
PIRP NTAPI IoAllocateIrp(IN CCHAR StackSize, IN BOOLEAN ChargeQuota)
Definition: irp.c:615
FORCEINLINE VOID SrbSetSrbFlags(_In_ PVOID Srb, _In_ ULONG Flags)
Definition: srbhelper.h:964
FORCEINLINE VOID SrbSetRequestAttribute(_In_ PVOID Srb, _In_ UCHAR RequestAttribute)
Definition: srbhelper.h:1131
PSTORAGE_ADAPTER_DESCRIPTOR AdapterDescriptor
Definition: classpnp.h:877
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
unsigned char * PUCHAR
Definition: typedefs.h:53
char CCHAR
Definition: typedefs.h:51
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
FORCEINLINE VOID IoSetNextIrpStackLocation(_Inout_ PIRP Irp)
Definition: iofuncs.h:2680

Referenced by ClassDeviceControl().

◆ ClassDeviceHwFirmwareGetInfoProcess()

NTSTATUS ClassDeviceHwFirmwareGetInfoProcess ( _In_ PDEVICE_OBJECT  DeviceObject,
_Inout_ PIRP  Irp 
)

Definition at line 8366 of file utils.c.

8385{
8387
8388#if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
8389
8390 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
8391 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
8393 PSTORAGE_HW_FIRMWARE_INFO_QUERY query = (PSTORAGE_HW_FIRMWARE_INFO_QUERY)Irp->AssociatedIrp.SystemBuffer;
8394 BOOLEAN passDown = FALSE;
8395 BOOLEAN copyData = FALSE;
8396
8397
8398 //
8399 // Input buffer is not big enough to contain required input information.
8400 //
8401 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_HW_FIRMWARE_INFO_QUERY)) {
8402
8404 goto Exit_Firmware_Get_Info;
8405 }
8406
8407 //
8408 // Output buffer is too small to contain return data.
8409 //
8410 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_HW_FIRMWARE_INFO)) {
8411
8413 goto Exit_Firmware_Get_Info;
8414 }
8415
8416 //
8417 // Only process the request for a supported port driver.
8418 //
8421 goto Exit_Firmware_Get_Info;
8422 }
8423
8424 //
8425 // Buffer "FunctionSupportInfo" is allocated during start device process. Following check defends against the situation
8426 // of receiving this IOCTL when the device is created but not started, or device start failed but did not get removed yet.
8427 //
8428 if (commonExtension->IsFdo && (fdoExtension->FunctionSupportInfo == NULL)) {
8429
8431 goto Exit_Firmware_Get_Info;
8432 }
8433
8434 //
8435 // Process the situation that request should be forwarded to lower level.
8436 //
8437 if (!commonExtension->IsFdo) {
8438 passDown = TRUE;
8439 }
8440
8441 if ((query->Flags & STORAGE_HW_FIRMWARE_REQUEST_FLAG_CONTROLLER) != 0) {
8442 passDown = TRUE;
8443 }
8444
8445 if (passDown) {
8446
8448
8450 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
8451 return status;
8452 }
8453
8454 //
8455 // The request is for a FDO. Process the request.
8456 //
8457 if (fdoExtension->FunctionSupportInfo->HwFirmwareGetInfoSupport == NotSupported) {
8459 goto Exit_Firmware_Get_Info;
8460 } else {
8461 //
8462 // Retrieve information from lower layer for the request. The cached information is not used
8463 // in case device firmware information changed.
8464 //
8466 copyData = NT_SUCCESS(status);
8467 }
8468
8469Exit_Firmware_Get_Info:
8470
8471 if (copyData) {
8472 //
8473 // Firmware information is already cached in classpnp. Return a copy.
8474 //
8475 KLOCK_QUEUE_HANDLE lockHandle;
8476 KeAcquireInStackQueuedSpinLock(&fdoExtension->FunctionSupportInfo->SyncLock, &lockHandle);
8477
8478 ULONG dataLength = min(irpStack->Parameters.DeviceIoControl.OutputBufferLength, fdoExtension->FunctionSupportInfo->HwFirmwareInfo->Size);
8479
8480 memcpy(Irp->AssociatedIrp.SystemBuffer, fdoExtension->FunctionSupportInfo->HwFirmwareInfo, dataLength);
8481
8482 KeReleaseInStackQueuedSpinLock(&lockHandle);
8483
8484 Irp->IoStatus.Information = dataLength;
8485 }
8486
8487 Irp->IoStatus.Status = status;
8488
8489#else
8491 Irp->IoStatus.Status = status;
8492#endif // #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
8493
8496
8497 return status;
8498}
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
ULONG dataLength
Definition: scsi.h:3751

Referenced by ClassDeviceControl().

◆ ClassDeviceHwFirmwareIsPortDriverSupported()

__inline BOOLEAN ClassDeviceHwFirmwareIsPortDriverSupported ( _In_ PDEVICE_OBJECT  DeviceObject)

Definition at line 8330 of file utils.c.

8346{
8347 //
8348 // If the request is for a FDO, process the request for Storport, SDstor and Spaceport only.
8349 // Don't process it if we don't have a miniport descriptor.
8350 //
8351 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
8352 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
8353
8354 BOOLEAN isSupported = FALSE;
8355 if (commonExtension->IsFdo && (fdoExtension->MiniportDescriptor != NULL)) {
8356 isSupported = ((fdoExtension->MiniportDescriptor->Portdriver == StoragePortCodeSetStorport) ||
8357 (fdoExtension->MiniportDescriptor->Portdriver == StoragePortCodeSetSpaceport) ||
8358 (fdoExtension->MiniportDescriptor->Portdriver == StoragePortCodeSetSDport ));
8359 }
8360
8361 return isSupported;
8362}
@ StoragePortCodeSetStorport
Definition: ntddstor.h:619
@ StoragePortCodeSetSpaceport
Definition: ntddstor.h:621
@ StoragePortCodeSetSDport
Definition: ntddstor.h:625

Referenced by ClassDeviceHwFirmwareActivateProcess(), ClassDeviceHwFirmwareDownloadProcess(), and ClassDeviceHwFirmwareGetInfoProcess().

◆ ClassGetLBProvisioningLogPage()

NTSTATUS ClassGetLBProvisioningLogPage ( _In_ PDEVICE_OBJECT  DeviceObject,
_In_ PSCSI_REQUEST_BLOCK  Srb,
_In_ ULONG  LogPageSize,
_Inout_ PLOG_PAGE_LOGICAL_BLOCK_PROVISIONING  LogPage 
)

Definition at line 4679 of file utils.c.

4707{
4710 PCDB cdb = NULL;
4711
4712 //
4713 // Make sure the caller passed in an adequate output buffer. The Allocation
4714 // Length field in the Log Sense command is only 2 bytes so we need to also
4715 // make sure that the given log page size isn't larger than MAXUSHORT.
4716 //
4717 if (LogPage == NULL ||
4718 LogPageSize < sizeof(LOG_PAGE_LOGICAL_BLOCK_PROVISIONING) ||
4719 LogPageSize > MAXUSHORT)
4720 {
4721 TracePrint((TRACE_LEVEL_ERROR,
4722 TRACE_FLAG_GENERAL,
4723 "ClassGetLBProvisioningLogPage: DO (%p), Invalid parameter, LogPage = %p, LogPageSize = %u.\n",
4725 LogPage,
4726 LogPageSize));
4727
4729 }
4730
4731 //
4732 // Initialize the SRB.
4733 //
4734 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4738 1,
4740 if (NT_SUCCESS(status)) {
4742 } else {
4743 //
4744 // Should not occur.
4745 //
4747 }
4748 } else {
4750 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
4752 }
4753
4754 //
4755 // Build and send down the Log Sense command.
4756 //
4757 SrbSetTimeOutValue(Srb, fdoExtension->TimeOutValue);
4760 SrbAssignSrbFlags(Srb, fdoExtension->SrbFlags);
4761 SrbSetCdbLength(Srb, sizeof(cdb->LOGSENSE));
4762
4763 cdb = SrbGetCdb(Srb);
4764 cdb->LOGSENSE.OperationCode = SCSIOP_LOG_SENSE;
4765 cdb->LOGSENSE.PageCode = LOG_PAGE_CODE_LOGICAL_BLOCK_PROVISIONING;
4766 cdb->LOGSENSE.PCBit = 0;
4767 cdb->LOGSENSE.ParameterPointer[0] = 0;
4768 cdb->LOGSENSE.ParameterPointer[1] = 0;
4769 REVERSE_BYTES_SHORT(&(cdb->LOGSENSE.AllocationLength), &LogPageSize);
4770
4772 Srb,
4773 LogPage,
4774 LogPageSize,
4775 FALSE);
4776
4777 //
4778 // Handle the case where we get back STATUS_DATA_OVERRUN b/c the input
4779 // buffer was larger than necessary.
4780 //
4781 if (status == STATUS_DATA_OVERRUN &&
4782 SrbGetDataTransferLength(Srb) < LogPageSize)
4783 {
4785 }
4786
4787 //
4788 // Log the command.
4789 //
4790 TracePrint((TRACE_LEVEL_INFORMATION,
4791 TRACE_FLAG_IOCTL,
4792 "ClassGetLBProvisioningLogPage: DO (%p), LogSense command issued for LBP log page. NT Status: %!STATUS!.\n",
4794 status
4795 ));
4796
4797 return status;
4798}
#define SCSIOP_LOG_SENSE
Definition: cdrw_hw.h:937
NTSTATUS InitializeStorageRequestBlock(_Inout_bytecount_(ByteSize) PSTORAGE_REQUEST_BLOCK Srb, _In_ USHORT AddressType, _In_ ULONG ByteSize, _In_ ULONG NumSrbExData,...)
Definition: srblib.c:206
NTSTATUS NTAPI ClassSendSrbSynchronous(_In_ PDEVICE_OBJECT Fdo, _Inout_ PSCSI_REQUEST_BLOCK _Srb, _In_reads_bytes_opt_(BufferLength) PVOID BufferAddress, _In_ ULONG BufferLength, _In_ BOOLEAN WriteToDevice)
Definition: class.c:4042
#define SP_UNTAGGED
Definition: srb.h:233
#define SRB_FUNCTION_EXECUTE_SCSI
Definition: srb.h:315
#define SRB_SIMPLE_TAG_REQUEST
Definition: srb.h:423
#define LOG_PAGE_CODE_LOGICAL_BLOCK_PROVISIONING
Definition: scsi.h:3262
#define REVERSE_BYTES_SHORT(Destination, Source)
Definition: scsi.h:3474
#define STORAGE_ADDRESS_TYPE_BTL8
Definition: srb.h:657
* PSTORAGE_REQUEST_BLOCK
Definition: srb.h:652
@ SrbExDataTypeScsiCdb16
Definition: srb.h:450
FORCEINLINE VOID SrbAssignSrbFlags(_In_ PVOID Srb, _In_ ULONG Flags)
Definition: srbhelper.h:946
#define SrbSetRequestTag
Definition: srbhelper.h:869
FORCEINLINE ULONG SrbGetDataTransferLength(_In_ PVOID Srb)
Definition: srbhelper.h:765
PDEVICE_OBJECT DeviceObject
Definition: classpnp.h:871
UCHAR Function
Definition: srb.h:250
USHORT Length
Definition: srb.h:249
#define MAXUSHORT
Definition: typedefs.h:83
#define STATUS_DATA_OVERRUN
Definition: udferr_usr.h:152

Referenced by ClassGetLBProvisioningResources().

◆ ClassGetLBProvisioningResources()

NTSTATUS ClassGetLBProvisioningResources ( _In_ PDEVICE_OBJECT  DeviceObject,
_Inout_ PSCSI_REQUEST_BLOCK  Srb,
_In_ ULONG  ResourcesSize,
_Inout_ PSTORAGE_LB_PROVISIONING_MAP_RESOURCES  Resources 
)

Definition at line 4958 of file utils.c.

4995{
4998 ULONG logPageSize;
5000
5001 //
5002 // This functionality is only supported for devices that support logical
5003 // block provisioning.
5004 //
5005 if (fdoExtension->FunctionSupportInfo->ValidInquiryPages.LBProvisioning == FALSE)
5006 {
5007 TracePrint((TRACE_LEVEL_ERROR,
5008 TRACE_FLAG_GENERAL,
5009 "ClassGetLBProvisioningResources: DO (%p), Device does not support logical block provisioning.\n",
5010 DeviceObject));
5011
5012 return STATUS_NOT_SUPPORTED;
5013 }
5014
5015 //
5016 // Validate the output buffer.
5017 //
5018 if (Resources == NULL ||
5019 ResourcesSize < sizeof(STORAGE_LB_PROVISIONING_MAP_RESOURCES))
5020 {
5021 TracePrint((TRACE_LEVEL_ERROR,
5022 TRACE_FLAG_GENERAL,
5023 "ClassGetLBProvisioningResources: DO (%p), Invalid parameter, Resources = %p, ResourcesSize = %u.\n",
5025 Resources,
5026 ResourcesSize));
5027
5029 }
5030
5031 //
5032 // Allocate a buffer for the log page. Currently the log page contains:
5033 // 1. Log page header
5034 // 2. Log page parameter for used resources
5035 // 3. Log page parameter for available resources
5036 //
5038
5039#if defined(_ARM_) || defined(_ARM64_)
5040 //
5041 // ARM has specific alignment requirements, although this will not have a functional impact on x86 or amd64
5042 // based platforms. We are taking the conservative approach here.
5043 //
5044 logPageSize = ALIGN_UP_BY(logPageSize, KeGetRecommendedSharedDataAlignment());
5045 logPage = (PLOG_PAGE_LOGICAL_BLOCK_PROVISIONING)ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, logPageSize, CLASS_TAG_LB_PROVISIONING);
5046#else
5048#endif
5049 if (logPage != NULL)
5050 {
5051 //
5052 // Get the LBP log page from the device.
5053 //
5055 Srb,
5056 logPageSize,
5057 logPage);
5058
5059 if (NT_SUCCESS(status))
5060 {
5061 //
5062 // Interpret the log page and fill in the output buffer.
5063 //
5065 logPageSize,
5066 logPage,
5067 ResourcesSize,
5068 Resources);
5069 }
5070
5071 ExFreePool(logPage);
5072 }
5073 else
5074 {
5075 TracePrint((TRACE_LEVEL_ERROR,
5076 TRACE_FLAG_GENERAL,
5077 "ClassGetLBProvisioningResources: DO (%p), Failed to allocate memory for LBP log page.\n",
5078 DeviceObject));
5079
5081 }
5082
5083 return status;
5084}
#define CLASS_TAG_LB_PROVISIONING
Definition: classpnp.h:89
NTSTATUS ClassInterpretLBProvisioningLogPage(_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG LogPageSize, _In_ PLOG_PAGE_LOGICAL_BLOCK_PROVISIONING LogPage, _In_ ULONG ResourcesSize, _Out_ PSTORAGE_LB_PROVISIONING_MAP_RESOURCES Resources)
Definition: utils.c:4800
NTSTATUS ClassGetLBProvisioningLogPage(_In_ PDEVICE_OBJECT DeviceObject, _In_ PSCSI_REQUEST_BLOCK Srb, _In_ ULONG LogPageSize, _Inout_ PLOG_PAGE_LOGICAL_BLOCK_PROVISIONING LogPage)
Definition: utils.c:4679
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
ULONG NTAPI KeGetRecommendedSharedDataAlignment(VOID)
Definition: cpu.c:496
struct _LOG_PAGE_LOGICAL_BLOCK_PROVISIONING * PLOG_PAGE_LOGICAL_BLOCK_PROVISIONING
struct _LOG_PAGE_LOGICAL_BLOCK_PROVISIONING LOG_PAGE_LOGICAL_BLOCK_PROVISIONING

Referenced by ClassDeviceGetLBProvisioningResources().

◆ ClassInterpretLBProvisioningLogPage()

NTSTATUS ClassInterpretLBProvisioningLogPage ( _In_ PDEVICE_OBJECT  DeviceObject,
_In_ ULONG  LogPageSize,
_In_ PLOG_PAGE_LOGICAL_BLOCK_PROVISIONING  LogPage,
_In_ ULONG  ResourcesSize,
_Out_ PSTORAGE_LB_PROVISIONING_MAP_RESOURCES  Resources 
)

Definition at line 4800 of file utils.c.

4838{
4840 USHORT pageLength;
4841 PLOG_PARAMETER_HEADER parameter;
4842 PVOID endOfPage;
4843 USHORT parameterCode;
4844 ULONG resourceCount;
4845 UCHAR thresholdExponent = fdoExtension->FunctionSupportInfo->LBProvisioningData.ThresholdExponent;
4846 ULONGLONG thresholdSetSize;
4847
4848 //
4849 // SBC-3 states that the threshold exponent (from the 0xB2 VPD page), must
4850 // be non-zero and less than or equal to 32.
4851 //
4852 if (thresholdExponent < 0 || thresholdExponent > 32)
4853 {
4854 TracePrint((TRACE_LEVEL_ERROR,
4855 TRACE_FLAG_GENERAL,
4856 "ClassInterpretLBProvisioningLogPage: DO (%p), Threshold Exponent (%u) is invalid.\n",
4858 thresholdExponent));
4859
4860 return STATUS_NOT_SUPPORTED;
4861 }
4862
4863 if (Resources == NULL ||
4864 ResourcesSize < sizeof(STORAGE_LB_PROVISIONING_MAP_RESOURCES) ||
4865 LogPage == NULL ||
4866 LogPageSize < sizeof(LOG_PAGE_LOGICAL_BLOCK_PROVISIONING))
4867 {
4868 TracePrint((TRACE_LEVEL_ERROR,
4869 TRACE_FLAG_GENERAL,
4870 "ClassInterpretLBProvisioningLogPage: DO (%p), Invalid parameter, Resources = %p, ResourcesSize = %u, LogPage = %p, LogPageSize = %u.\n",
4872 Resources,
4873 ResourcesSize,
4874 LogPage,
4875 LogPageSize));
4876
4878 }
4879
4880 //
4881 // Calculate the threshold set size (in LBAs).
4882 //
4883 thresholdSetSize = 1ULL << thresholdExponent;
4884
4885 REVERSE_BYTES_SHORT(&pageLength, &(LogPage->PageLength));
4886
4887 //
4888 // Initialize the output buffer.
4889 //
4893
4894 //
4895 // Make sure we don't walk off the end of the log page buffer
4896 // if pageLength is somehow longer than the buffer itself.
4897 //
4898 pageLength = (USHORT)min(pageLength, (LogPageSize - FIELD_OFFSET(LOG_PAGE_LOGICAL_BLOCK_PROVISIONING, Parameters)));
4899
4901 endOfPage = (PVOID)((PUCHAR)parameter + pageLength);
4902
4903 //
4904 // Walk the parameters.
4905 //
4906 while ((PVOID)parameter < endOfPage)
4907 {
4908 if (parameter->ParameterLength > 0)
4909 {
4910 REVERSE_BYTES_SHORT(&parameterCode, &(parameter->ParameterCode));
4911 switch(parameterCode)
4912 {
4914 {
4916 Resources->AvailableMappingResources = (ULONGLONG)resourceCount * thresholdSetSize * (ULONGLONG)fdoExtension->DiskGeometry.BytesPerSector;
4917 Resources->AvailableMappingResourcesValid = TRUE;
4918
4919 //
4920 // Devices that implement SBC-3 revisions older than r27 will not specify
4921 // an LBP log page parameter that has fields beyond ResourceCount.
4922 //
4923 if (parameter->ParameterLength > FIELD_OFFSET(LOG_PARAMETER_THRESHOLD_RESOURCE_COUNT, ResourceCount[3])) {
4924 Resources->AvailableMappingResourcesScope = ((PLOG_PARAMETER_THRESHOLD_RESOURCE_COUNT)parameter)->Scope;
4925 }
4926
4927 break;
4928 }
4929
4931 {
4933 Resources->UsedMappingResources = (ULONGLONG)resourceCount * thresholdSetSize * (ULONGLONG)fdoExtension->DiskGeometry.BytesPerSector;
4934 Resources->UsedMappingResourcesValid = TRUE;
4935
4936 //
4937 // Devices that implement SBC-3 revisions older than r27 will not specify
4938 // an LBP log page parameter that has fields beyond ResourceCount.
4939 //
4940 if (parameter->ParameterLength > FIELD_OFFSET(LOG_PARAMETER_THRESHOLD_RESOURCE_COUNT, ResourceCount[3])) {
4941 Resources->UsedMappingResourcesScope = ((PLOG_PARAMETER_THRESHOLD_RESOURCE_COUNT)parameter)->Scope;
4942 }
4943
4944 break;
4945 }
4946 }
4947 }
4948
4949 //
4950 // Move to the next parameter.
4951 //
4952 parameter = (PLOG_PARAMETER_HEADER)((PUCHAR)parameter + sizeof(LOG_PARAMETER_HEADER) + parameter->ParameterLength);
4953 }
4954
4955 return STATUS_SUCCESS;
4956}
static ULONG ResourceCount
Definition: inbv.c:50
unsigned short USHORT
Definition: pedump.c:61
struct _LOG_PARAMETER_HEADER LOG_PARAMETER_HEADER
#define LOG_PAGE_LBP_PARAMETER_CODE_USED
Definition: scsi.h:3360
struct _LOG_PARAMETER_THRESHOLD_RESOURCE_COUNT * PLOG_PARAMETER_THRESHOLD_RESOURCE_COUNT
struct _LOG_PARAMETER_HEADER * PLOG_PARAMETER_HEADER
#define LOG_PAGE_LBP_PARAMETER_CODE_AVAILABLE
Definition: scsi.h:3359
#define REVERSE_BYTES(Destination, Source)
Definition: scsi.h:3465
ULONG BytesPerSector
Definition: ntdddisk.h:409
DISK_GEOMETRY DiskGeometry
Definition: classpnp.h:888
void * PVOID
Definition: typedefs.h:50
uint64_t ULONGLONG
Definition: typedefs.h:67
_Must_inspect_result_ _In_ WDFQUEUE _In_opt_ WDFREQUEST _In_opt_ WDFFILEOBJECT _Inout_opt_ PWDF_REQUEST_PARAMETERS Parameters
Definition: wdfio.h:869

Referenced by ClassGetLBProvisioningResources().

◆ ClasspAccessAlignmentProperty()

NTSTATUS ClasspAccessAlignmentProperty ( _In_ PDEVICE_OBJECT  DeviceObject,
_In_ PIRP  Irp,
_Inout_ PSCSI_REQUEST_BLOCK  Srb 
)

Definition at line 1700 of file utils.c.

1709{
1711
1712 PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1714 PSTORAGE_PROPERTY_QUERY query = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer;
1716 ULONG length = 0;
1717 ULONG information = 0;
1718
1720
1721 //
1722 // check registry setting and fail the IOCTL if it's required.
1723 // this registry setting can be used to work around issues which upper layer doesn't support large physical sector size.
1724 //
1725 if (fdoExtension->FunctionSupportInfo->RegAccessAlignmentQueryNotSupported) {
1727 goto Exit;
1728 }
1729
1730 if ( (DeviceObject->DeviceType != FILE_DEVICE_DISK) ||
1731 (TEST_FLAG(DeviceObject->Characteristics, FILE_FLOPPY_DISKETTE)) ||
1732 (fdoExtension->FunctionSupportInfo->LowerLayerSupport.AccessAlignmentProperty == Supported) ) {
1733 // if it's not disk, forward the request to lower layer,
1734 // if the IOCTL is supported by lower stack, forward it down.
1736
1738 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
1739 return status;
1740 }
1741
1742 //
1743 // Check proper query type.
1744 //
1745
1746 if (query->QueryType == PropertyExistsQuery) {
1748 goto Exit;
1749 } else if (query->QueryType != PropertyStandardQuery) {
1751 goto Exit;
1752 }
1753
1754 //
1755 // Request validation.
1756 // Note that InputBufferLength and IsFdo have been validated before entering this routine.
1757 //
1758
1762 goto Exit;
1763 }
1764
1765 // do not touch this buffer because it can still be used as input buffer for lower layer in 'SupportUnknown' case.
1766 accessAlignment = (PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
1767
1768 length = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
1769
1771
1772 if (length >= sizeof(STORAGE_DESCRIPTOR_HEADER)) {
1773
1775 accessAlignment->Version = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
1776 accessAlignment->Size = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
1778 goto Exit;
1779 }
1780
1782 goto Exit;
1783 }
1784
1785 // not support Cache Line,
1786 // 'BytesPerCacheLine' and 'BytesOffsetForCacheAlignment' fields are zero-ed.
1787
1788 //
1789 // note that 'Supported' case has been handled at the beginning of this function.
1790 //
1791 switch (fdoExtension->FunctionSupportInfo->LowerLayerSupport.AccessAlignmentProperty) {
1792 case SupportUnknown: {
1793 // send down request and wait for the request to complete.
1794 status = ClassForwardIrpSynchronous(commonExtension, Irp);
1795
1797 // case 1: the request is not supported by lower layer, sends down command
1798 // some port drivers (or filter drivers) return STATUS_INVALID_DEVICE_REQUEST if a request is not supported.
1799
1800 // ClassReadCapacity16() will either return status from cached data or send command to retrieve the information.
1801 if (ClasspIsObsoletePortDriver(fdoExtension) == FALSE) {
1802 status = ClassReadCapacity16(fdoExtension, Srb);
1803 } else {
1804 fdoExtension->FunctionSupportInfo->ReadCapacity16Data.CommandStatus = status;
1805 }
1806
1807 // data is ready in fdoExtension
1808 // set the support status after the SCSI command is executed to avoid racing condition between multiple same type of requests.
1809 fdoExtension->FunctionSupportInfo->LowerLayerSupport.AccessAlignmentProperty = NotSupported;
1810
1811 if (NT_SUCCESS(status)) {
1812 // fill output buffer
1813 RtlZeroMemory(accessAlignment, length);
1814 accessAlignment->Version = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
1815 accessAlignment->Size = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
1816 accessAlignment->BytesPerLogicalSector = fdoExtension->FunctionSupportInfo->ReadCapacity16Data.BytesPerLogicalSector;
1817 accessAlignment->BytesPerPhysicalSector = fdoExtension->FunctionSupportInfo->ReadCapacity16Data.BytesPerPhysicalSector;
1818 accessAlignment->BytesOffsetForSectorAlignment = fdoExtension->FunctionSupportInfo->ReadCapacity16Data.BytesOffsetForSectorAlignment;
1819
1820 // set returned data length
1822 } else {
1823 information = 0;
1824 }
1825
1826 } else {
1827 // case 2: the request is supported and it completes successfully
1828 // case 3: the request is supported by lower stack but other failure status is returned.
1829 // from now on, the same request will be send down to lower stack directly.
1830 fdoExtension->FunctionSupportInfo->LowerLayerSupport.AccessAlignmentProperty = Supported;
1831 information = (ULONG)Irp->IoStatus.Information;
1832
1833
1834 }
1835
1836
1837 goto Exit;
1838
1839 break;
1840 }
1841
1842 case NotSupported: {
1843
1844 // ClassReadCapacity16() will either return status from cached data or send command to retrieve the information.
1845 status = ClassReadCapacity16(fdoExtension, Srb);
1846
1847 if (NT_SUCCESS(status)) {
1848 RtlZeroMemory(accessAlignment, length);
1849 accessAlignment->Version = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
1850 accessAlignment->Size = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
1851 accessAlignment->BytesPerLogicalSector = fdoExtension->FunctionSupportInfo->ReadCapacity16Data.BytesPerLogicalSector;
1852 accessAlignment->BytesPerPhysicalSector = fdoExtension->FunctionSupportInfo->ReadCapacity16Data.BytesPerPhysicalSector;
1853 accessAlignment->BytesOffsetForSectorAlignment = fdoExtension->FunctionSupportInfo->ReadCapacity16Data.BytesOffsetForSectorAlignment;
1854
1856 } else {
1857 information = 0;
1858 }
1859 goto Exit;
1860
1861 break;
1862 }
1863
1864 case Supported: {
1865 NT_ASSERT(FALSE); // this case is handled at the beginning of the function.
1867 break;
1868 }
1869
1870 } // end of switch (fdoExtension->FunctionSupportInfo->LowerLayerSupport.AccessAlignmentProperty)
1871
1872Exit:
1873
1874 //
1875 // Set the size and status in IRP
1876 //
1877 Irp->IoStatus.Information = information;
1878 Irp->IoStatus.Status = status;
1879
1882
1883 return status;
1884}
#define TEST_FLAG(Flags, Bit)
Definition: cdrom.h:1495
FORCEINLINE BOOLEAN ClasspLowerLayerNotSupport(_In_ NTSTATUS Status)
Definition: classp.h:2638
FORCEINLINE BOOLEAN ClasspIsObsoletePortDriver(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: classp.h:1335
@ Supported
Definition: classpnp.h:733
@ SupportUnknown
Definition: classpnp.h:732
struct _COMMON_DEVICE_EXTENSION * PCOMMON_DEVICE_EXTENSION
NTSTATUS NTAPI ClassForwardIrpSynchronous(_In_ PCOMMON_DEVICE_EXTENSION CommonExtension, _In_ PIRP Irp)
Definition: class.c:11343
NTSTATUS ClassReadCapacity16(_Inout_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:1568
#define FILE_FLOPPY_DISKETTE
Definition: nt_native.h:809
STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR
Definition: ntddstor.h:609
* PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR
Definition: ntddstor.h:609
#define STATUS_INTERNAL_ERROR
Definition: ntstatus.h:465
#define FILE_DEVICE_DISK
Definition: winioctl.h:113
static void Exit(void)
Definition: sock.c:1330

Referenced by ClassDeviceControl().

◆ ClasspBinaryToAscii()

_IRQL_requires_same_ PUCHAR ClasspBinaryToAscii ( _In_reads_(Length) PUCHAR  HexBuffer,
_In_ ULONG  Length,
_Inout_ PULONG  UpdateLength 
)

Definition at line 7717 of file utils.c.

7744{
7745 static const UCHAR integerTable[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
7746 ULONG i;
7747 ULONG j;
7748 ULONG actualLength;
7749 PUCHAR buffer = NULL;
7750 UCHAR highWord;
7751 UCHAR lowWord;
7752
7753 TracePrint((TRACE_LEVEL_VERBOSE,
7754 TRACE_FLAG_IOCTL,
7755 "ClasspBinaryToAscii (HexBuff %p): Entering function.\n",
7756 HexBuffer));
7757
7758 if (!HexBuffer || Length == 0) {
7759 *UpdateLength = 0;
7760 goto __ClasspBinaryToAscii_Exit;
7761 }
7762
7763 //
7764 // Each byte converts into 2 chars:
7765 // e.g. 0x05 => '0' '5'
7766 // 0x0C => '0' 'C'
7767 // 0x12 => '1' '2'
7768 // And we need a terminating NULL for the string.
7769 //
7770 actualLength = (Length * 2) + 1;
7771
7772 //
7773 // Allocate the buffer.
7774 //
7775 buffer = ExAllocatePoolWithTag(NonPagedPoolNx, actualLength, CLASSPNP_POOL_TAG_TOKEN_OPERATION);
7776 if (!buffer) {
7777
7778 TracePrint((TRACE_LEVEL_ERROR,
7779 TRACE_FLAG_IOCTL,
7780 "ClasspBinaryToAscii (HexBuff %p): Failed to allocate buffer for ASCII equivalent.\n",
7781 HexBuffer));
7782
7783 *UpdateLength = 0;
7784 goto __ClasspBinaryToAscii_Exit;
7785 }
7786
7787 RtlZeroMemory(buffer, actualLength);
7788
7789 for (i = 0, j = 0; i < Length; i++) {
7790
7791 //
7792 // Split out each nibble from the binary byte.
7793 //
7794 highWord = HexBuffer[i] >> 4;
7795 lowWord = HexBuffer[i] & 0x0F;
7796
7797 //
7798 // Using the lookup table, convert and stuff into
7799 // the ascii buffer.
7800 //
7801 buffer[j++] = integerTable[highWord];
7802#ifdef _MSC_VER
7803#pragma warning(suppress: 6386) // PREFast bug means it doesn't see that Length < actualLength
7804#endif
7805 buffer[j++] = integerTable[lowWord];
7806 }
7807
7808 //
7809 // Update the caller's length field.
7810 //
7811 *UpdateLength = actualLength;
7812
7813__ClasspBinaryToAscii_Exit:
7814
7815 TracePrint((TRACE_LEVEL_VERBOSE,
7816 TRACE_FLAG_IOCTL,
7817 "ClasspBinaryToAscii (HexBuff %p): Exiting function with buffer %s.\n",
7818 HexBuffer,
7819 (buffer == NULL) ? "" : (const char*)buffer));
7820
7821 return buffer;
7822}
#define CLASSPNP_POOL_TAG_TOKEN_OPERATION
Definition: classp.h:193
GLuint buffer
Definition: glext.h:5915
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102

Referenced by ClasspContinueOffloadWrite(), and ClasspReceivePopulateTokenInformationTransferPacketDone().

◆ ClasspBuildDeviceMdl()

PMDL ClasspBuildDeviceMdl ( PVOID  Buffer,
ULONG  BufferLen,
BOOLEAN  WriteToDevice 
)

Definition at line 582 of file utils.c.

583{
584 PMDL mdl;
585
586 mdl = IoAllocateMdl(Buffer, BufferLen, FALSE, FALSE, NULL);
587 if (mdl){
588 _SEH2_TRY {
590#ifdef _MSC_VER
591 #pragma warning(suppress: 6320) // We want to handle any exception that MmProbeAndLockPages might throw
592#endif
595
596 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, "ClasspBuildDeviceMdl: MmProbeAndLockPages failed with %xh.", status));
597 IoFreeMdl(mdl);
598 mdl = NULL;
599 } _SEH2_END;
600 }
601 else {
602 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, "ClasspBuildDeviceMdl: IoAllocateMdl failed"));
603 }
604
605 return mdl;
606}
_In_ PSCSI_REQUEST_BLOCK _In_opt_ PVOID _In_ ULONG _In_ BOOLEAN WriteToDevice
Definition: cdrom.h:992
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
MDL * mdl
#define IoFreeMdl
Definition: fxmdl.h:89
#define IoAllocateMdl
Definition: fxmdl.h:88
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
VOID NTAPI MmProbeAndLockPages(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN LOCK_OPERATION Operation)
Definition: mdlsup.c:931
#define KernelMode
Definition: asm.h:34
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
@ IoReadAccess
Definition: ketypes.h:851
@ IoWriteAccess
Definition: ketypes.h:852

Referenced by BuildDeviceInputMdl().

◆ ClasspCalculateLogicalSectorSize()

ULONG ClasspCalculateLogicalSectorSize ( _In_ PDEVICE_OBJECT  Fdo,
_In_ ULONG  BytesPerBlockInBigEndian 
)

Definition at line 1483 of file utils.c.

1492{
1493 ULONG logicalSectorSize;
1494
1495 REVERSE_BYTES(&logicalSectorSize, &BytesPerBlockInBigEndian);
1496
1497 if (logicalSectorSize == 0) {
1498 logicalSectorSize = 512;
1499 } else {
1500 //
1501 // Clear all but the highest set bit.
1502 // That will give us a bytesPerSector value that is a power of 2.
1503 //
1504 if (logicalSectorSize & (logicalSectorSize-1)) {
1505 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "FDO %ph has non-standard sector size 0x%x.", Fdo, logicalSectorSize));
1506 do {
1507 logicalSectorSize &= logicalSectorSize-1;
1508 }
1509 while (logicalSectorSize & (logicalSectorSize-1));
1510 }
1511 }
1512
1513 return logicalSectorSize;
1514}

Referenced by InterpretCapacityData(), and InterpretReadCapacity16Data().

◆ ClasspConvertToScsiRequestBlock()

VOID ClasspConvertToScsiRequestBlock ( _Out_ PSCSI_REQUEST_BLOCK  Srb,
_In_ PSTORAGE_REQUEST_BLOCK  SrbEx 
)

Definition at line 6559 of file utils.c.

6563{
6564 PSTOR_ADDR_BTL8 storAddrBtl8;
6565 ULONG i;
6566 BOOLEAN foundEntry = FALSE;
6567 PSRBEX_DATA srbExData;
6568
6569 if ((Srb == NULL) || (SrbEx == NULL)) {
6570 return;
6571 }
6572
6574
6575 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
6576 Srb->Function = (UCHAR)SrbEx->SrbFunction;
6577 Srb->SrbStatus = SrbEx->SrbStatus;
6578 Srb->QueueTag = (UCHAR)SrbEx->RequestTag;
6579 Srb->QueueAction = (UCHAR)SrbEx->RequestAttribute;
6580 Srb->SrbFlags = SrbEx->SrbFlags;
6581 Srb->DataTransferLength = SrbEx->DataTransferLength;
6582 Srb->TimeOutValue = SrbEx->TimeOutValue;
6583 Srb->DataBuffer = SrbEx->DataBuffer;
6584 Srb->OriginalRequest = SrbEx->OriginalRequest;
6585 Srb->SrbExtension = SrbEx->MiniportContext;
6586 Srb->InternalStatus = SrbEx->SystemStatus;
6587
6588 //
6589 // Handle address fields
6590 //
6591 if (SrbEx->AddressOffset >= sizeof(STORAGE_REQUEST_BLOCK)) {
6592 storAddrBtl8 = (PSTOR_ADDR_BTL8)((PCHAR)SrbEx + SrbEx->AddressOffset);
6593
6594 if (storAddrBtl8->Type == STOR_ADDRESS_TYPE_BTL8) {
6595 Srb->PathId = storAddrBtl8->Path;
6596 Srb->TargetId = storAddrBtl8->Target;
6597 Srb->Lun = storAddrBtl8->Lun;
6598 } else {
6599 // Catch unsupported address types
6601 }
6602 }
6603
6604 //
6605 // Handle SRB function specific fields
6606 //
6607 if (SrbEx->NumSrbExData > 0) {
6608
6609 for (i = 0; i < SrbEx->NumSrbExData; i++) {
6610
6611 if ((SrbEx->SrbExDataOffset[i] == 0) ||
6612 (SrbEx->SrbExDataOffset[i] < sizeof(STORAGE_REQUEST_BLOCK))) {
6613 // Catch invalid offsets
6615 continue;
6616 }
6617
6618 srbExData = (PSRBEX_DATA)((PCHAR)SrbEx + SrbEx->SrbExDataOffset[i]);
6619
6620 switch (SrbEx->SrbFunction) {
6621
6623
6624 switch (srbExData->Type) {
6625
6627 Srb->ScsiStatus = ((PSRBEX_DATA_SCSI_CDB16)srbExData)->ScsiStatus;
6628 Srb->CdbLength = ((PSRBEX_DATA_SCSI_CDB16)srbExData)->CdbLength;
6629 Srb->SenseInfoBufferLength = ((PSRBEX_DATA_SCSI_CDB16)srbExData)->SenseInfoBufferLength;
6630 Srb->SenseInfoBuffer = ((PSRBEX_DATA_SCSI_CDB16)srbExData)->SenseInfoBuffer;
6631 RtlCopyMemory(Srb->Cdb, ((PSRBEX_DATA_SCSI_CDB16)srbExData)->Cdb, sizeof(Srb->Cdb));
6632 foundEntry = TRUE;
6633 break;
6634
6636 Srb->ScsiStatus = ((PSRBEX_DATA_SCSI_CDB32)srbExData)->ScsiStatus;
6637 Srb->CdbLength = ((PSRBEX_DATA_SCSI_CDB32)srbExData)->CdbLength;
6638 Srb->SenseInfoBufferLength = ((PSRBEX_DATA_SCSI_CDB32)srbExData)->SenseInfoBufferLength;
6639 Srb->SenseInfoBuffer = ((PSRBEX_DATA_SCSI_CDB32)srbExData)->SenseInfoBuffer;
6640
6641 // Copy only the first 16 bytes
6642 RtlCopyMemory(Srb->Cdb, ((PSRBEX_DATA_SCSI_CDB32)srbExData)->Cdb, sizeof(Srb->Cdb));
6643 foundEntry = TRUE;
6644 break;
6645
6647 Srb->ScsiStatus = ((PSRBEX_DATA_SCSI_CDB_VAR)srbExData)->ScsiStatus;
6648 Srb->CdbLength = (UCHAR)((PSRBEX_DATA_SCSI_CDB_VAR)srbExData)->CdbLength;
6649 Srb->SenseInfoBufferLength = ((PSRBEX_DATA_SCSI_CDB_VAR)srbExData)->SenseInfoBufferLength;
6650 Srb->SenseInfoBuffer = ((PSRBEX_DATA_SCSI_CDB_VAR)srbExData)->SenseInfoBuffer;
6651
6652 // Copy only the first 16 bytes
6653 RtlCopyMemory(Srb->Cdb, ((PSRBEX_DATA_SCSI_CDB_VAR)srbExData)->Cdb, sizeof(Srb->Cdb));
6654 foundEntry = TRUE;
6655 break;
6656
6657 default:
6658 break;
6659
6660 }
6661 break;
6662
6663 case SRB_FUNCTION_WMI:
6664
6665 if (srbExData->Type == SrbExDataTypeWmi) {
6666 ((PSCSI_WMI_REQUEST_BLOCK)Srb)->WMISubFunction = ((PSRBEX_DATA_WMI)srbExData)->WMISubFunction;
6667 ((PSCSI_WMI_REQUEST_BLOCK)Srb)->WMIFlags = ((PSRBEX_DATA_WMI)srbExData)->WMIFlags;
6668 ((PSCSI_WMI_REQUEST_BLOCK)Srb)->DataPath = ((PSRBEX_DATA_WMI)srbExData)->DataPath;
6669 foundEntry = TRUE;
6670 }
6671 break;
6672
6673 case SRB_FUNCTION_PNP:
6674
6675 if (srbExData->Type == SrbExDataTypePnP) {
6676 ((PSCSI_PNP_REQUEST_BLOCK)Srb)->PnPAction = ((PSRBEX_DATA_PNP)srbExData)->PnPAction;
6677 ((PSCSI_PNP_REQUEST_BLOCK)Srb)->PnPSubFunction = ((PSRBEX_DATA_PNP)srbExData)->PnPSubFunction;
6678 ((PSCSI_PNP_REQUEST_BLOCK)Srb)->SrbPnPFlags = ((PSRBEX_DATA_PNP)srbExData)->SrbPnPFlags;
6679 foundEntry = TRUE;
6680 }
6681 break;
6682
6683 case SRB_FUNCTION_POWER:
6684
6685 if (srbExData->Type == SrbExDataTypePower) {
6686 ((PSCSI_POWER_REQUEST_BLOCK)Srb)->DevicePowerState = ((PSRBEX_DATA_POWER)srbExData)->DevicePowerState;
6687 ((PSCSI_POWER_REQUEST_BLOCK)Srb)->PowerAction = ((PSRBEX_DATA_POWER)srbExData)->PowerAction;
6688 ((PSCSI_POWER_REQUEST_BLOCK)Srb)->SrbPowerFlags = ((PSRBEX_DATA_POWER)srbExData)->SrbPowerFlags;
6689 foundEntry = TRUE;
6690 }
6691 break;
6692
6693 default:
6694 break;
6695
6696 }
6697
6698 //
6699 // Quit on first match
6700 //
6701 if (foundEntry) {
6702 break;
6703 }
6704 }
6705 }
6706
6707 return;
6708}
#define SRB_FUNCTION_WMI
Definition: srb.h:331
struct _SCSI_WMI_REQUEST_BLOCK * PSCSI_WMI_REQUEST_BLOCK
struct STOR_ADDRESS_ALIGN _STOR_ADDR_BTL8 * PSTOR_ADDR_BTL8
#define STOR_ADDRESS_TYPE_BTL8
Definition: scsi.h:3525
struct _SCSI_PNP_REQUEST_BLOCK * PSCSI_PNP_REQUEST_BLOCK
struct SRB_ALIGN _SRBEX_DATA_SCSI_CDB_VAR * PSRBEX_DATA_SCSI_CDB_VAR
#define SRB_FUNCTION_POWER
Definition: srb.h:95
struct _SCSI_POWER_REQUEST_BLOCK * PSCSI_POWER_REQUEST_BLOCK
#define SRB_FUNCTION_PNP
Definition: srb.h:96
struct SRB_ALIGN _SRBEX_DATA * PSRBEX_DATA
@ SrbExDataTypeWmi
Definition: srb.h:453
@ SrbExDataTypeScsiCdb32
Definition: srb.h:451
@ SrbExDataTypePower
Definition: srb.h:454
@ SrbExDataTypeScsiCdbVar
Definition: srb.h:452
@ SrbExDataTypePnP
Definition: srb.h:455
struct SRB_ALIGN _SRBEX_DATA_SCSI_CDB16 * PSRBEX_DATA_SCSI_CDB16
struct SRB_ALIGN _SRBEX_DATA_SCSI_CDB32 * PSRBEX_DATA_SCSI_CDB32
STORAGE_REQUEST_BLOCK
Definition: srb.h:652
struct SRB_ALIGN _SRBEX_DATA_POWER * PSRBEX_DATA_POWER
struct SRB_ALIGN _SRBEX_DATA_WMI * PSRBEX_DATA_WMI
struct SRB_ALIGN _SRBEX_DATA_PNP * PSRBEX_DATA_PNP
UCHAR QueueTag
Definition: srb.h:256
ULONG TimeOutValue
Definition: srb.h:262
UCHAR TargetId
Definition: srb.h:254
PVOID OriginalRequest
Definition: srb.h:266
UCHAR SenseInfoBufferLength
Definition: srb.h:259
PVOID DataBuffer
Definition: srb.h:263
UCHAR PathId
Definition: srb.h:253
UCHAR QueueAction
Definition: srb.h:257
UCHAR CdbLength
Definition: srb.h:258
UCHAR Cdb[16]
Definition: srb.h:279
PVOID SenseInfoBuffer
Definition: srb.h:264
UCHAR ScsiStatus
Definition: srb.h:252
ULONG DataTransferLength
Definition: srb.h:261
PVOID SrbExtension
Definition: srb.h:267
ULONG InternalStatus
Definition: srb.h:269
ULONG SrbFlags
Definition: srb.h:260
UCHAR SrbStatus
Definition: srb.h:251
char * PCHAR
Definition: typedefs.h:51

Referenced by ClassInterpretSenseInfo(), InterpretSenseInfoWithoutHistory(), and InterpretTransferPacketError().

◆ ClasspDeviceGetBlockDeviceCharacteristicsVPDPage()

NTSTATUS ClasspDeviceGetBlockDeviceCharacteristicsVPDPage ( _In_ PFUNCTIONAL_DEVICE_EXTENSION  fdoExtension,
_In_ PSCSI_REQUEST_BLOCK  Srb 
)

Definition at line 2072 of file utils.c.

2095{
2097 PCDB cdb;
2098 UCHAR bufferLength = sizeof(VPD_BLOCK_DEVICE_CHARACTERISTICS_PAGE); // data is 64 bytes
2099 ULONG allocationBufferLength = bufferLength;
2101
2102
2103#if defined(_ARM_) || defined(_ARM64_)
2104 //
2105 // ARM has specific alignment requirements, although this will not have a functional impact on x86 or amd64
2106 // based platforms. We are taking the conservative approach here.
2107 //
2108 allocationBufferLength = ALIGN_UP_BY(allocationBufferLength,KeGetRecommendedSharedDataAlignment());
2110 allocationBufferLength,
2111 '5CcS'
2112 );
2113#else
2114
2117 '5CcS'
2118 );
2119#endif
2120 if (dataBuffer == NULL) {
2122 goto Exit;
2123 }
2124
2125 RtlZeroMemory(dataBuffer, allocationBufferLength);
2126
2127 // prepare the Srb
2128 SrbSetTimeOutValue(Srb, fdoExtension->TimeOutValue);
2131 SrbAssignSrbFlags(Srb, fdoExtension->SrbFlags);
2132
2133 SrbSetCdbLength(Srb, 6);
2134
2135 cdb = SrbGetCdb(Srb);
2136 cdb->CDB6INQUIRY3.OperationCode = SCSIOP_INQUIRY;
2137 cdb->CDB6INQUIRY3.EnableVitalProductData = 1; //EVPD bit
2139 cdb->CDB6INQUIRY3.AllocationLength = bufferLength; //AllocationLength field in CDB6INQUIRY3 is only one byte.
2140
2141 status = ClassSendSrbSynchronous(fdoExtension->CommonExtension.DeviceObject,
2142 Srb,
2143 dataBuffer,
2144 allocationBufferLength,
2145 FALSE);
2146 if (NT_SUCCESS(status)) {
2147 if (SrbGetDataTransferLength(Srb) < 0x8) {
2148 // the device should return at least 8 bytes of data for use.
2150 } else if ( (dataBuffer->PageLength != 0x3C) || (dataBuffer->PageCode != VPD_BLOCK_DEVICE_CHARACTERISTICS) ) {
2151 // 'PageLength' shall be 0x3C; and 'PageCode' shall match.
2153 } else {
2154 // cache data into fdoExtension
2155 fdoExtension->FunctionSupportInfo->DeviceCharacteristicsData.MediumRotationRate = (dataBuffer->MediumRotationRateMsb << 8) |
2156 dataBuffer->MediumRotationRateLsb;
2157 fdoExtension->FunctionSupportInfo->DeviceCharacteristicsData.MediumProductType = dataBuffer->MediumProductType;
2158 fdoExtension->FunctionSupportInfo->DeviceCharacteristicsData.NominalFormFactor = dataBuffer->NominalFormFactor;
2159 }
2160 } else {
2161 // the command failed, surface up the command error from 'status' variable. Nothing to do here.
2162 }
2163
2164Exit:
2165 if (dataBuffer != NULL) {
2167 }
2168
2169 return status;
2170}
#define SCSIOP_INQUIRY
Definition: cdrw_hw.h:888
PVOID dataBuffer
#define VPD_BLOCK_DEVICE_CHARACTERISTICS
Definition: scsi.h:2417
struct _VPD_BLOCK_DEVICE_CHARACTERISTICS_PAGE VPD_BLOCK_DEVICE_CHARACTERISTICS_PAGE
struct _VPD_BLOCK_DEVICE_CHARACTERISTICS_PAGE * PVPD_BLOCK_DEVICE_CHARACTERISTICS_PAGE
struct _CDB::_CDB6INQUIRY3 CDB6INQUIRY3
_In_opt_ PVOID _In_ ULONG bufferLength
Definition: wdfdriver.h:109

Referenced by ClasspDeviceMediaTypeProperty(), and ClasspDeviceSeekPenaltyProperty().

◆ ClasspDeviceGetBlockLimitsVPDPage()

NTSTATUS ClasspDeviceGetBlockLimitsVPDPage ( _In_ PFUNCTIONAL_DEVICE_EXTENSION  FdoExtension,
_Inout_bytecount_(SrbSize) PSCSI_REQUEST_BLOCK  Srb,
_In_ ULONG  SrbSize,
_Out_ PCLASS_VPD_B0_DATA  BlockLimitsData 
)

Definition at line 2521 of file utils.c.

2527{
2530 UCHAR bufferLength = VPD_MAX_BUFFER_SIZE; // use biggest buffer possible
2531 ULONG allocationBufferLength = bufferLength;
2532 PCDB cdb;
2533 PVPD_BLOCK_LIMITS_PAGE blockLimits = NULL;
2534 ULONG dataTransferLength = 0;
2535
2536 //
2537 // Set default values for UNMAP parameters based upon UNMAP support or lack
2538 // thereof.
2539 //
2540 if (FdoExtension->FunctionSupportInfo->LBProvisioningData.LBPU) {
2541 //
2542 // If UNMAP is supported, we default to the maximum LBA count and
2543 // block descriptor count. We also default the UNMAP granularity to
2544 // a single block and specify no granularity alignment.
2545 //
2546 BlockLimitsData->MaxUnmapLbaCount = (ULONG)-1;
2547 BlockLimitsData->MaxUnmapBlockDescrCount = (ULONG)-1;
2548 BlockLimitsData->OptimalUnmapGranularity = 1;
2549 BlockLimitsData->UnmapGranularityAlignment = 0;
2550 BlockLimitsData->UGAVALID = FALSE;
2551 } else {
2552 BlockLimitsData->MaxUnmapLbaCount = 0;
2553 BlockLimitsData->MaxUnmapBlockDescrCount = 0;
2554 BlockLimitsData->OptimalUnmapGranularity = 0;
2555 BlockLimitsData->UnmapGranularityAlignment = 0;
2556 BlockLimitsData->UGAVALID = FALSE;
2557 }
2558
2559 //
2560 // Try to get the Block Limits VPD page (0xB0), if it is supported.
2561 //
2562 if (FdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockLimits == TRUE)
2563 {
2564#if defined(_ARM_) || defined(_ARM64_)
2565 //
2566 // ARM has specific alignment requirements, although this will not have a functional impact on x86 or amd64
2567 // based platforms. We are taking the conservative approach here.
2568 //
2569 allocationBufferLength = ALIGN_UP_BY(allocationBufferLength, KeGetRecommendedSharedDataAlignment());
2570 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, allocationBufferLength, '0CcS');
2571#else
2572 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, bufferLength, '0CcS');
2573#endif
2574 if (dataBuffer == NULL)
2575 {
2576 // return without updating FdoExtension->FunctionSupportInfo->BlockLimitsData.CommandStatus
2577 // the field will remain value as "-1", so that the command will be attempted next time this function is called.
2579 goto Exit;
2580 }
2581
2582 blockLimits = (PVPD_BLOCK_LIMITS_PAGE)dataBuffer;
2583
2584 RtlZeroMemory(dataBuffer, allocationBufferLength);
2585
2586 if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2587
2588#ifdef _MSC_VER
2589 #pragma prefast(suppress:26015, "InitializeStorageRequestBlock ensures buffer access is bounded")
2590#endif
2593 SrbSize,
2594 1,
2596
2597 if (NT_SUCCESS(status)) {
2599 } else {
2600 //
2601 // Should not occur.
2602 //
2604 }
2605 } else {
2607 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
2610 }
2611
2612 if (NT_SUCCESS(status)) {
2613 // prepare the Srb
2614 SrbSetTimeOutValue(Srb, FdoExtension->TimeOutValue);
2618
2619 SrbSetCdbLength(Srb, 6);
2620
2621 cdb = SrbGetCdb(Srb);
2622 cdb->CDB6INQUIRY3.OperationCode = SCSIOP_INQUIRY;
2623 cdb->CDB6INQUIRY3.EnableVitalProductData = 1; //EVPD bit
2624 cdb->CDB6INQUIRY3.PageCode = VPD_BLOCK_LIMITS;
2625 cdb->CDB6INQUIRY3.AllocationLength = bufferLength; //AllocationLength field in CDB6INQUIRY3 is only one byte.
2626
2628 Srb,
2629 dataBuffer,
2630 allocationBufferLength,
2631 FALSE);
2632 dataTransferLength = SrbGetDataTransferLength(Srb);
2633 }
2634
2635 //
2636 // Handle the case where we get back STATUS_DATA_OVERRUN b/c the input
2637 // buffer was larger than necessary.
2638 //
2639
2640 if (status == STATUS_DATA_OVERRUN && dataTransferLength < bufferLength)
2641 {
2643 }
2644
2645 if (NT_SUCCESS(status))
2646 {
2647 USHORT pageLength;
2648 REVERSE_BYTES_SHORT(&pageLength, &(blockLimits->PageLength));
2649
2650 //
2651 // Regardless of the device's support for unmap, cache away at least the basic block limits information
2652 //
2653 if (dataTransferLength >= 0x10 && blockLimits->PageCode == VPD_BLOCK_LIMITS) {
2654
2655 // (6:7) OPTIMAL TRANSFER LENGTH GRANULARITY
2656 REVERSE_BYTES_SHORT(&BlockLimitsData->OptimalTransferLengthGranularity, &blockLimits->OptimalTransferLengthGranularity);
2657 // (8:11) MAXIMUM TRANSFER LENGTH
2658 REVERSE_BYTES(&BlockLimitsData->MaximumTransferLength, &blockLimits->MaximumTransferLength);
2659 // (12:15) OPTIMAL TRANSFER LENGTH
2660 REVERSE_BYTES(&BlockLimitsData->OptimalTransferLength, &blockLimits->OptimalTransferLength);
2661 }
2662
2663 if ((dataTransferLength < 0x24) ||
2665 (blockLimits->PageCode != VPD_BLOCK_LIMITS))
2666 {
2667 // the device should return at least 36 bytes of data for use.
2668 // 'PageCode' shall match and we need all the relevant data after the header.
2670 }
2671 }
2672
2673 if (NT_SUCCESS(status))
2674 {
2675 // cache data into FdoExtension
2676 // (20:23) MAXIMUM UNMAP LBA COUNT
2677 REVERSE_BYTES(&BlockLimitsData->MaxUnmapLbaCount, &blockLimits->MaximumUnmapLBACount);
2678 // (24:27) MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT
2679 REVERSE_BYTES(&BlockLimitsData->MaxUnmapBlockDescrCount, &blockLimits->MaximumUnmapBlockDescriptorCount);
2680 // (28:31) OPTIMAL UNMAP GRANULARITY
2681 REVERSE_BYTES(&BlockLimitsData->OptimalUnmapGranularity, &blockLimits->OptimalUnmapGranularity);
2682
2683 // (32:35) UNMAP GRANULARITY ALIGNMENT; (32) bit7: UGAVALID
2684 BlockLimitsData->UGAVALID = blockLimits->UGAValid;
2685 if (BlockLimitsData->UGAVALID == TRUE) {
2686 REVERSE_BYTES(&BlockLimitsData->UnmapGranularityAlignment, &blockLimits->UnmapGranularityAlignment);
2687 BlockLimitsData->UnmapGranularityAlignment &= 0x7FFFFFFF; // remove value of UGAVALID bit.
2688 } else {
2689 BlockLimitsData->UnmapGranularityAlignment = 0;
2690 }
2691
2692 TracePrint((TRACE_LEVEL_INFORMATION,
2693 TRACE_FLAG_PNP,
2694 "ClasspDeviceGetBlockLimitsVPDPage (%p): %s %s (rev %s) reported following parameters: \
2695 \n\t\t\tOptimalTransferLengthGranularity: %u \
2696 \n\t\t\tMaximumTransferLength: %u \
2697 \n\t\t\tOptimalTransferLength: %u \
2698 \n\t\t\tMaximumUnmapLBACount: %u \
2699 \n\t\t\tMaximumUnmapBlockDescriptorCount: %u \
2700 \n\t\t\tOptimalUnmapGranularity: %u \
2701 \n\t\t\tUGAValid: %u \
2702 \n\t\t\tUnmapGranularityAlignment: %u\n",
2703 FdoExtension->DeviceObject,
2704 (PCSZ)(((PUCHAR)FdoExtension->DeviceDescriptor) + FdoExtension->DeviceDescriptor->VendorIdOffset),
2705 (PCSZ)(((PUCHAR)FdoExtension->DeviceDescriptor) + FdoExtension->DeviceDescriptor->ProductIdOffset),
2706 (PCSZ)(((PUCHAR)FdoExtension->DeviceDescriptor) + FdoExtension->DeviceDescriptor->ProductRevisionOffset),
2707 BlockLimitsData->OptimalTransferLengthGranularity,
2708 BlockLimitsData->MaximumTransferLength,
2709 BlockLimitsData->OptimalTransferLength,
2710 BlockLimitsData->MaxUnmapLbaCount,
2711 BlockLimitsData->MaxUnmapBlockDescrCount,
2712 BlockLimitsData->OptimalUnmapGranularity,
2713 BlockLimitsData->UGAVALID,
2714 BlockLimitsData->UnmapGranularityAlignment));
2715
2716 }
2717 } else {
2719 }
2720
2721 BlockLimitsData->CommandStatus = status;
2722
2723Exit:
2725
2726 return status;
2727}
@ Reserved1
Definition: bcd.h:201
#define VPD_MAX_BUFFER_SIZE
Definition: scsi.h:2402
struct _VPD_BLOCK_LIMITS_PAGE * PVPD_BLOCK_LIMITS_PAGE
#define VPD_BLOCK_LIMITS
Definition: scsi.h:2416
UCHAR MaximumTransferLength[4]
Definition: scsi.h:2537
UCHAR OptimalUnmapGranularity[4]
Definition: scsi.h:2542
UCHAR OptimalTransferLengthGranularity[2]
Definition: scsi.h:2536
UCHAR MaximumUnmapLBACount[4]
Definition: scsi.h:2540
UCHAR OptimalTransferLength[4]
Definition: scsi.h:2538
UCHAR MaximumUnmapBlockDescriptorCount[4]
Definition: scsi.h:2541
UCHAR PageLength[2]
Definition: scsi.h:2531
UCHAR UnmapGranularityAlignment[4]
Definition: scsi.h:2551
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
CONST char * PCSZ
Definition: umtypes.h:125

Referenced by ClasspGetLBProvisioningInfo(), and ClasspRefreshFunctionSupportInfo().

◆ ClasspDeviceGetLBAStatus()

NTSTATUS ClasspDeviceGetLBAStatus ( _In_ PDEVICE_OBJECT  DeviceObject,
_Inout_ PIRP  Irp,
_Inout_ PSCSI_REQUEST_BLOCK  Srb 
)

Definition at line 3861 of file utils.c.

3911{
3914 PDEVICE_MANAGE_DATA_SET_ATTRIBUTES dsmAttributes = (PDEVICE_MANAGE_DATA_SET_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer;
3915 PDEVICE_DATA_SET_RANGE dataSetRanges = NULL;
3917 ULONG dsmOutputLength;
3918 NTSTATUS finalStatus;
3919 NTSTATUS getLBAWorkerStatus;
3920 ULONG retryCount;
3921 ULONG retryCountMax;
3922 CLASS_VPD_B0_DATA blockLimitsData;
3923 ULONG generationCount1;
3924 ULONG generationCount2;
3925 BOOLEAN blockLimitsDataMayHaveChanged;
3927 LONGLONG startingOffset;
3928 ULONGLONG lengthInBytes;
3929 BOOLEAN consolidateableBlocksOnly = FALSE;
3930 ULONG outputVersion;
3931
3932 //
3933 // Basic parameter validation.
3934 // Note that InputBufferLength and IsFdo have been validated beforing entering this routine.
3935 //
3936 if (dsmOutput == NULL ||
3937 dsmAttributes == NULL)
3938 {
3939 finalStatus = STATUS_INVALID_PARAMETER;
3940 goto Exit;
3941 }
3942
3944 //
3945 // The caller wants the mapping status of the entire disk.
3946 //
3947 ULONG unmapGranularityAlignment = 0;
3948 if (fdoExtension->FunctionSupportInfo->BlockLimitsData.UGAVALID) {
3949 unmapGranularityAlignment = fdoExtension->FunctionSupportInfo->BlockLimitsData.UnmapGranularityAlignment;
3950 }
3951 startingOffset = unmapGranularityAlignment;
3952 lengthInBytes = (ULONGLONG)fdoExtension->CommonExtension.PartitionLength.QuadPart - (ULONGLONG)startingOffset;
3953 } else {
3954 if (dsmAttributes->DataSetRangesOffset == 0 ||
3955 dsmAttributes->DataSetRangesLength == 0) {
3956 finalStatus = STATUS_INVALID_PARAMETER;
3957 goto Exit;
3958 }
3959
3960 //
3961 // We only service the first dataset range specified.
3962 //
3963 dataSetRanges = (PDEVICE_DATA_SET_RANGE)((PUCHAR)dsmAttributes + dsmAttributes->DataSetRangesOffset);
3964 startingOffset = dataSetRanges[0].StartingOffset;
3965 lengthInBytes = dataSetRanges[0].LengthInBytes;
3966 }
3967
3968
3969 //
3970 // See if the sender is requesting a specific version of the output data
3971 // structure. Othwerwise, default to V1.
3972 //
3974#if (NTDDI_VERSION >= NTDDI_WINBLUE)
3975 if ((dsmAttributes->ParameterBlockOffset >= sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES)) &&
3976 (dsmAttributes->ParameterBlockLength >= sizeof(DEVICE_DATA_SET_LBP_STATE_PARAMETERS))) {
3977 PDEVICE_DATA_SET_LBP_STATE_PARAMETERS parameters = Add2Ptr(dsmAttributes, dsmAttributes->ParameterBlockOffset);
3978 if ((parameters->Version == DEVICE_DATA_SET_LBP_STATE_PARAMETERS_VERSION_V1) &&
3979 (parameters->Size >= sizeof(DEVICE_DATA_SET_LBP_STATE_PARAMETERS))) {
3980
3981 outputVersion = parameters->OutputVersion;
3982
3983 if ((outputVersion != DEVICE_DATA_SET_LB_PROVISIONING_STATE_VERSION_V1) &&
3985 finalStatus = STATUS_INVALID_PARAMETER;
3986 goto Exit;
3987 }
3988 }
3989 }
3990#endif
3991
3992 //
3993 // Take a snapshot of the block limits data for the worker function to use.
3994 // We need to fail the request if we fail to get updated block limits data
3995 // since we need an accurate Optimal Unmap Granularity value to properly
3996 // convert the returned mapping descriptors into a bitmap.
3997 //
3998 finalStatus = ClasspBlockLimitsDataSnapshot(fdoExtension,
3999 TRUE,
4000 &blockLimitsData,
4001 &generationCount1);
4002
4003 if (!NT_SUCCESS(finalStatus)) {
4004 information = 0;
4005 goto Exit;
4006 }
4007
4009 consolidateableBlocksOnly = TRUE;
4010 }
4011
4012 //
4013 // The retry logic is to handle the case when block limits data changes during rare occasions
4014 // (e.g. diff-VHD fork or merge).
4015 //
4016 retryCountMax = GET_LBA_STATUS_RETRY_COUNT_MAX;
4017 for (retryCount = 0; retryCount < retryCountMax; retryCount++) {
4018
4019 dsmOutputLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
4020 getLBAWorkerStatus = ClasspDeviceGetLBAStatusWorker(DeviceObject,
4021 &blockLimitsData,
4022 startingOffset,
4023 lengthInBytes,
4024 dsmOutput,
4025 &dsmOutputLength,
4026 Srb,
4027 consolidateableBlocksOnly,
4028 outputVersion,
4029 &blockLimitsDataMayHaveChanged);
4030
4031 if (!NT_SUCCESS(getLBAWorkerStatus) && !blockLimitsDataMayHaveChanged) {
4032 information = 0;
4033 finalStatus = getLBAWorkerStatus;
4034 break;
4035 }
4036
4037 //
4038 // Again, we need to fail the request if we fail to get updated block
4039 // limits data since we need an accurate Optimal Unmap Granularity value.
4040 //
4041 finalStatus = ClasspBlockLimitsDataSnapshot(fdoExtension,
4042 TRUE,
4043 &blockLimitsData,
4044 &generationCount2);
4045 if (!NT_SUCCESS(finalStatus)) {
4046 information = 0;
4047 goto Exit;
4048 }
4049
4050 if (generationCount1 == generationCount2) {
4051 //
4052 // Block limits data stays the same during the call to ClasspDeviceGetLBAStatusWorker()
4053 // The result from ClasspDeviceGetLBAStatusWorker() is valid.
4054 //
4055 finalStatus = getLBAWorkerStatus;
4056 if (NT_SUCCESS(finalStatus)) {
4057 information = dsmOutputLength;
4058 }
4059 break;
4060 }
4061
4062 //
4063 // Try again with the latest block limits data
4064 //
4065 generationCount1 = generationCount2;
4066 information = 0;
4067 finalStatus = STATUS_DEVICE_DATA_ERROR;
4068 }
4069
4070Exit:
4071 Irp->IoStatus.Information = information;
4072 Irp->IoStatus.Status = finalStatus;
4075 return finalStatus;
4076}
#define GET_LBA_STATUS_RETRY_COUNT_MAX
Definition: classp.h:229
NTSTATUS ClasspBlockLimitsDataSnapshot(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _In_ BOOLEAN ForceQuery, _Out_ PCLASS_VPD_B0_DATA BlockLimitsData, _Out_ PULONG GenerationCount)
Definition: class.c:16504
NTSTATUS ClasspDeviceGetLBAStatusWorker(_In_ PDEVICE_OBJECT DeviceObject, _In_ PCLASS_VPD_B0_DATA BlockLimitsData, _In_ ULONGLONG StartingOffset, _In_ ULONGLONG LengthInBytes, _Out_ PDEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT DsmOutput, _Inout_ PULONG DsmOutputLength, _Inout_ PSCSI_REQUEST_BLOCK Srb, _In_ BOOLEAN ConsolidateableBlocksOnly, _In_ ULONG OutputVersion, _Out_ PBOOLEAN BlockLimitsDataMayHaveChanged)
Definition: utils.c:4079
#define Add2Ptr(PTR, INC)
#define DEVICE_DATA_SET_LB_PROVISIONING_STATE_VERSION_V1
Definition: ntddstor.h:939
#define DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE
Definition: ntddstor.h:306
struct _DEVICE_DATA_SET_RANGE * PDEVICE_DATA_SET_RANGE
#define DEVICE_DSM_FLAG_ALLOCATION_CONSOLIDATEABLE_ONLY
Definition: ntddstor.h:963
struct _DEVICE_MANAGE_DATA_SET_ATTRIBUTES * PDEVICE_MANAGE_DATA_SET_ATTRIBUTES
#define DEVICE_DATA_SET_LB_PROVISIONING_STATE_VERSION_V2
Definition: ntddstor.h:953
LARGE_INTEGER PartitionLength
Definition: classpnp.h:618
COMMON_DEVICE_EXTENSION CommonExtension
Definition: classpnp.h:873
int64_t LONGLONG
Definition: typedefs.h:68
#define STATUS_DEVICE_DATA_ERROR
Definition: udferr_usr.h:159
LONGLONG QuadPart
Definition: typedefs.h:114

Referenced by ClassDeviceControl().

◆ ClasspDeviceGetLBAStatusWorker()

NTSTATUS ClasspDeviceGetLBAStatusWorker ( _In_ PDEVICE_OBJECT  DeviceObject,
_In_ PCLASS_VPD_B0_DATA  BlockLimitsData,
_In_ ULONGLONG  StartingOffset,
_In_ ULONGLONG  LengthInBytes,
_Out_ PDEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT  DsmOutput,
_Inout_ PULONG  DsmOutputLength,
_Inout_ PSCSI_REQUEST_BLOCK  Srb,
_In_ BOOLEAN  ConsolidateableBlocksOnly,
_In_ ULONG  OutputVersion,
_Out_ PBOOLEAN  BlockLimitsDataMayHaveChanged 
)

Definition at line 4079 of file utils.c.

4147{
4149
4151
4153 ULONG bitMapGranularityInBits = FIELD_SIZE(DEVICE_DATA_SET_LB_PROVISIONING_STATE,SlabAllocationBitMap[0]) * 8;
4154 ULONG requiredOutputLength;
4155 ULONG outputLength = *DsmOutputLength;
4156
4157 ULONG blocksPerSlab;
4158 ULONGLONG bytesPerSlab;
4159 ULONGLONG alignmentInBytes = 0;
4160 ULONG alignmentInBlocks = 0;
4161 ULONG maxBufferSize;
4162 ULONG maxSlabs;
4163 ULONGLONG requestedSlabs; // Total number of slabs requested by the caller.
4164 ULONGLONG startingLBA;
4165 ULONGLONG startingOffsetDelta;
4166 ULONG totalProcessedSlabs = 0; // Total number of slabs we processed.
4167 ULONGLONG slabsPerCommand; // Number of slabs we can ask for in one Get LBA Status command.
4168 BOOLEAN doneProcessing = FALSE; // Indicates we should break out of the Get LBA Status loop.
4169
4170 ULONG lbaStatusSize;
4171 PLBA_STATUS_LIST_HEADER lbaStatusListHeader = NULL;
4172
4173 //
4174 // This function can fail if the block limits data on the device changes.
4175 // This flag tells the caller if it should retry with a newer block limits data
4176 //
4177 *BlockLimitsDataMayHaveChanged = FALSE;
4178
4179 //
4180 // Make sure we're running at PASSIVE_LEVEL
4181 //
4183 {
4186 goto Exit;
4187 }
4188
4189 //
4190 // Don't send down a Get LBA Status command if UNMAP isn't supported.
4191 //
4192 if (!fdoExtension->FunctionSupportInfo->LBProvisioningData.LBPU)
4193 {
4194 return STATUS_NOT_SUPPORTED;
4195 goto Exit;
4196 }
4197
4198 //
4199 // Make sure we have a non-zero value for the number of bytes per block.
4200 // Otherwise we will end up dividing by zero later on.
4201 //
4202 if (fdoExtension->DiskGeometry.BytesPerSector == 0)
4203 {
4205 if(!NT_SUCCESS(status) || fdoExtension->DiskGeometry.BytesPerSector == 0)
4206 {
4208 goto Exit;
4209 }
4210 }
4211
4212 //
4213 // We only service the first dataset range specified.
4214 //
4215 if (BlockLimitsData->UGAVALID == TRUE) {
4216 alignmentInBlocks = BlockLimitsData->UnmapGranularityAlignment;
4217 alignmentInBytes = (ULONGLONG)alignmentInBlocks * (ULONGLONG)fdoExtension->DiskGeometry.BytesPerSector;
4218 }
4219
4220 //
4221 // Make sure the specified range is valid. The Unmap Granularity Alignment
4222 // defines a region at the beginning of the disk that cannot be
4223 // mapped/unmapped so the specified range should not include any part of that
4224 // region.
4225 //
4226 if (LengthInBytes == 0 ||
4227 StartingOffset < alignmentInBytes ||
4228 StartingOffset + LengthInBytes > (ULONGLONG)fdoExtension->CommonExtension.PartitionLength.QuadPart)
4229 {
4230 TracePrint((TRACE_LEVEL_ERROR,
4231 TRACE_FLAG_IOCTL,
4232 "ClasspDeviceGetLBAStatusWorker (%p): Invalid range, length is %I64u bytes, starting offset is %I64u bytes, Unmap alignment is %I64u bytes, and disk size is %I64u bytes\n",
4234 LengthInBytes,
4236 alignmentInBytes,
4238
4240 goto Exit;
4241 }
4242
4243 //
4244 // Calculate the number of bytes per slab so that we can convert (and
4245 // possibly align) the given offset (given in bytes) to slabs.
4246 //
4247 blocksPerSlab = BlockLimitsData->OptimalUnmapGranularity;
4248 bytesPerSlab = (ULONGLONG)blocksPerSlab * (ULONGLONG)fdoExtension->DiskGeometry.BytesPerSector;
4249
4250 //
4251 // If the starting offset is not slab-aligned, we need to adjust it to
4252 // be aligned with the next highest slab. We also need to save the delta
4253 // to return to the user later.
4254 //
4255 if (((StartingOffset - alignmentInBytes) % bytesPerSlab) != 0)
4256 {
4257 startingLBA = (((StartingOffset - alignmentInBytes) / bytesPerSlab) + 1) * (ULONGLONG)blocksPerSlab + alignmentInBlocks;
4258 startingOffsetDelta = (startingLBA * fdoExtension->DiskGeometry.BytesPerSector) - StartingOffset;
4259 }
4260 else
4261 {
4262 startingLBA = ((StartingOffset - alignmentInBytes) / bytesPerSlab) * (ULONGLONG)blocksPerSlab + alignmentInBlocks;
4263 startingOffsetDelta = 0;
4264 }
4265
4266 //
4267 // Caclulate the number of slabs the caller requested.
4268 //
4269 if ((LengthInBytes % bytesPerSlab) == 0) {
4270 requestedSlabs = (LengthInBytes / bytesPerSlab);
4271 } else {
4272 //
4273 // Round up the number of requested slabs if the length indicates a
4274 // partial slab. This should cover the case where the user specifies
4275 // a dataset range for the whole disk, but the size of the disk is not
4276 // a slab-multiple. Rounding up allows us to return the status of the
4277 // partial slab
4278 //
4279 requestedSlabs = (LengthInBytes / bytesPerSlab) + 1;
4280 }
4281
4282 //
4283 // If the caller asked for no slabs then return STATUS_INVALID_PARAMETER.
4284 //
4285 if (requestedSlabs == 0)
4286 {
4287 TracePrint((TRACE_LEVEL_ERROR,
4288 TRACE_FLAG_IOCTL,
4289 "ClasspDeviceGetLBAStatusWorker (%p): Invalid number (%I64u) of slabs requested\n",
4291 requestedSlabs));
4292
4294 goto Exit;
4295 }
4296
4297 //
4298 // Cap requested slabs at MAXULONG since SlabAllocationBitMapBitCount
4299 // is a 4-byte field. We may return less data than requested, but the
4300 // caller can simply re-query for the omitted portion(s).
4301 //
4302 requestedSlabs = min(requestedSlabs, MAXULONG);
4303
4304 //
4305 // Calculate the required size of the output buffer based upon the desired
4306 // version of the output structure.
4307 // In the worst case, Get LBA Status returns a descriptor for each slab
4308 // requested, thus the required output buffer length is equal to:
4309 // 1. The size of DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT; plus
4310 // 2. The size of DEVICE_DATA_SET_LB_PROVISIONING_STATE(_V2); plus
4311 // 3. The size of a ULONG array large enough to hold a bit for each slab requested.
4312 // (The first element is already allocated in DEVICE_DATA_SET_LB_PROVISIONING_STATE(_V2).)
4313 //
4314#if (NTDDI_VERSION >= NTDDI_WINBLUE)
4316
4317 requiredOutputLength = (ULONG)(sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT)
4319 + (((requestedSlabs - 1) / bitMapGranularityInBits))
4320 * FIELD_SIZE(DEVICE_DATA_SET_LB_PROVISIONING_STATE_V2, SlabAllocationBitMap[0]));
4321
4322 } else
4323#else
4324 UNREFERENCED_PARAMETER(OutputVersion);
4325#endif
4326 {
4327
4328 requiredOutputLength = (ULONG)(sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT)
4330 + (((requestedSlabs - 1) / bitMapGranularityInBits))
4331 * FIELD_SIZE(DEVICE_DATA_SET_LB_PROVISIONING_STATE, SlabAllocationBitMap[0]));
4332 }
4333
4334 //
4335 // The output buffer is not big enough to hold the requested data.
4336 // Inform the caller of the correct buffer size.
4337 //
4338 if (outputLength < requiredOutputLength)
4339 {
4341
4342 TracePrint((TRACE_LEVEL_ERROR,
4343 TRACE_FLAG_IOCTL,
4344 "ClasspDeviceGetLBAStatusWorker (%p): Given output buffer is %u bytes, needs to be %u bytes\n",
4346 outputLength,
4347 requiredOutputLength));
4348
4349 //
4350 // If the output buffer is big enough, write the required buffer
4351 // length to the first ULONG bytes of the output buffer.
4352 //
4353 if (outputLength >= sizeof(ULONG))
4354 {
4355 *((PULONG)DsmOutput) = requiredOutputLength;
4356 }
4357
4358 goto Exit;
4359 }
4360
4361 //
4362 // Calculate the maximum number of slabs that could be returned by a single
4363 // Get LBA Status command. The max buffer size could either be capped by
4364 // the Parameter Data Length field or the Max Transfer Length of the
4365 // adapter.
4366 // The number of slabs we actually ask for in a single command is the
4367 // smaller of the number of slabs requested by the user or the max number
4368 // of slabs we can theoretically ask for in a single command.
4369 //
4370 maxBufferSize = MIN(MAXULONG, fdoExtension->PrivateFdoData->HwMaxXferLen);
4371 maxSlabs = (maxBufferSize - sizeof(LBA_STATUS_LIST_HEADER)) / sizeof(LBA_STATUS_DESCRIPTOR);
4372 slabsPerCommand = min(requestedSlabs, maxSlabs);
4373
4374 //
4375 // Allocate the buffer that will contain the returned LBA Status Descriptors.
4376 // Assume that in the worst case every other slab has a different mapping
4377 // status. That means that there may be a descriptor for every slab requested.
4378 //
4379 lbaStatusSize = (ULONG)(sizeof(LBA_STATUS_LIST_HEADER) + (slabsPerCommand * sizeof(LBA_STATUS_DESCRIPTOR)));
4380#if defined(_ARM_) || defined(_ARM64_)
4381 //
4382 // ARM has specific alignment requirements, although this will not have a functional impact on x86 or amd64
4383 // based platforms. We are taking the conservative approach here.
4384 //
4385 lbaStatusSize = ALIGN_UP_BY(lbaStatusSize,KeGetRecommendedSharedDataAlignment());
4386 lbaStatusListHeader = (PLBA_STATUS_LIST_HEADER)ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, lbaStatusSize, CLASS_TAG_LB_PROVISIONING);
4387#else
4388 lbaStatusListHeader = (PLBA_STATUS_LIST_HEADER)ExAllocatePoolWithTag(NonPagedPoolNx, lbaStatusSize, CLASS_TAG_LB_PROVISIONING);
4389#endif
4390
4391 if (lbaStatusListHeader == NULL)
4392 {
4393 TracePrint((TRACE_LEVEL_ERROR,
4394 TRACE_FLAG_IOCTL,
4395 "ClasspDeviceGetLBAStatusWorker (%p): Failed to allocate %u bytes for descriptors\n",
4397 lbaStatusSize));
4398
4399 NT_ASSERT(lbaStatusListHeader != NULL);
4401 goto Exit;
4402 }
4403
4404 //
4405 // Set default values for the output buffer.
4406 // If we process at least one slab from the device we will update the
4407 // offset and lengths accordingly.
4408 //
4409 DsmOutput->Action = DeviceDsmAction_Allocation;
4410 DsmOutput->Size = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT);
4411 DsmOutput->OutputBlockOffset = 0;
4412 DsmOutput->OutputBlockLength = 0;
4413 *DsmOutputLength = DsmOutput->Size;
4414
4415 //
4416 // The returned DEVICE_DATA_SET_LB_PROVISIONING_STATE is at the end of the
4417 // DSM output structure. Zero it out before we start to fill it in.
4418 //
4419 lbpState = Add2Ptr(DsmOutput, sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT));
4420 RtlZeroMemory(lbpState, requiredOutputLength - sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT));
4421
4422 do {
4423 //
4424 // Send down GetLBAStatus for the current range.
4425 //
4426 status = GetLBAStatus(fdoExtension,
4427 Srb,
4428 startingLBA,
4429 lbaStatusListHeader,
4430 lbaStatusSize,
4431 ConsolidateableBlocksOnly);
4432
4433 if (NT_SUCCESS(status))
4434 {
4435 ULONG descrIndex = 0;
4436 ULONG descrSize = 0;
4437 ULONG descrSizeOverhead;
4438 ULONG descrCount = 0;
4439 ULONGLONG expectedStartingLBA;
4440 BOOLEAN processCurrentDescriptor = TRUE;
4441 ULONG commandProcessedSlabs = 0; // Number of slabs processed for this command.
4442
4443 descrSizeOverhead = FIELD_OFFSET(LBA_STATUS_LIST_HEADER, Descriptors[0]) -
4445 REVERSE_BYTES(&descrSize, &(lbaStatusListHeader->ParameterLength));
4446
4447 //
4448 // If the returned Parameter Data Length field describes more
4449 // descriptors than we allocated space for then make sure we don't
4450 // try to process more descriptors than are actually present.
4451 //
4452 if (descrSize > (lbaStatusSize - RTL_SIZEOF_THROUGH_FIELD(LBA_STATUS_LIST_HEADER, ParameterLength))) {
4453 descrSize = (lbaStatusSize - RTL_SIZEOF_THROUGH_FIELD(LBA_STATUS_LIST_HEADER, ParameterLength));
4454 }
4455
4456 if (descrSize >= descrSizeOverhead) {
4457 descrSize -= descrSizeOverhead;
4458 descrCount = descrSize / sizeof(LBA_STATUS_DESCRIPTOR);
4459
4460 //
4461 // Make sure at least one descriptor was returned.
4462 //
4463 if (descrCount > 0) {
4464 //
4465 // We expect the first starting LBA returned by the device to be the
4466 // same starting LBA we specified in the command.
4467 //
4468 expectedStartingLBA = startingLBA;
4469
4470 //
4471 // Translate the returned LBA status descriptors into a bitmap where each bit represents
4472 // a slab. The slab size is represented by the Optimal Unmap Granularity.
4473 // 1 = The slab is mapped.
4474 // 0 = The slab is unmapped (deallocated or anchored).
4475 //
4476 for (descrIndex = 0; descrIndex < descrCount && totalProcessedSlabs < requestedSlabs && !doneProcessing; descrIndex++)
4477 {
4478 PLBA_STATUS_DESCRIPTOR lbaStatusDescr = &(lbaStatusListHeader->Descriptors[descrIndex]);
4479 ULONGLONG returnedStartingLBA;
4480 ULONG mapped = (lbaStatusDescr->ProvisioningStatus != LBA_STATUS_MAPPED) ? 0x0 : 0x1;
4481 ULONG lbaCount = 0;
4482
4483 REVERSE_BYTES_QUAD(&returnedStartingLBA, &(lbaStatusDescr->StartingLBA));
4484 REVERSE_BYTES(&lbaCount, &(lbaStatusDescr->LogicalBlockCount));
4485
4486 if (returnedStartingLBA != expectedStartingLBA)
4487 {
4488 //
4489 // We expect the descriptors will express a contiguous range of LBAs.
4490 // If the starting LBA is not contiguous with the LBA range from the
4491 // previous descriptor then we should not process any more descriptors,
4492 // including the current one.
4493 //
4494 TracePrint((TRACE_LEVEL_ERROR,
4495 TRACE_FLAG_IOCTL,
4496 "ClasspDeviceGetLBAStatusWorker (%p): Device returned starting LBA = %I64x when %I64x was expected.\n",
4498 returnedStartingLBA,
4499 startingLBA));
4500
4501 doneProcessing = TRUE;
4502 processCurrentDescriptor = FALSE;
4503 *BlockLimitsDataMayHaveChanged = TRUE;
4504 }
4505 else if (lbaCount > 0 && lbaCount % blocksPerSlab != 0)
4506 {
4507 //
4508 // If the device returned an LBA count with a partial slab, round
4509 // the LBA count up to the nearest slab and set a flag to stop
4510 // processing further descriptors. This is mainly to handle the
4511 // case where disk size may not be slab-aligned and thus the last
4512 // "slab" is actually a partial slab.
4513 //
4514 TracePrint((TRACE_LEVEL_WARNING,
4515 TRACE_FLAG_IOCTL,
4516 "ClasspDeviceGetLBAStatusWorker (%p): Device returned an LBA count (%u) that is not a multiple of the slab size (%u)\n",
4518 lbaCount,
4519 blocksPerSlab));
4520
4521 lbaCount = ((lbaCount / blocksPerSlab) + 1) * blocksPerSlab;
4522
4523 doneProcessing = TRUE;
4524 processCurrentDescriptor = TRUE;
4525 }
4526 else if (lbaCount == 0)
4527 {
4528 //
4529 // If the LBA count is 0, just skip this descriptor.
4530 //
4531 TracePrint((TRACE_LEVEL_WARNING,
4532 TRACE_FLAG_IOCTL,
4533 "ClasspDeviceGetLBAStatusWorker (%p): Device returned a zero LBA count\n",
4534 DeviceObject));
4535
4536 processCurrentDescriptor = FALSE;
4537 }
4538
4539 //
4540 // Generate bits for the slabs described in the current descriptor.
4541 // It's possible the device may have returned more slabs than requested
4542 // so we make sure to stop once we've processed all we need.
4543 //
4544 if (processCurrentDescriptor)
4545 {
4546 ULONG descrSlabs = lbaCount / blocksPerSlab; // Number of slabs in this descriptor.
4547
4548 for(; 0 < descrSlabs && totalProcessedSlabs < requestedSlabs; descrSlabs--, commandProcessedSlabs++, totalProcessedSlabs++)
4549 {
4550 ULONG bitMapIndex = totalProcessedSlabs / bitMapGranularityInBits;
4551 ULONG bitPos = totalProcessedSlabs % bitMapGranularityInBits;
4552
4553 #if (NTDDI_VERSION >= NTDDI_WINBLUE)
4555 ((PDEVICE_DATA_SET_LB_PROVISIONING_STATE_V2)lbpState)->SlabAllocationBitMap[bitMapIndex] |= (mapped << bitPos);
4556 } else
4557 #endif
4558 {
4559 lbpState->SlabAllocationBitMap[bitMapIndex] |= (mapped << bitPos);
4560 }
4561 }
4562 }
4563
4564 //
4565 // Calculate the next expected starting LBA.
4566 //
4567 expectedStartingLBA = returnedStartingLBA + lbaCount;
4568 }
4569
4570 if (commandProcessedSlabs > 0) {
4571
4572 //
4573 // Calculate the starting LBA we'll use for the next command.
4574 //
4575 startingLBA += ((ULONGLONG)commandProcessedSlabs * (ULONGLONG)blocksPerSlab);
4576
4577 } else {
4578 //
4579 // This should never happen, but we should handle it gracefully anyway.
4580 //
4581 TracePrint((TRACE_LEVEL_ERROR,
4582 TRACE_FLAG_IOCTL,
4583 "ClasspDeviceGetLBAStatusWorker (%p): The slab allocation bitmap has zero length.\n",
4584 DeviceObject));
4585
4586 NT_ASSERT(commandProcessedSlabs != 0);
4587 doneProcessing = TRUE;
4589 }
4590 } else {
4591 TracePrint((TRACE_LEVEL_ERROR,
4592 TRACE_FLAG_IOCTL,
4593 "ClasspDeviceGetLBAStatusWorker (%p): Device returned no LBA Status Descriptors.\n",
4594 DeviceObject));
4595
4596 doneProcessing = TRUE;
4598 }
4599 } else {
4600 TracePrint((TRACE_LEVEL_ERROR,
4601 TRACE_FLAG_IOCTL,
4602 "ClasspDeviceGetLBAStatusWorker (%p): not enough bytes returned\n",
4603 DeviceObject));
4604
4605 doneProcessing = TRUE;
4607 }
4608 }
4609
4610 //
4611 // Loop until we encounter some error or we've processed all the requested slabs.
4612 //
4613 } while (NT_SUCCESS(status) &&
4614 !doneProcessing &&
4615 (totalProcessedSlabs < requestedSlabs));
4616
4617 //
4618 // At least one slab was returned by the device and processed, which we
4619 // consider success. It's up to the caller to detect truncation.
4620 // Update the output buffer sizes, offsets, etc. accordingly.
4621 //
4622 if (totalProcessedSlabs > 0) {
4623
4624 #if (NTDDI_VERSION >= NTDDI_WINBLUE)
4627
4628 lbpStateV2->SlabSizeInBytes = bytesPerSlab;
4629 lbpStateV2->SlabOffsetDeltaInBytes = startingOffsetDelta;
4630 lbpStateV2->SlabAllocationBitMapBitCount = totalProcessedSlabs;
4631 lbpStateV2->SlabAllocationBitMapLength = ((totalProcessedSlabs - 1) / (ULONGLONG)bitMapGranularityInBits) + 1;
4633
4634 //
4635 // Note that there is already one element of the bitmap array allocated
4636 // in the DEVICE_DATA_SET_LB_PROVISIONING_STATE_V2 structure itself, which
4637 // is why we subtract 1 from SlabAllocationBitMapLength.
4638 //
4640 + ((lbpStateV2->SlabAllocationBitMapLength - 1) * sizeof(lbpStateV2->SlabAllocationBitMap[0]));
4641
4642 } else
4643 #endif
4644 {
4645
4646 lbpState->SlabSizeInBytes = bytesPerSlab;
4647 lbpState->SlabOffsetDeltaInBytes = (ULONG)startingOffsetDelta;
4648 lbpState->SlabAllocationBitMapBitCount = totalProcessedSlabs;
4649 lbpState->SlabAllocationBitMapLength = ((totalProcessedSlabs - 1) / bitMapGranularityInBits) + 1;
4651
4652 //
4653 // Note that there is already one element of the bitmap array allocated
4654 // in the DEVICE_DATA_SET_LB_PROVISIONING_STATE structure itself, which
4655 // is why we subtract 1 from SlabAllocationBitMapLength.
4656 //
4657 lbpState->Size = sizeof(DEVICE_DATA_SET_LB_PROVISIONING_STATE)
4658 + ((lbpState->SlabAllocationBitMapLength - 1) * sizeof(lbpState->SlabAllocationBitMap[0]));
4659 }
4660
4661 DsmOutput->OutputBlockLength = lbpState->Size; // Size is at the same offset in all versions of the structure.
4662 DsmOutput->OutputBlockOffset = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT);
4663 *DsmOutputLength = DsmOutput->Size + DsmOutput->OutputBlockLength;
4664
4666 }
4667
4668 TracePrint((TRACE_LEVEL_INFORMATION,
4669 TRACE_FLAG_IOCTL,
4670 "ClasspDeviceGetLBAStatusWorker (%p): Processed a total of %u slabs\n",
4672 totalProcessedSlabs));
4673Exit:
4674
4675 FREE_POOL(lbaStatusListHeader);
4676 return status;
4677}
#define MIN(x, y)
Definition: rdesktop.h:171
_In_ PFCB _In_ LONGLONG StartingOffset
Definition: cdprocs.h:291
_Must_inspect_result_ NTSTATUS NTAPI ClassReadDriveCapacity(_In_ PDEVICE_OBJECT Fdo)
Definition: class.c:2742
NTSTATUS GetLBAStatus(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _In_ PSCSI_REQUEST_BLOCK Srb, _In_ ULONGLONG StartingLBA, _Inout_ PLBA_STATUS_LIST_HEADER LBAStatusHeader, _In_ ULONG LBAStatusSize, _In_ BOOLEAN ConsolidateableBlocksOnly)
Definition: utils.c:3772
#define RTL_SIZEOF_THROUGH_FIELD(type, field)
Definition: ntbasedef.h:672
struct _DEVICE_DATA_SET_LB_PROVISIONING_STATE DEVICE_DATA_SET_LB_PROVISIONING_STATE
#define DeviceDsmAction_Allocation
Definition: ntddstor.h:280
struct _DEVICE_DATA_SET_LB_PROVISIONING_STATE_V2 * PDEVICE_DATA_SET_LB_PROVISIONING_STATE_V2
struct _DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT
struct _DEVICE_DATA_SET_LB_PROVISIONING_STATE_V2 DEVICE_DATA_SET_LB_PROVISIONING_STATE_V2
struct _LBA_STATUS_LIST_HEADER LBA_STATUS_LIST_HEADER
#define LBA_STATUS_MAPPED
Definition: scsi.h:2786
#define REVERSE_BYTES_QUAD(Destination, Source)
Definition: scsi.h:3452
struct _LBA_STATUS_DESCRIPTOR LBA_STATUS_DESCRIPTOR
struct _LBA_STATUS_LIST_HEADER * PLBA_STATUS_LIST_HEADER
ULONG SlabAllocationBitMap[ANYSIZE_ARRAY]
Definition: ntddstor.h:948
ULONGLONG StartingLBA
Definition: scsi.h:2773
UCHAR ProvisioningStatus
Definition: scsi.h:2775
ULONG LogicalBlockCount
Definition: scsi.h:2774
LBA_STATUS_DESCRIPTOR Descriptors[0]
Definition: scsi.h:2783
#define MAXULONG
Definition: typedefs.h:251
uint32_t * PULONG
Definition: typedefs.h:59
_In_ ULONG ParameterLength
Definition: usbdlib.h:206
#define FIELD_SIZE(type, field)

Referenced by ClasspDeviceGetLBAStatus().

◆ ClasspDeviceGetLBProvisioningVPDPage()

NTSTATUS ClasspDeviceGetLBProvisioningVPDPage ( _In_ PDEVICE_OBJECT  DeviceObject,
_Inout_opt_ PSCSI_REQUEST_BLOCK  Srb 
)

Definition at line 2350 of file utils.c.

2354{
2357 USHORT pageLength = 0;
2358
2360 UCHAR bufferLength = VPD_MAX_BUFFER_SIZE; // use biggest buffer possible
2361 ULONG allocationBufferLength = bufferLength; // Since the CDB size may differ from the actual buffer allocation
2362 PCDB cdb;
2363 ULONG dataTransferLength = 0;
2365
2366 //
2367 // if the informaiton has been attempted to retrieve, return the cached status.
2368 //
2369 if (fdoExtension->FunctionSupportInfo->LBProvisioningData.CommandStatus != -1) {
2370 // get cached NTSTATUS from previous call.
2371 return fdoExtension->FunctionSupportInfo->LBProvisioningData.CommandStatus;
2372 }
2373
2374 //
2375 // Initialize LBProvisioningData fields to 'unsupported' defaults.
2376 //
2377 fdoExtension->FunctionSupportInfo->LBProvisioningData.ProvisioningType = PROVISIONING_TYPE_UNKNOWN;
2378 fdoExtension->FunctionSupportInfo->LBProvisioningData.LBPRZ = FALSE;
2379 fdoExtension->FunctionSupportInfo->LBProvisioningData.LBPU = FALSE;
2380 fdoExtension->FunctionSupportInfo->LBProvisioningData.ANC_SUP = FALSE;
2381 fdoExtension->FunctionSupportInfo->LBProvisioningData.ThresholdExponent = 0;
2382
2383 //
2384 // Try to get the Thin Provisioning VPD page (0xB2), if it is supported.
2385 //
2386 if (fdoExtension->FunctionSupportInfo->ValidInquiryPages.LBProvisioning == TRUE &&
2387 Srb != NULL)
2388 {
2389#if defined(_ARM_) || defined(_ARM64_)
2390 //
2391 // ARM has specific alignment requirements, although this will not have a functional impact on x86 or amd64
2392 // based platforms. We are taking the conservative approach here.
2393 //
2394 //
2395 allocationBufferLength = ALIGN_UP_BY(allocationBufferLength,KeGetRecommendedSharedDataAlignment());
2396 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, allocationBufferLength,'0CcS');
2397#else
2398 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, bufferLength,'0CcS');
2399#endif
2400 if (dataBuffer == NULL) {
2401 // return without updating FdoExtension->FunctionSupportInfo->LBProvisioningData.CommandStatus
2402 // the field will remain value as "-1", so that the command will be attempted next time this function is called.
2404 goto Exit;
2405 }
2406
2408
2409 RtlZeroMemory(dataBuffer, allocationBufferLength);
2410
2411 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2415 1,
2417 if (NT_SUCCESS(status)) {
2419 } else {
2420 //
2421 // Should not occur.
2422 //
2424 }
2425 } else {
2427 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
2430 }
2431
2432 if (NT_SUCCESS(status)) {
2433 // prepare the Srb
2434 SrbSetTimeOutValue(Srb, fdoExtension->TimeOutValue);
2437 SrbAssignSrbFlags(Srb, fdoExtension->SrbFlags);
2438
2439 SrbSetCdbLength(Srb, 6);
2440
2441 cdb = SrbGetCdb(Srb);
2442 cdb->CDB6INQUIRY3.OperationCode = SCSIOP_INQUIRY;
2443 cdb->CDB6INQUIRY3.EnableVitalProductData = 1; //EVPD bit
2444 cdb->CDB6INQUIRY3.PageCode = VPD_LOGICAL_BLOCK_PROVISIONING;
2445 cdb->CDB6INQUIRY3.AllocationLength = bufferLength; //AllocationLength field in CDB6INQUIRY3 is only one byte.
2446
2448 Srb,
2449 dataBuffer,
2450 allocationBufferLength,
2451 FALSE);
2452
2453 dataTransferLength = SrbGetDataTransferLength(Srb);
2454 }
2455
2456 //
2457 // Handle the case where we get back STATUS_DATA_OVERRUN b/c the input
2458 // buffer was larger than necessary.
2459 //
2460 if (status == STATUS_DATA_OVERRUN && dataTransferLength < bufferLength)
2461 {
2463 }
2464
2465 if (NT_SUCCESS(status)) {
2466 REVERSE_BYTES_SHORT(&pageLength, &(lbProvisioning->PageLength));
2467 }
2468
2469 if ( NT_SUCCESS(status) &&
2470 ((dataTransferLength < 0x08) ||
2472 (lbProvisioning->PageCode != VPD_LOGICAL_BLOCK_PROVISIONING)) ) {
2473 // the device should return at least 8 bytes of data for use.
2474 // 'PageCode' shall match and we need all the relevant data after the header.
2476 }
2477
2478 //
2479 // Fill in the FDO extension with either the data from the VPD page, or
2480 // use defaults if there was an error.
2481 //
2482 if (NT_SUCCESS(status))
2483 {
2484 fdoExtension->FunctionSupportInfo->LBProvisioningData.ProvisioningType = lbProvisioning->ProvisioningType;
2485 fdoExtension->FunctionSupportInfo->LBProvisioningData.LBPRZ = lbProvisioning->LBPRZ;
2486 fdoExtension->FunctionSupportInfo->LBProvisioningData.LBPU = lbProvisioning->LBPU;
2487 fdoExtension->FunctionSupportInfo->LBProvisioningData.ANC_SUP = lbProvisioning->ANC_SUP;
2488 fdoExtension->FunctionSupportInfo->LBProvisioningData.ThresholdExponent = lbProvisioning->ThresholdExponent;
2489
2490 TracePrint((TRACE_LEVEL_INFORMATION,
2491 TRACE_FLAG_PNP,
2492 "ClasspDeviceGetLBProvisioningVPDPage (%p): %s %s (rev %s) reported following parameters: \
2493 \n\t\t\tProvisioningType: %u \
2494 \n\t\t\tLBPRZ: %u \
2495 \n\t\t\tLBPU: %u \
2496 \n\t\t\tANC_SUP: %I64u \
2497 \n\t\t\tThresholdExponent: %u\n",
2499 (PCSZ)(((PUCHAR)fdoExtension->DeviceDescriptor) + fdoExtension->DeviceDescriptor->VendorIdOffset),
2500 (PCSZ)(((PUCHAR)fdoExtension->DeviceDescriptor) + fdoExtension->DeviceDescriptor->ProductIdOffset),
2501 (PCSZ)(((PUCHAR)fdoExtension->DeviceDescriptor) + fdoExtension->DeviceDescriptor->ProductRevisionOffset),
2502 lbProvisioning->ProvisioningType,
2503 lbProvisioning->LBPRZ,
2504 lbProvisioning->LBPU,
2505 lbProvisioning->ANC_SUP,
2506 lbProvisioning->ThresholdExponent));
2507 }
2508 } else {
2510 }
2511
2512 fdoExtension->FunctionSupportInfo->LBProvisioningData.CommandStatus = status;
2513
2514Exit:
2516
2517 return status;
2518}
@ Reserved2
Definition: bcd.h:202
#define VPD_LOGICAL_BLOCK_PROVISIONING
Definition: scsi.h:2418
struct _VPD_LOGICAL_BLOCK_PROVISIONING_PAGE * PVPD_LOGICAL_BLOCK_PROVISIONING_PAGE
#define PROVISIONING_TYPE_UNKNOWN
Definition: scsi.h:2588
PSTORAGE_DEVICE_DESCRIPTOR DeviceDescriptor
Definition: classpnp.h:876

Referenced by ClasspGetLBProvisioningInfo().

◆ ClasspDeviceLBProvisioningProperty()

NTSTATUS ClasspDeviceLBProvisioningProperty ( _In_ PDEVICE_OBJECT  DeviceObject,
_Inout_ PIRP  Irp,
_Inout_ PSCSI_REQUEST_BLOCK  Srb 
)

Definition at line 2894 of file utils.c.

2899{
2901 NTSTATUS blockLimitsStatus;
2903 PSTORAGE_PROPERTY_QUERY query = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer;
2905 ULONG length = 0;
2906 ULONG information = 0;
2907 CLASS_VPD_B0_DATA blockLimitsData;
2908 ULONG generationCount;
2909
2911
2913
2914 //
2915 // Check proper query type.
2916 //
2917 if (query->QueryType == PropertyExistsQuery) {
2919 goto Exit;
2920 } else if (query->QueryType != PropertyStandardQuery) {
2922 goto Exit;
2923 }
2924
2925 //
2926 // Request validation.
2927 // Note that InputBufferLength and IsFdo have been validated beforing entering this routine.
2928 //
2929
2933 goto Exit;
2934 }
2935
2936 lbpDescr = (PDEVICE_LB_PROVISIONING_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
2937
2938 length = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
2939
2940 RtlZeroMemory(lbpDescr, length);
2941
2943
2944 if (length >= sizeof(STORAGE_DESCRIPTOR_HEADER)) {
2945
2947 lbpDescr->Version = sizeof(DEVICE_LB_PROVISIONING_DESCRIPTOR);
2948 lbpDescr->Size = sizeof(DEVICE_LB_PROVISIONING_DESCRIPTOR);
2950 goto Exit;
2951 }
2952
2954 goto Exit;
2955 }
2956
2957 //
2958 // Set the structure version/size based upon the size of the given output
2959 // buffer. We may be working with an older component that was built with
2960 // the V1 structure definition.
2961 //
2966 } else {
2967 lbpDescr->Version = sizeof(DEVICE_LB_PROVISIONING_DESCRIPTOR);
2968 lbpDescr->Size = sizeof(DEVICE_LB_PROVISIONING_DESCRIPTOR);
2970 }
2971
2972 //
2973 // Take a snapshot of the block limits data since it can change.
2974 // If we failed to get the block limits data, we'll just set the Optimal
2975 // Unmap Granularity (and alignment) will default to 0. We don't want to
2976 // fail the request outright since there is some non-block limits data that
2977 // we can return.
2978 //
2979 blockLimitsStatus = ClasspBlockLimitsDataSnapshot(fdoExtension,
2980 TRUE,
2981 &blockLimitsData,
2982 &generationCount);
2983
2984 //
2985 // Fill in the output buffer. All data is copied from the FDO extension where we
2986 // cached Logical Block Provisioning info when the device was first initialized.
2987 //
2988
2989 lbpDescr->ThinProvisioningEnabled = ClasspIsThinProvisioned(fdoExtension->FunctionSupportInfo);
2990
2991 //
2992 // Make sure we have a non-zero value for the number of bytes per block.
2993 //
2994 if (fdoExtension->DiskGeometry.BytesPerSector == 0)
2995 {
2997 if(!NT_SUCCESS(status) || fdoExtension->DiskGeometry.BytesPerSector == 0)
2998 {
3000 information = 0;
3001 goto Exit;
3002 }
3003 }
3004
3005 lbpDescr->ThinProvisioningReadZeros = fdoExtension->FunctionSupportInfo->LBProvisioningData.LBPRZ;
3006 lbpDescr->AnchorSupported = fdoExtension->FunctionSupportInfo->LBProvisioningData.ANC_SUP;
3007
3008 if (NT_SUCCESS(blockLimitsStatus)) {
3009 lbpDescr->UnmapGranularityAlignmentValid = blockLimitsData.UGAVALID;
3010
3011 //
3012 // Granularity and Alignment are given to us in units of blocks,
3013 // but we convert and return them in bytes as it is more convenient
3014 // to the caller.
3015 //
3016 lbpDescr->OptimalUnmapGranularity = (ULONGLONG)blockLimitsData.OptimalUnmapGranularity * fdoExtension->DiskGeometry.BytesPerSector;
3018
3019#if (NTDDI_VERSION >= NTDDI_WINBLUE)
3020 //
3021 // If the output buffer is large enough (i.e. not a V1 structure) copy
3022 // over the max UNMAP LBA count and max UNMAP block descriptor count.
3023 //
3025 lbpDescr->MaxUnmapLbaCount = blockLimitsData.MaxUnmapLbaCount;
3026 lbpDescr->MaxUnmapBlockDescriptorCount = blockLimitsData.MaxUnmapBlockDescrCount;
3027 }
3028#endif
3029 }
3030
3031Exit:
3032
3033 //
3034 // Set the size and status in IRP
3035 //
3036 Irp->IoStatus.Information = information;
3037 Irp->IoStatus.Status = status;
3038
3041
3042 return status;
3043}
FORCEINLINE BOOLEAN ClasspIsThinProvisioned(_In_ PCLASS_FUNCTION_SUPPORT_INFO SupportInfo)
Definition: classp.h:1317
struct _DEVICE_LB_PROVISIONING_DESCRIPTOR * PDEVICE_LB_PROVISIONING_DESCRIPTOR
struct _DEVICE_LB_PROVISIONING_DESCRIPTOR DEVICE_LB_PROVISIONING_DESCRIPTOR
#define DEVICE_LB_PROVISIONING_DESCRIPTOR_V1_SIZE
Definition: ntddstor.h:661
BOOLEAN UGAVALID
Definition: classpnp.h:754
ULONG UnmapGranularityAlignment
Definition: classpnp.h:753
ULONG MaxUnmapBlockDescrCount
Definition: classpnp.h:751
ULONG OptimalUnmapGranularity
Definition: classpnp.h:752
ULONG MaxUnmapLbaCount
Definition: classpnp.h:750

Referenced by ClassDeviceControl().

◆ ClasspDeviceMediaTypeProperty()

NTSTATUS ClasspDeviceMediaTypeProperty ( _In_ PDEVICE_OBJECT  DeviceObject,
_Inout_ PIRP  Irp,
_Inout_ PSCSI_REQUEST_BLOCK  Srb 
)

Definition at line 1917 of file utils.c.

1941{
1944 PSTORAGE_PROPERTY_QUERY query = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer;
1946 PIO_STACK_LOCATION irpStack;
1947 ULONG length = 0;
1948 ULONG information = 0;
1949
1951
1952 TracePrint((TRACE_LEVEL_VERBOSE,
1953 TRACE_FLAG_IOCTL,
1954 "ClasspDeviceMediaTypeProperty (%p): Entering function.\n",
1955 DeviceObject));
1956
1957 //
1958 // Check proper query type.
1959 //
1960 if (query->QueryType == PropertyExistsQuery) {
1961
1962 //
1963 // In order to maintain consistency with the how the rest of the properties
1964 // are handled, always return success for PropertyExistsQuery.
1965 //
1967 goto __ClasspDeviceMediaTypeProperty_Exit;
1968
1969 } else if (query->QueryType != PropertyStandardQuery) {
1970
1971 TracePrint((TRACE_LEVEL_ERROR,
1972 TRACE_FLAG_IOCTL,
1973 "ClasspDeviceMediaTypeProperty (%p): Unsupported query type %x for media type property.\n",
1975 query->QueryType));
1976
1978 goto __ClasspDeviceMediaTypeProperty_Exit;
1979 }
1980
1981 //
1982 // Validate the request.
1983 // InputBufferLength and IsFdo have already been validated.
1984 //
1985
1987
1989
1990 TracePrint((TRACE_LEVEL_ERROR,
1991 TRACE_FLAG_IOCTL,
1992 "ClasspDeviceMediaTypeProperty (%p): Query property for media type at incorrect IRQL.\n",
1993 DeviceObject));
1994
1996 goto __ClasspDeviceMediaTypeProperty_Exit;
1997 }
1998
1999 length = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
2000
2001 if (length >= sizeof(STORAGE_DESCRIPTOR_HEADER)) {
2002
2004 pDesc->Version = sizeof(STORAGE_MEDIUM_PRODUCT_TYPE_DESCRIPTOR);
2005 pDesc->Size = sizeof(STORAGE_MEDIUM_PRODUCT_TYPE_DESCRIPTOR);
2006 } else {
2007
2009 goto __ClasspDeviceMediaTypeProperty_Exit;
2010 }
2011
2013
2015 goto __ClasspDeviceMediaTypeProperty_Exit;
2016 }
2017
2018 //
2019 // Only query BlockDeviceCharacteristics VPD page if device support has been confirmed.
2020 //
2021 if (fdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockDeviceCharacteristics == TRUE) {
2023 } else {
2024 //
2025 // Otherwise device was previously found lacking support for this VPD page. Fail the request.
2026 //
2028 goto __ClasspDeviceMediaTypeProperty_Exit;
2029 }
2030
2031 if (!NT_SUCCESS(status)) {
2032
2033 status = fdoExtension->FunctionSupportInfo->DeviceCharacteristicsData.CommandStatus;
2034 information = 0;
2035
2036 TracePrint((TRACE_LEVEL_ERROR,
2037 TRACE_FLAG_IOCTL,
2038 "ClasspDeviceGetBlockDeviceCharacteristicsVPDPage (%p): VPD retrieval fails with %x.\n",
2040 status));
2041
2042 goto __ClasspDeviceMediaTypeProperty_Exit;
2043 }
2044
2045 //
2046 // Fill in the output buffer. All data is copied from the FDO extension, cached
2047 // from device response to earlier VPD_BLOCK_DEVICE_CHARACTERISTICS query.
2048 //
2049 pDesc->MediumProductType = fdoExtension->FunctionSupportInfo->DeviceCharacteristicsData.MediumProductType;
2051
2052__ClasspDeviceMediaTypeProperty_Exit:
2053
2054 //
2055 // Set the size and status in IRP
2056 //
2057 Irp->IoStatus.Information = information;
2058 Irp->IoStatus.Status = status;
2059
2062
2063 TracePrint((TRACE_LEVEL_VERBOSE,
2064 TRACE_FLAG_IOCTL,
2065 "ClasspDeviceMediaTypeProperty (%p): Exiting function with status %x.\n",
2067 status));
2068
2069 return status;
2070}
NTSTATUS ClasspDeviceGetBlockDeviceCharacteristicsVPDPage(_In_ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension, _In_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:2072
STORAGE_MEDIUM_PRODUCT_TYPE_DESCRIPTOR
Definition: ntddstor.h:615
* PSTORAGE_MEDIUM_PRODUCT_TYPE_DESCRIPTOR
Definition: ntddstor.h:615

Referenced by ClassDeviceControl().

◆ ClasspDeviceSeekPenaltyProperty()

NTSTATUS ClasspDeviceSeekPenaltyProperty ( _In_ PDEVICE_OBJECT  DeviceObject,
_In_ PIRP  Irp,
_Inout_ PSCSI_REQUEST_BLOCK  Srb 
)

Definition at line 2172 of file utils.c.

2181{
2183
2184 PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
2186 PSTORAGE_PROPERTY_QUERY query = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer;
2188 ULONG length = 0;
2189 ULONG information = 0;
2190 BOOLEAN incursSeekPenalty = TRUE;
2192
2193 if ( (DeviceObject->DeviceType != FILE_DEVICE_DISK) ||
2194 (TEST_FLAG(DeviceObject->Characteristics, FILE_FLOPPY_DISKETTE)) ||
2195 (fdoExtension->FunctionSupportInfo->LowerLayerSupport.SeekPenaltyProperty == Supported) ) {
2196 // if it's not disk, forward the request to lower layer,
2197 // if the IOCTL is supported by lower stack, forward it down.
2199
2201 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
2202 return status;
2203 }
2204
2205 //
2206 // Check proper query type.
2207 //
2208
2209 if (query->QueryType == PropertyExistsQuery) {
2211 goto Exit;
2212 } else if (query->QueryType != PropertyStandardQuery) {
2214 goto Exit;
2215 }
2216
2217 //
2218 // Request validation.
2219 // Note that InputBufferLength and IsFdo have been validated beforing entering this routine.
2220 //
2221
2225 goto Exit;
2226 }
2227
2228 // do not touch this buffer because it can still be used as input buffer for lower layer in 'SupportUnknown' case.
2229 seekPenalty = (PDEVICE_SEEK_PENALTY_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
2230
2231 length = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
2232
2234
2235 if (length >= sizeof(STORAGE_DESCRIPTOR_HEADER)) {
2236
2238 seekPenalty->Version = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR);
2239 seekPenalty->Size = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR);
2241 goto Exit;
2242 }
2243
2245 goto Exit;
2246 }
2247
2248 //
2249 // note that 'Supported' case has been handled at the beginning of this function.
2250 //
2251 switch (fdoExtension->FunctionSupportInfo->LowerLayerSupport.SeekPenaltyProperty) {
2252 case SupportUnknown: {
2253 // send down request and wait for the request to complete.
2254 status = ClassForwardIrpSynchronous(commonExtension, Irp);
2255
2257 // case 1: the request is not supported by lower layer, sends down command
2258 // some port drivers (or filter drivers) return STATUS_INVALID_DEVICE_REQUEST if a request is not supported.
2259
2260 // send INQUIRY command if the VPD page is supported.
2261 if (fdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockDeviceCharacteristics == TRUE) {
2263 } else {
2264 // the INQUIRY - VPD page command to discover the info is not supported, fail the request.
2266 }
2267
2268 if (NT_SUCCESS(status)) {
2269 status = IncursSeekPenalty(fdoExtension->FunctionSupportInfo->DeviceCharacteristicsData.MediumRotationRate, &incursSeekPenalty);
2270 }
2271
2272 fdoExtension->FunctionSupportInfo->DeviceCharacteristicsData.CommandStatus = status;
2273
2274 // data is ready in fdoExtension
2275 // set the support status after the SCSI command is executed to avoid racing condition between multiple same type of requests.
2276 fdoExtension->FunctionSupportInfo->LowerLayerSupport.SeekPenaltyProperty = NotSupported;
2277
2278 // fill output buffer
2279 if (NT_SUCCESS(status)) {
2280 RtlZeroMemory(seekPenalty, length);
2281 seekPenalty->Version = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR);
2282 seekPenalty->Size = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR);
2283 seekPenalty->IncursSeekPenalty = incursSeekPenalty;
2285
2286
2287 } else {
2288 information = 0;
2289 }
2290
2291 } else {
2292 // case 2: the request is supported and it completes successfully
2293 // case 3: the request is supported by lower stack but other failure status is returned.
2294 // from now on, the same request will be send down to lower stack directly.
2295 fdoExtension->FunctionSupportInfo->LowerLayerSupport.SeekPenaltyProperty = Supported;
2296 information = (ULONG)Irp->IoStatus.Information;
2297
2298 }
2299
2300
2301 goto Exit;
2302
2303 break;
2304 }
2305
2306 case NotSupported: {
2307 status = fdoExtension->FunctionSupportInfo->DeviceCharacteristicsData.CommandStatus;
2308
2309 if (NT_SUCCESS(status)) {
2310 status = IncursSeekPenalty(fdoExtension->FunctionSupportInfo->DeviceCharacteristicsData.MediumRotationRate, &incursSeekPenalty);
2311 }
2312
2313 if (NT_SUCCESS(status)) {
2314 RtlZeroMemory(seekPenalty, length);
2315 seekPenalty->Version = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR);
2316 seekPenalty->Size = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR);
2317 seekPenalty->IncursSeekPenalty = incursSeekPenalty;
2319
2320 } else {
2321 information = 0;
2322 }
2323
2324 goto Exit;
2325
2326 break;
2327 }
2328
2329 case Supported: {
2330 NT_ASSERT(FALSE); // this case is handled at the begining of the function.
2331 break;
2332 }
2333
2334 } // end of switch (fdoExtension->FunctionSupportInfo->LowerLayerSupport.SeekPenaltyProperty)
2335
2336Exit:
2337
2338 //
2339 // Set the size and status in IRP
2340 //
2341 Irp->IoStatus.Information = information;;
2342 Irp->IoStatus.Status = status;
2343
2346
2347 return status;
2348}
static NTSTATUS IncursSeekPenalty(_In_ USHORT MediumRotationRate, _In_ PBOOLEAN IncursSeekPenalty)
Definition: utils.c:1888
struct _DEVICE_SEEK_PENALTY_DESCRIPTOR DEVICE_SEEK_PENALTY_DESCRIPTOR
struct _DEVICE_SEEK_PENALTY_DESCRIPTOR * PDEVICE_SEEK_PENALTY_DESCRIPTOR

Referenced by ClassDeviceControl().

◆ ClasspDeviceTrimProcess()

NTSTATUS ClasspDeviceTrimProcess ( _In_ PDEVICE_OBJECT  DeviceObject,
_In_ PIRP  Irp,
_In_ PGUID  ActivityId,
_Inout_ PSCSI_REQUEST_BLOCK  Srb 
)

Definition at line 3476 of file utils.c.

3487{
3489
3490 PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
3492
3493 PDEVICE_MANAGE_DATA_SET_ATTRIBUTES dsmAttributes = Irp->AssociatedIrp.SystemBuffer;
3494
3495 PDEVICE_DATA_SET_RANGE dataSetRanges;
3496 ULONG dataSetRangesCount;
3497 DEVICE_DATA_SET_RANGE entireDataSetRange = {0};
3498 ULONG i;
3499 ULONGLONG granularityAlignmentInBytes;
3500 ULONG granularityInBlocks;
3501 ULONG srbFlags = 0;
3502
3503 CLASS_VPD_B0_DATA blockLimitsData;
3504 ULONG generationCount;
3505
3506
3507 if ( (DeviceObject->DeviceType != FILE_DEVICE_DISK) ||
3508 (TEST_FLAG(DeviceObject->Characteristics, FILE_FLOPPY_DISKETTE)) ||
3509 (fdoExtension->FunctionSupportInfo->LowerLayerSupport.TrimProcess == Supported) ) {
3510 // if it's not disk, forward the request to lower layer,
3511 // if the IOCTL is supported by lower stack, forward it down.
3513
3514 TracePrint((TRACE_LEVEL_INFORMATION,
3515 TRACE_FLAG_GENERAL,
3516 "ClasspDeviceTrimProcess (%p): Lower layer supports Trim DSM IOCTL, forwarding IOCTL.\n",
3517 DeviceObject));
3518
3520 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
3521 return status;
3522 }
3523
3524 //
3525 // Request validation.
3526 // Note that InputBufferLength and IsFdo have been validated beforing entering this routine.
3527 //
3528
3532 goto Exit;
3533 }
3534
3535
3536 //
3537 // If the caller has not set the "entire dataset range" flag then at least
3538 // one dataset range should be specified. However, if the caller *has* set
3539 // the flag, then there should not be any dataset ranges specified.
3540 //
3541 if ((!TEST_FLAG(dsmAttributes->Flags, DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE) &&
3542 (dsmAttributes->DataSetRangesOffset == 0 ||
3543 dsmAttributes->DataSetRangesLength == 0)) ||
3545 (dsmAttributes->DataSetRangesOffset != 0 ||
3546 dsmAttributes->DataSetRangesLength != 0))) {
3547
3549 goto Exit;
3550 }
3551
3552 //
3553 // note that 'Supported' case has been handled at the beginning of this function.
3554 //
3555 switch (fdoExtension->FunctionSupportInfo->LowerLayerSupport.TrimProcess) {
3556 case SupportUnknown: {
3557 // send down request and wait for the request to complete.
3558 status = ClassForwardIrpSynchronous(commonExtension, Irp);
3559
3560 TracePrint((TRACE_LEVEL_INFORMATION,
3561 TRACE_FLAG_GENERAL,
3562 "ClasspDeviceTrimProcess (%p): Trim DSM IOCTL support unknown. Forwarded IOCTL and received NTSTATUS %!STATUS!.\n",
3564 status));
3565
3567 // case 1: the request is not supported by lower layer, sends down command
3568 // some port drivers (or filter drivers) return STATUS_INVALID_DEVICE_REQUEST if a request is not supported.
3569 // In this case we'll just fall through to the NotSupported case so that we can handle it ourselves.
3570
3571 //
3572 // VPD pages 0xB2 and 0xB0 should have been cached in Start Device phase - ClassPnpStartDevice.
3573 // 0xB2 page: fdoExtension->FunctionSupportInfo->LBProvisioningData;
3574 // 0xB0 page: fdoExtension->FunctionSupportInfo->BlockLimitsData
3575 //
3576 if (fdoExtension->FunctionSupportInfo->ValidInquiryPages.LBProvisioning == TRUE) {
3577 NT_ASSERT(fdoExtension->FunctionSupportInfo->LBProvisioningData.CommandStatus != -1);
3578 }
3579
3580 if (fdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockLimits == TRUE) {
3581 NT_ASSERT(fdoExtension->FunctionSupportInfo->BlockLimitsData.CommandStatus != -1);
3582 }
3583
3584 } else {
3585
3586 // case 2: the request is supported and it completes successfully
3587 // case 3: the request is supported by lower stack but other failure status is returned.
3588 // from now on, the same request will be send down to lower stack directly.
3589 fdoExtension->FunctionSupportInfo->LowerLayerSupport.TrimProcess = Supported;
3590 goto Exit;
3591 }
3592 }
3593
3594 case NotSupported: {
3595
3596 // send UNMAP command if it is supported. don't need to check 'status' value.
3597 if (ClasspSupportsUnmap(fdoExtension->FunctionSupportInfo))
3598 {
3599 //
3600 // Make sure that we know the bytes per sector (logical block) as it's
3601 // necessary for calculations involving granularity and alignment.
3602 //
3603 if (fdoExtension->DiskGeometry.BytesPerSector == 0) {
3604 status = ClassReadDriveCapacity(fdoExtension->DeviceObject);
3605 if(!NT_SUCCESS(status) || fdoExtension->DiskGeometry.BytesPerSector == 0) {
3607 goto Exit;
3608 }
3609 }
3610
3611 //
3612 // Take a snapshot of the block limits data since it can change.
3613 // It's acceptable if the block limits data is outdated since
3614 // there isn't a hard requirement on the unmap granularity.
3615 //
3616 ClasspBlockLimitsDataSnapshot(fdoExtension,
3617 FALSE,
3618 &blockLimitsData,
3619 &generationCount);
3620
3621 //
3622 // Check to see if the Optimal Unmap Granularity and Unmap Granularity
3623 // Alignment have been specified. If not, default the granularity to
3624 // one block and the alignment to zero.
3625 //
3626 if (blockLimitsData.OptimalUnmapGranularity != 0)
3627 {
3628 granularityInBlocks = blockLimitsData.OptimalUnmapGranularity;
3629 }
3630 else
3631 {
3632 granularityInBlocks = 1;
3633
3634 TracePrint((TRACE_LEVEL_INFORMATION,
3635 TRACE_FLAG_GENERAL,
3636 "ClasspDeviceTrimProcess (%p): Optimal Unmap Granularity not provided, defaulted to 1.\n",
3637 DeviceObject));
3638 }
3639
3640 if (blockLimitsData.UGAVALID == TRUE)
3641 {
3642 granularityAlignmentInBytes = (ULONGLONG)blockLimitsData.UnmapGranularityAlignment * fdoExtension->DiskGeometry.BytesPerSector;
3643 }
3644 else
3645 {
3646 granularityAlignmentInBytes = 0;
3647
3648 TracePrint((TRACE_LEVEL_INFORMATION,
3649 TRACE_FLAG_GENERAL,
3650 "ClasspDeviceTrimProcess (%p): Unmap Granularity Alignment not provided, defaulted to 0.\n",
3651 DeviceObject));
3652 }
3653
3655 {
3656 //
3657 // The caller wants to UNMAP the entire disk so we need to build a single
3658 // dataset range that represents the entire disk.
3659 //
3660 entireDataSetRange.StartingOffset = granularityAlignmentInBytes;
3661 entireDataSetRange.LengthInBytes = (ULONGLONG)fdoExtension->CommonExtension.PartitionLength.QuadPart - (ULONGLONG)entireDataSetRange.StartingOffset;
3662
3663 dataSetRanges = &entireDataSetRange;
3664 dataSetRangesCount = 1;
3665 }
3666 else
3667 {
3668
3669 dataSetRanges = (PDEVICE_DATA_SET_RANGE)((PUCHAR)dsmAttributes + dsmAttributes->DataSetRangesOffset);
3670 dataSetRangesCount = dsmAttributes->DataSetRangesLength / sizeof(DEVICE_DATA_SET_RANGE);
3671
3672 //
3673 // Validate the data ranges. Make sure the range is block-aligned,
3674 // falls in a valid portion of the disk, and is non-zero.
3675 //
3676 for (i = 0; i < dataSetRangesCount; i++)
3677 {
3678 if ((dataSetRanges[i].StartingOffset % fdoExtension->DiskGeometry.BytesPerSector != 0) ||
3679 (dataSetRanges[i].LengthInBytes % fdoExtension->DiskGeometry.BytesPerSector != 0) ||
3680 (dataSetRanges[i].StartingOffset < (LONGLONG)granularityAlignmentInBytes) ||
3681 (dataSetRanges[i].LengthInBytes == 0) ||
3682 ((ULONGLONG)dataSetRanges[i].StartingOffset + dataSetRanges[i].LengthInBytes > (ULONGLONG)fdoExtension->CommonExtension.PartitionLength.QuadPart))
3683 {
3684 TracePrint((TRACE_LEVEL_ERROR,
3685 TRACE_FLAG_IOCTL,
3686 "ClasspDeviceTrimProcess (%p): Invalid dataset range. StartingOffset = %I64x, LengthInBytes = %I64x\n",
3688 dataSetRanges[i].StartingOffset,
3689 dataSetRanges[i].LengthInBytes));
3690
3692 goto Exit;
3693 }
3694 }
3695 }
3696
3697
3699 {
3700 {
3701 //
3702 // For security reasons, file-level TRIM must be forwarded on only
3703 // if reading the unmapped blocks' contents will return back zeros.
3704 // This is because if LBPRZ bit is not set, it indicates that a read
3705 // of unmapped blocks may return "any" data thus potentially leaking
3706 // in data (into the read buffer) from other blocks.
3707 //
3708 if (fdoExtension->FunctionSupportInfo->ValidInquiryPages.LBProvisioning &&
3709 !fdoExtension->FunctionSupportInfo->LBProvisioningData.LBPRZ) {
3710
3711 TracePrint((TRACE_LEVEL_ERROR,
3712 TRACE_FLAG_IOCTL,
3713 "ClasspDeviceTrimProcess (%p): Device does not support file level TRIM.\n",
3714 DeviceObject));
3715
3717 goto Exit;
3718 }
3719 }
3720 }
3721
3722 // process DSM IOCTL
3723 status = DeviceProcessDsmTrimRequest(fdoExtension,
3724 dataSetRanges,
3725 dataSetRangesCount,
3726 granularityInBlocks,
3727 srbFlags,
3728 Irp,
3729 ActivityId,
3730 Srb);
3731 } else {
3732 // DSM IOCTL should be completed as not supported
3733
3734 TracePrint((TRACE_LEVEL_ERROR,
3735 TRACE_FLAG_IOCTL,
3736 "ClasspDeviceTrimProcess (%p): Device does not support UNMAP.\n",
3737 DeviceObject));
3738
3740 }
3741
3742 // set the support status after the SCSI command is executed to avoid racing condition between multiple same type of requests.
3743 fdoExtension->FunctionSupportInfo->LowerLayerSupport.TrimProcess = NotSupported;
3744
3745 break;
3746 }
3747
3748 case Supported: {
3749 NT_ASSERT(FALSE); // this case is handled at the begining of the function.
3750 break;
3751 }
3752
3753 } // end of switch (fdoExtension->FunctionSupportInfo->LowerLayerSupport.TrimProcess)
3754
3755Exit:
3756
3757 //
3758 // Set the size and status in IRP
3759 //
3760 Irp->IoStatus.Information = 0;
3761 Irp->IoStatus.Status = status;
3762
3763
3764
3767
3768 return status;
3769}
FORCEINLINE BOOLEAN ClasspSupportsUnmap(_In_ PCLASS_FUNCTION_SUPPORT_INFO SupportInfo)
Definition: classp.h:1308
NTSTATUS DeviceProcessDsmTrimRequest(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _In_ PDEVICE_DATA_SET_RANGE DataSetRanges, _In_ ULONG DataSetRangesCount, _In_ ULONG UnmapGranularity, _In_ ULONG SrbFlags, _In_ PIRP Irp, _In_ PGUID ActivityId, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:3164
#define DEVICE_DSM_FLAG_TRIM_NOT_FS_ALLOCATED
Definition: ntddstor.h:764
struct _DEVICE_DATA_SET_RANGE DEVICE_DATA_SET_RANGE
#define STATUS_TRIM_READ_ZERO_NOT_SUPPORTED
Definition: ntstatus.h:1000
ULONGLONG LengthInBytes
Definition: ntddstor.h:768
LONGLONG StartingOffset
Definition: ntddstor.h:767
_In_ PCEVENT_DESCRIPTOR _In_opt_ LPCGUID ActivityId
Definition: wmifuncs.h:120

Referenced by ClassDeviceControl().

◆ ClasspDeviceTrimProperty()

NTSTATUS ClasspDeviceTrimProperty ( _In_ PDEVICE_OBJECT  DeviceObject,
_In_ PIRP  Irp,
_Inout_ PSCSI_REQUEST_BLOCK  Srb 
)

Definition at line 2730 of file utils.c.

2739{
2741
2742 PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
2744 PSTORAGE_PROPERTY_QUERY query = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer;
2746 ULONG length = 0;
2747 ULONG information = 0;
2748
2749 PDEVICE_TRIM_DESCRIPTOR trimDescr;
2750
2752
2753 if ( (DeviceObject->DeviceType != FILE_DEVICE_DISK) ||
2754 (TEST_FLAG(DeviceObject->Characteristics, FILE_FLOPPY_DISKETTE)) ||
2755 (fdoExtension->FunctionSupportInfo->LowerLayerSupport.TrimProperty == Supported) ) {
2756 // if it's not disk, forward the request to lower layer,
2757 // if the IOCTL is supported by lower stack, forward it down.
2759
2761 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
2762 return status;
2763 }
2764
2765 //
2766 // Check proper query type.
2767 //
2768
2769 if (query->QueryType == PropertyExistsQuery) {
2771 goto Exit;
2772 } else if (query->QueryType != PropertyStandardQuery) {
2774 goto Exit;
2775 }
2776