ReactOS 0.4.15-dev-7958-gcd0bb1a
utils.c
Go to the documentation of this file.
1/*++
2
3Copyright (C) Microsoft Corporation, 1991 - 2010
4
5Module Name:
6
7 utils.c
8
9Abstract:
10
11 SCSI class driver routines
12
13Environment:
14
15 kernel mode only
16
17Notes:
18
19
20Revision History:
21
22--*/
23
24
25#include "classp.h"
26#include "debug.h"
27#include <ntiologc.h>
28
29
30#ifdef DEBUG_USE_WPP
31#include "utils.tmh"
32#endif
33
34//
35// Constant value used in firmware upgrade process.
36//
37#define FIRMWARE_ACTIVATE_TIMEOUT_VALUE 30
38
39
40#ifdef ALLOC_PRAGMA
41 #pragma alloc_text(PAGE, ClassGetDeviceParameter)
42 #pragma alloc_text(PAGE, ClassScanForSpecial)
43 #pragma alloc_text(PAGE, ClassSetDeviceParameter)
44 #pragma alloc_text(PAGE, ClasspMyStringMatches)
45 #pragma alloc_text(PAGE, ClasspDeviceCopyOffloadProperty)
46 #pragma alloc_text(PAGE, ClasspValidateOffloadSupported)
47 #pragma alloc_text(PAGE, ClasspValidateOffloadInputParameters)
48#endif
49
50// custom string match -- careful!
52{
53 ULONG length; // strlen returns an int, not size_t (!)
54 PAGED_CODE();
56 // if no match requested, return TRUE
57 if (StringToMatch == NULL) {
58 return TRUE;
59 }
60 // cache the string length for efficiency
61 length = (ULONG)strlen(StringToMatch);
62 // ZERO-length strings may only match zero-length strings
63 if (length == 0) {
64 return (strlen(TargetString) == 0);
65 }
66 // strncmp returns zero if the strings match
67 return (strncmp(StringToMatch, TargetString, length) == 0);
68}
69
70
72VOID
73NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
74ClassGetDeviceParameter(
78 _Inout_ PULONG ParameterValue // also default value
79 )
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()
228
231NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
232ClassSetDeviceParameter(
237{
239 HANDLE deviceParameterHandle = NULL;
240 HANDLE deviceSubkeyHandle = NULL;
241
242 PAGED_CODE();
243
244 //
245 // open the given parameter
246 //
247
251 &deviceParameterHandle);
252
253 if (NT_SUCCESS(status) && (SubkeyName != NULL)) {
254
255 UNICODE_STRING subkeyName;
256 OBJECT_ATTRIBUTES objectAttributes;
257
258 RtlInitUnicodeString(&subkeyName, SubkeyName);
259 InitializeObjectAttributes(&objectAttributes,
260 &subkeyName,
262 deviceParameterHandle,
263 NULL);
264
265 status = ZwCreateKey(&deviceSubkeyHandle,
267 &objectAttributes,
268 0, NULL, 0, NULL);
269 if (!NT_SUCCESS(status)) {
270 ZwClose(deviceParameterHandle);
271 }
272
273 }
274
275 if (NT_SUCCESS(status)) {
276
279 (PWSTR) (SubkeyName ?
280 deviceSubkeyHandle :
281 deviceParameterHandle),
283 REG_DWORD,
285 sizeof(ULONG));
286
287 //
288 // close what we open
289 //
290
291 if (SubkeyName) {
292 ZwClose(deviceSubkeyHandle);
293 }
294
295 ZwClose(deviceParameterHandle);
296 }
297
298 return status;
299
300} // end ClassSetDeviceParameter()
301
302
303/*
304 * ClassScanForSpecial
305 *
306 * This routine was written to simplify scanning for special
307 * hardware based upon id strings. it does not check the registry.
308 */
309
311VOID
312NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
313ClassScanForSpecial(
316 _In_ PCLASS_SCAN_FOR_SPECIAL_HANDLER Function)
317{
318 PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;
319 PUCHAR vendorId;
320 PUCHAR productId;
321 PUCHAR productRevision;
322 UCHAR nullString[] = "";
323
324 PAGED_CODE();
327
328 deviceDescriptor = FdoExtension->DeviceDescriptor;
329
330 if (DeviceList == NULL) {
331 return;
332 }
333 if (Function == NULL) {
334 return;
335 }
336
337 //
338 // SCSI sets offsets to -1, ATAPI sets to 0. check for both.
339 //
340
341 if (deviceDescriptor->VendorIdOffset != 0 &&
342 deviceDescriptor->VendorIdOffset != -1) {
343 vendorId = ((PUCHAR)deviceDescriptor);
344 vendorId += deviceDescriptor->VendorIdOffset;
345 } else {
346 vendorId = nullString;
347 }
348 if (deviceDescriptor->ProductIdOffset != 0 &&
349 deviceDescriptor->ProductIdOffset != -1) {
350 productId = ((PUCHAR)deviceDescriptor);
351 productId += deviceDescriptor->ProductIdOffset;
352 } else {
353 productId = nullString;
354 }
355 if (deviceDescriptor->ProductRevisionOffset != 0 &&
356 deviceDescriptor->ProductRevisionOffset != -1) {
357 productRevision = ((PUCHAR)deviceDescriptor);
358 productRevision += deviceDescriptor->ProductRevisionOffset;
359 } else {
360 productRevision = nullString;
361 }
362
363 //
364 // loop while the device list is valid (not null-filled)
365 //
366
367 for (;(DeviceList->VendorId != NULL ||
368 DeviceList->ProductId != NULL ||
369 DeviceList->ProductRevision != NULL);DeviceList++) {
370
371 if (ClasspMyStringMatches(DeviceList->VendorId, (PCHAR)vendorId) &&
372 ClasspMyStringMatches(DeviceList->ProductId, (PCHAR)productId) &&
373 ClasspMyStringMatches(DeviceList->ProductRevision, (PCHAR)productRevision)
374 ) {
375
376 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "ClasspScanForSpecialByInquiry: Found matching "
377 "controller Ven: %s Prod: %s Rev: %s\n",
378 (PCSZ)vendorId, (PCSZ)productId, (PCSZ)productRevision));
379
380 //
381 // pass the context to the call back routine and exit
382 //
383
385
386 //
387 // for CHK builds, try to prevent wierd stacks by having a debug
388 // print here. it's a hack, but i know of no other way to prevent
389 // the stack from being wrong.
390 //
391
392 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "ClasspScanForSpecialByInquiry: "
393 "completed callback\n"));
394 return;
395
396 } // else the strings did not match
397
398 } // none of the devices matched.
399
400 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "ClasspScanForSpecialByInquiry: no match found for %p\n",
401 FdoExtension->DeviceObject));
402 return;
403
404} // end ClasspScanForSpecialByInquiry()
405
406
407//
408// In order to provide better performance without the need to reboot,
409// we need to implement a self-adjusting method to set and clear the
410// srb flags based upon current performance.
411//
412// whenever there is an error, immediately grab the spin lock. the
413// MP perf hit here is acceptable, since we're in an error path. this
414// is also neccessary because we are guaranteed to be modifying the
415// SRB flags here, setting SuccessfulIO to zero, and incrementing the
416// actual error count (which is always done within this spinlock).
417//
418// whenever there is no error, increment a counter. if there have been
419// errors on the device, and we've enabled dynamic perf, *and* we've
420// just crossed the perf threshhold, then grab the spin lock and
421// double check that the threshhold has, indeed been hit(*). then
422// decrement the error count, and if it's dropped sufficiently, undo
423// some of the safety changes made in the SRB flags due to the errors.
424//
425// * this works in all cases. even if lots of ios occur after the
426// previous guy went in and cleared the successfulio counter, that
427// just means that we've hit the threshhold again, and so it's proper
428// to run the inner loop again.
429//
430
431VOID
434 )
435{
436 PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
437 KIRQL oldIrql;
438 ULONG errors;
439
440 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
441
442 fdoData->Perf.SuccessfulIO = 0; // implicit interlock
443 errors = InterlockedIncrement((volatile LONG *)&FdoExtension->ErrorCount);
444
445 if (!fdoData->DisableThrottling) {
446
447 if (errors >= CLASS_ERROR_LEVEL_1) {
448
449 //
450 // If the error count has exceeded the error limit, then disable
451 // any tagged queuing, multiple requests per lu queueing
452 // and sychronous data transfers.
453 //
454 // Clearing the no queue freeze flag prevents the port driver
455 // from sending multiple requests per logical unit.
456 //
457
460
462
463 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClasspPerfIncrementErrorCount: "
464 "Too many errors; disabling tagged queuing and "
465 "synchronous data tranfers.\n"));
466
467 }
468
469 if (errors >= CLASS_ERROR_LEVEL_2) {
470
471 //
472 // If a second threshold is reached, disable disconnects.
473 //
474
476 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClasspPerfIncrementErrorCount: "
477 "Too many errors; disabling disconnects.\n"));
478 }
479 }
480
481 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
482 return;
483}
484
485VOID
488 )
489{
490 PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
491 KIRQL oldIrql;
492 ULONG errors;
493 ULONG succeeded = 0;
494
495 //
496 // don't take a hit from the interlocked op unless we're in
497 // a degraded state and we've got a threshold to hit.
498 //
499
500 if (FdoExtension->ErrorCount == 0) {
501 return;
502 }
503
504 if (fdoData->Perf.ReEnableThreshhold == 0) {
505 return;
506 }
507
508 succeeded = InterlockedIncrement((volatile LONG *)&fdoData->Perf.SuccessfulIO);
509 if (succeeded < fdoData->Perf.ReEnableThreshhold) {
510 return;
511 }
512
513 //
514 // if we hit the threshold, grab the spinlock and verify we've
515 // actually done so. this allows us to ignore the spinlock 99%
516 // of the time.
517 //
518
519 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
520
521 //
522 // re-read the value, so we don't run this multiple times
523 // for a single threshhold being hit. this keeps errorcount
524 // somewhat useful.
525 //
526
527 succeeded = fdoData->Perf.SuccessfulIO;
528
529 if ((FdoExtension->ErrorCount != 0) &&
530 (fdoData->Perf.ReEnableThreshhold <= succeeded)
531 ) {
532
533 fdoData->Perf.SuccessfulIO = 0; // implicit interlock
534
535 NT_ASSERT(FdoExtension->ErrorCount > 0);
536 errors = InterlockedDecrement((volatile LONG *)&FdoExtension->ErrorCount);
537
538 //
539 // note: do in reverse order of the sets "just in case"
540 //
541
542 if (errors < CLASS_ERROR_LEVEL_2) {
543 if (errors == CLASS_ERROR_LEVEL_2 - 1) {
544 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClasspPerfIncrementSuccessfulIo: "
545 "Error level 2 no longer required.\n"));
546 }
547 if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
549 CLEAR_FLAG(FdoExtension->SrbFlags,
551 }
552 }
553
554 if (errors < CLASS_ERROR_LEVEL_1) {
555 if (errors == CLASS_ERROR_LEVEL_1 - 1) {
556 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClasspPerfIncrementSuccessfulIo: "
557 "Error level 1 no longer required.\n"));
558 }
559 if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
561 CLEAR_FLAG(FdoExtension->SrbFlags,
563 }
564 if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
566 SET_FLAG(FdoExtension->SrbFlags,
568 }
569 if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
571 SET_FLAG(FdoExtension->SrbFlags,
573 }
574 }
575 } // end of threshhold definitely being hit for first time
576
577 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
578 return;
579}
580
581
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}
607
608
610{
611 return ClasspBuildDeviceMdl(Buffer, BufferLen, FALSE);
612}
613
614
616{
618 IoFreeMdl(Mdl);
619}
620
621
623{
625 return;
626}
627
628
629#if 0
630 VOID
631 ClasspPerfResetCounters(
633 )
634 {
635 PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
636 KIRQL oldIrql;
637
638 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
639 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClasspPerfResetCounters: "
640 "Resetting all perf counters.\n"));
641 fdoData->Perf.SuccessfulIO = 0;
642 FdoExtension->ErrorCount = 0;
643
644 if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
646 CLEAR_FLAG(FdoExtension->SrbFlags,
648 }
649 if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
651 CLEAR_FLAG(FdoExtension->SrbFlags,
653 }
654 if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
656 SET_FLAG(FdoExtension->SrbFlags,
658 }
659 if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
661 SET_FLAG(FdoExtension->SrbFlags,
663 }
664 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
665 return;
666 }
667#endif
668
669
670/*++
671
672ClasspDuidGetDeviceIdProperty
673
674Routine Description:
675
676 Add StorageDeviceIdProperty to the device unique ID structure.
677
678Arguments:
679
680 DeviceObject - a pointer to the device object
681 Irp - a pointer to the I/O request packet
682
683Return Value:
684
685 Status Code
686
687--*/
691 IN PIRP Irp
692 )
693{
694 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
695 PSTORAGE_DEVICE_ID_DESCRIPTOR deviceIdDescriptor = NULL;
699 PUCHAR dest;
700
702
704
705 ULONG queryLength;
707
708 //
709 // Get the VPD page 83h data.
710 //
711
712 status = ClassGetDescriptor(commonExtension->LowerDeviceObject,
713 &propertyId,
714 (PVOID *)&deviceIdDescriptor);
715
716 if (!NT_SUCCESS(status) || !deviceIdDescriptor) {
717 goto FnExit;
718 }
719
720 queryLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
721 descHeader = Irp->AssociatedIrp.SystemBuffer;
722
723 //
724 // Adjust required size and potential destination location.
725 //
726
727 offset = descHeader->Size;
728 dest = (PUCHAR)descHeader + offset;
729
730 descHeader->Size += deviceIdDescriptor->Size;
731
732 if (queryLength < descHeader->Size) {
733
734 //
735 // Output buffer is too small. Return error and make sure
736 // the caller gets info about required buffer size.
737 //
738
739 Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER);
741 goto FnExit;
742 }
743
744 storageDuid = Irp->AssociatedIrp.SystemBuffer;
745 storageDuid->StorageDeviceIdOffset = offset;
746
748 deviceIdDescriptor,
749 deviceIdDescriptor->Size);
750
751 Irp->IoStatus.Information = storageDuid->Size;
753
754FnExit:
755
756 FREE_POOL(deviceIdDescriptor);
757
758 return status;
759}
760
761
762
763/*++
764
765ClasspDuidGetDeviceProperty
766
767Routine Description:
768
769 Add StorageDeviceProperty to the device unique ID structure.
770
771Arguments:
772
773 DeviceObject - a pointer to the device object
774 Irp - a pointer to the I/O request packet
775
776Return Value:
777
778 Status Code
779
780--*/
784 PIRP Irp
785 )
786{
787 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
788 PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = fdoExtension->DeviceDescriptor;
792 PUCHAR dest;
793
795
796 ULONG queryLength;
798
799 //
800 // Use the StorageDeviceProperty already cached in the device extension.
801 //
802
803 if (!deviceDescriptor) {
804 goto FnExit;
805 }
806
807 queryLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
808 descHeader = Irp->AssociatedIrp.SystemBuffer;
809
810 //
811 // Use this info only if serial number is available.
812 //
813
814 if (deviceDescriptor->SerialNumberOffset == 0) {
815 goto FnExit;
816 }
817
818 //
819 // Adjust required size and potential destination location.
820 //
821
822 offset = descHeader->Size;
823 dest = (PUCHAR)descHeader + offset;
824
825 descHeader->Size += deviceDescriptor->Size;
826
827 if (queryLength < descHeader->Size) {
828
829 //
830 // Output buffer is too small. Return error and make sure
831 // the caller get info about required buffer size.
832 //
833
834 Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER);
836 goto FnExit;
837 }
838
839 storageDuid = Irp->AssociatedIrp.SystemBuffer;
840 storageDuid->StorageDeviceOffset = offset;
841
843 deviceDescriptor,
844 deviceDescriptor->Size);
845
846 Irp->IoStatus.Information = storageDuid->Size;
848
849FnExit:
850
851 return status;
852}
853
854
855/*++
856
857ClasspDuidGetDriveLayout
858
859Routine Description:
860
861 Add drive layout signature to the device unique ID structure.
862 Layout signature is only added for disk-type devices.
863
864Arguments:
865
866 DeviceObject - a pointer to the device object
867 Irp - a pointer to the I/O request packet
868
869Return Value:
870
871 Status Code
872
873--*/
877 PIRP Irp
878 )
879{
880 PDRIVE_LAYOUT_INFORMATION_EX layoutEx = NULL;
884 PSTORAGE_DEVICE_LAYOUT_SIGNATURE driveLayoutSignature;
885
887
888 ULONG queryLength;
890
891 //
892 // Only process disk-type devices.
893 //
894
895 if (DeviceObject->DeviceType != FILE_DEVICE_DISK) {
896 goto FnExit;
897 }
898
899 //
900 // Get current partition table and process only if GPT
901 // or MBR layout.
902 //
903
905
906 if (!NT_SUCCESS(status)) {
908 goto FnExit;
909 }
910
911 if (layoutEx->PartitionStyle != PARTITION_STYLE_GPT &&
912 layoutEx->PartitionStyle != PARTITION_STYLE_MBR) {
914 goto FnExit;
915 }
916
917 queryLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
918 descHeader = Irp->AssociatedIrp.SystemBuffer;
919
920 //
921 // Adjust required size and potential destination location.
922 //
923
924 offset = descHeader->Size;
925 driveLayoutSignature = (PSTORAGE_DEVICE_LAYOUT_SIGNATURE)((PUCHAR)descHeader + offset);
926
927 descHeader->Size += sizeof(STORAGE_DEVICE_LAYOUT_SIGNATURE);
928
929 if (queryLength < descHeader->Size) {
930
931 //
932 // Output buffer is too small. Return error and make sure
933 // the caller get info about required buffer size.
934 //
935
936 Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER);
938 goto FnExit;
939 }
940
941 storageDuid = Irp->AssociatedIrp.SystemBuffer;
942
943 driveLayoutSignature->Size = sizeof(STORAGE_DEVICE_LAYOUT_SIGNATURE);
944 driveLayoutSignature->Version = DUID_VERSION_1;
945
946 if (layoutEx->PartitionStyle == PARTITION_STYLE_MBR) {
947
948 driveLayoutSignature->Mbr = TRUE;
949
950 RtlCopyMemory(&driveLayoutSignature->DeviceSpecific.MbrSignature,
951 &layoutEx->Mbr.Signature,
952 sizeof(layoutEx->Mbr.Signature));
953
954 } else {
955
956 driveLayoutSignature->Mbr = FALSE;
957
958 RtlCopyMemory(&driveLayoutSignature->DeviceSpecific.GptDiskId,
959 &layoutEx->Gpt.DiskId,
960 sizeof(layoutEx->Gpt.DiskId));
961 }
962
963 storageDuid->DriveLayoutSignatureOffset = offset;
964
965 Irp->IoStatus.Information = storageDuid->Size;
967
968
969FnExit:
970
971 FREE_POOL(layoutEx);
972
973 return status;
974}
975
976
977/*++
978
979ClasspDuidQueryProperty
980
981Routine Description:
982
983 Handles IOCTL_STORAGE_QUERY_PROPERTY for device unique ID requests
984 (when PropertyId is StorageDeviceUniqueIdProperty).
985
986Arguments:
987
988 DeviceObject - a pointer to the device object
989 Irp - a pointer to the I/O request packet
990
991Return Value:
992
993 Status Code
994
995--*/
999 PIRP Irp
1000 )
1001{
1002 PSTORAGE_PROPERTY_QUERY query = Irp->AssociatedIrp.SystemBuffer;
1003 PSTORAGE_DESCRIPTOR_HEADER descHeader;
1005
1007
1008 ULONG outLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
1009
1010 BOOLEAN includeOptionalIds;
1011 BOOLEAN overflow = FALSE;
1012 BOOLEAN infoFound = FALSE;
1013 BOOLEAN useStatus = TRUE; // Use the status directly instead of relying on overflow and infoFound flags.
1014
1015 //
1016 // Must run at less then dispatch.
1017 //
1018
1020
1023 goto FnExit;
1024 }
1025
1026 //
1027 // Check proper query type.
1028 //
1029
1030 if (query->QueryType == PropertyExistsQuery) {
1031 Irp->IoStatus.Information = 0;
1033 goto FnExit;
1034 }
1035
1036 if (query->QueryType != PropertyStandardQuery) {
1038 goto FnExit;
1039 }
1040
1041 //
1042 // Check AdditionalParameters validity.
1043 //
1044
1045 if (query->AdditionalParameters[0] == DUID_INCLUDE_SOFTWARE_IDS) {
1046 includeOptionalIds = TRUE;
1047 } else if (query->AdditionalParameters[0] == DUID_HARDWARE_IDS_ONLY) {
1048 includeOptionalIds = FALSE;
1049 } else {
1051 goto FnExit;
1052 }
1053
1054 //
1055 // Verify output parameters.
1056 //
1057
1058 if (outLength < sizeof(STORAGE_DESCRIPTOR_HEADER)) {
1059
1061 goto FnExit;
1062 }
1063
1064 //
1065 // From this point forward the status depends on the overflow
1066 // and infoFound flags.
1067 //
1068
1069 useStatus = FALSE;
1070
1071 descHeader = Irp->AssociatedIrp.SystemBuffer;
1072 RtlZeroMemory(descHeader, outLength);
1073
1074 descHeader->Version = DUID_VERSION_1;
1075 descHeader->Size = sizeof(STORAGE_DEVICE_UNIQUE_IDENTIFIER);
1076
1077 //
1078 // Try to build device unique id from StorageDeviceIdProperty.
1079 //
1080
1082 Irp);
1083
1085 overflow = TRUE;
1086 }
1087
1088 if (NT_SUCCESS(status)) {
1089 infoFound = TRUE;
1090 }
1091
1092 //
1093 // Try to build device unique id from StorageDeviceProperty.
1094 //
1095
1097 Irp);
1098
1100 overflow = TRUE;
1101 }
1102
1103 if (NT_SUCCESS(status)) {
1104 infoFound = TRUE;
1105 }
1106
1107 //
1108 // The following portion is optional and only included if the
1109 // caller requested software IDs.
1110 //
1111
1112 if (!includeOptionalIds) {
1113 goto FnExit;
1114 }
1115
1116 //
1117 // Try to build device unique id from drive layout signature (disk
1118 // devices only).
1119 //
1120
1122 Irp);
1123
1125 overflow = TRUE;
1126 }
1127
1128 if (NT_SUCCESS(status)) {
1129 infoFound = TRUE;
1130 }
1131
1132FnExit:
1133
1134 if (!useStatus) {
1135
1136 //
1137 // Return overflow, success, or a generic error.
1138 //
1139
1140 if (overflow) {
1141
1142 //
1143 // If output buffer is STORAGE_DESCRIPTOR_HEADER, then return
1144 // success to the user. Otherwise, send an error so the user
1145 // knows a larger buffer is required.
1146 //
1147
1148 if (outLength == sizeof(STORAGE_DESCRIPTOR_HEADER)) {
1150 Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER);
1151 } else {
1153 }
1154
1155 } else if (infoFound) {
1157
1158 //
1159 // Exercise the compare routine. This should always succeed.
1160 //
1161
1162 NT_ASSERT(DuidExactMatch == CompareStorageDuids(Irp->AssociatedIrp.SystemBuffer,
1163 Irp->AssociatedIrp.SystemBuffer));
1164
1165 } else {
1167 }
1168 }
1169
1170 Irp->IoStatus.Status = status;
1171
1174
1175 return status;
1176}
1177
1178/*++////////////////////////////////////////////////////////////////////////////
1179
1180ClasspWriteCacheProperty()
1181
1182Routine Description:
1183
1184 This routine reads the caching mode page from the device to
1185 build the Write Cache property page.
1186
1187Arguments:
1188
1189 DeviceObject - The device object to handle this irp
1190
1191 Irp - The IRP for this request
1192
1193 Srb - SRB allocated by the dispatch routine
1194
1195Return Value:
1196
1197--*/
1198
1201 _In_ PIRP Irp,
1203 )
1204{
1205 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1207 PSTORAGE_PROPERTY_QUERY query = Irp->AssociatedIrp.SystemBuffer;
1209 PMODE_PARAMETER_HEADER modeData = NULL;
1210 PMODE_CACHING_PAGE pageData = NULL;
1213 PCDB cdb;
1214
1215 //
1216 // Must run at less then dispatch.
1217 //
1218
1220
1223 goto WriteCacheExit;
1224 }
1225
1226 //
1227 // Check proper query type.
1228 //
1229
1230 if (query->QueryType == PropertyExistsQuery) {
1232 goto WriteCacheExit;
1233 }
1234
1235 if (query->QueryType != PropertyStandardQuery) {
1237 goto WriteCacheExit;
1238 }
1239
1240 length = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
1241
1242 if (length < sizeof(STORAGE_DESCRIPTOR_HEADER)) {
1244 goto WriteCacheExit;
1245 }
1246
1247 writeCache = (PSTORAGE_WRITE_CACHE_PROPERTY) Irp->AssociatedIrp.SystemBuffer;
1248 RtlZeroMemory(writeCache, length);
1249
1250 //
1251 // Set version and required size.
1252 //
1253
1254 writeCache->Version = sizeof(STORAGE_WRITE_CACHE_PROPERTY);
1255 writeCache->Size = sizeof(STORAGE_WRITE_CACHE_PROPERTY);
1256
1257 if (length < sizeof(STORAGE_WRITE_CACHE_PROPERTY)) {
1260 goto WriteCacheExit;
1261 }
1262
1263 //
1264 // Set known values
1265 //
1266
1267 writeCache->NVCacheEnabled = FALSE;
1268 writeCache->UserDefinedPowerProtection = TEST_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
1269
1270 //
1271 // Check for flush cache support by sending a sync cache command
1272 // to the device.
1273 //
1274
1275 //
1276 // Set timeout value and mark the request as not being a tagged request.
1277 //
1278 SrbSetTimeOutValue(Srb, fdoExtension->TimeOutValue * 4);
1281 SrbAssignSrbFlags(Srb, fdoExtension->SrbFlags);
1282
1283 SrbSetCdbLength(Srb, 10);
1284 cdb = SrbGetCdb(Srb);
1285 cdb->CDB10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
1286
1288 Srb,
1289 NULL,
1290 0,
1291 TRUE);
1292 if (NT_SUCCESS(status)) {
1293 writeCache->FlushCacheSupported = TRUE;
1294 } else {
1295 //
1296 // Device does not support sync cache
1297 //
1298
1299 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "ClasspWriteCacheProperty: Synchronize cache failed with status 0x%X\n", status));
1300 writeCache->FlushCacheSupported = FALSE;
1301 //
1302 // Reset the status if there was any failure
1303 //
1305 }
1306
1307 modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
1310
1311 if (modeData == NULL) {
1312 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "ClasspWriteCacheProperty: Unable to allocate mode data buffer\n"));
1314 goto WriteCacheExit;
1315 }
1316
1318
1320 (PCHAR) modeData,
1323
1324 if (length < sizeof(MODE_PARAMETER_HEADER)) {
1325
1326 //
1327 // Retry the request in case of a check condition.
1328 //
1329
1331 (PCHAR) modeData,
1334
1335 if (length < sizeof(MODE_PARAMETER_HEADER)) {
1336 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, "ClasspWriteCacheProperty: Mode Sense failed\n"));
1338 goto WriteCacheExit;
1339 }
1340 }
1341
1342 //
1343 // If the length is greater than length indicated by the mode data reset
1344 // the data to the mode data.
1345 //
1346
1347 if (length > (ULONG) (modeData->ModeDataLength + 1)) {
1348 length = modeData->ModeDataLength + 1;
1349 }
1350
1351 //
1352 // Look for caching page in the returned mode page data.
1353 //
1354
1355 pageData = ClassFindModePage((PCHAR) modeData,
1356 length,
1358 TRUE);
1359
1360 //
1361 // Check if valid caching page exists.
1362 //
1363
1364 if (pageData == NULL) {
1365
1366 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "ClasspWriteCacheProperty: Unable to find caching mode page.\n"));
1367 //
1368 // Set write cache value as unknown.
1369 //
1370 writeCache->WriteCacheEnabled = WriteCacheEnableUnknown;
1371 writeCache->WriteCacheType = WriteCacheTypeUnknown;
1372 } else {
1373 writeCache->WriteCacheEnabled = pageData->WriteCacheEnable ?
1375
1376 writeCache->WriteCacheType = pageData->WriteCacheEnable ?
1378 }
1379
1380 //
1381 // Check write through support. If the device previously failed a write request
1382 // with FUA bit is set, then CLASS_SPECIAL_FUA_NOT_SUPPORTED will be set,
1383 // which means write through is not support by the device.
1384 //
1385
1388 writeCache->WriteThroughSupported = WriteThroughSupported;
1389 } else {
1390 writeCache->WriteThroughSupported = WriteThroughNotSupported;
1391 }
1392
1393 //
1394 // Get the changeable caching mode page and check write cache is changeable.
1395 //
1396
1398
1400 (PCHAR) modeData,
1404
1405 if (length < sizeof(MODE_PARAMETER_HEADER)) {
1406
1407 //
1408 // Retry the request in case of a check condition.
1409 //
1410
1412 (PCHAR) modeData,
1416
1417 if (length < sizeof(MODE_PARAMETER_HEADER)) {
1418
1419 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "ClasspWriteCacheProperty: Mode Sense failed\n"));
1420
1421 //
1422 // If the device fails to return changeable pages, then
1423 // set the write cache changeable value to unknown.
1424 //
1425
1426 writeCache->WriteCacheChangeable = WriteCacheChangeUnknown;
1428 goto WriteCacheExit;
1429 }
1430 }
1431
1432 //
1433 // If the length is greater than length indicated by the mode data reset
1434 // the data to the mode data.
1435 //
1436
1437 if (length > (ULONG) (modeData->ModeDataLength + 1)) {
1438 length = modeData->ModeDataLength + 1;
1439 }
1440
1441 //
1442 // Look for caching page in the returned mode page data.
1443 //
1444
1445 pageData = ClassFindModePage((PCHAR) modeData,
1446 length,
1448 TRUE);
1449 //
1450 // Check if valid caching page exists.
1451 //
1452
1453 if (pageData == NULL) {
1454 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "ClasspWriteCacheProperty: Unable to find caching mode page.\n"));
1455 //
1456 // Set write cache changeable value to unknown.
1457 //
1458 writeCache->WriteCacheChangeable = WriteCacheChangeUnknown;
1459 } else {
1460 writeCache->WriteCacheChangeable = pageData->WriteCacheEnable ?
1462 }
1463
1465
1466WriteCacheExit:
1467
1468 FREE_POOL(modeData);
1469
1470 //
1471 // Set the size and status in IRP
1472 //
1473 Irp->IoStatus.Information = information;;
1474 Irp->IoStatus.Status = status;
1475
1478
1479 return status;
1480}
1481
1482ULONG
1485 _In_ ULONG BytesPerBlockInBigEndian
1486 )
1487/*++
1488 Convert the big-endian value.
1489 if it's 0, default to the standard 512 bytes.
1490 if it's not a power of 2 value, round down to power of 2.
1491--*/
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}
1515
1519 _In_ PREAD_CAPACITY16_DATA ReadCapacity16Data
1520 )
1521{
1523 USHORT lowestAlignedBlock;
1524 USHORT logicalBlocksPerPhysicalBlock;
1525 PCLASS_READ_CAPACITY16_DATA cachedData = &(FdoExtension->FunctionSupportInfo->ReadCapacity16Data);
1526
1527 // use Logical Sector Size from DiskGeometry to avoid duplicated calculation.
1528 FdoExtension->FunctionSupportInfo->ReadCapacity16Data.BytesPerLogicalSector = ClasspCalculateLogicalSectorSize(FdoExtension->DeviceObject, ReadCapacity16Data->BytesPerBlock);
1529
1530 // FdoExtension->DiskGeometry.BytesPerSector might be 0 for class drivers that don't get READ CAPACITY info yet.
1531 NT_ASSERT( (FdoExtension->DiskGeometry.BytesPerSector == 0) ||
1532 (FdoExtension->DiskGeometry.BytesPerSector == FdoExtension->FunctionSupportInfo->ReadCapacity16Data.BytesPerLogicalSector) );
1533
1534 logicalBlocksPerPhysicalBlock = 1 << ReadCapacity16Data->LogicalPerPhysicalExponent;
1535 lowestAlignedBlock = (ReadCapacity16Data->LowestAlignedBlock_MSB << 8) | ReadCapacity16Data->LowestAlignedBlock_LSB;
1536
1537 if (lowestAlignedBlock > logicalBlocksPerPhysicalBlock) {
1538 // we get garbage data
1540 } else {
1541 // value of lowestAlignedBlock (from T10 spec) needs to be converted.
1542 lowestAlignedBlock = (logicalBlocksPerPhysicalBlock - lowestAlignedBlock) % logicalBlocksPerPhysicalBlock;
1543 }
1544
1545 if (NT_SUCCESS(status)) {
1546 // fill output buffer
1547 cachedData->BytesPerPhysicalSector = cachedData->BytesPerLogicalSector * logicalBlocksPerPhysicalBlock;
1548 cachedData->BytesOffsetForSectorAlignment = cachedData->BytesPerLogicalSector * lowestAlignedBlock;
1549
1550 //
1551 // Fill in the Logical Block Provisioning info. Note that we do not
1552 // use these fields; we use the Provisioning Type and LBPRZ fields from
1553 // the Logical Block Provisioning VPD page (0xB2).
1554 //
1555 cachedData->LBProvisioningEnabled = ReadCapacity16Data->LBPME;
1556 cachedData->LBProvisioningReadZeros = ReadCapacity16Data->LBPRZ;
1557
1558 TracePrint((TRACE_LEVEL_INFORMATION,
1559 TRACE_FLAG_INIT,
1560 "InterpretReadCapacity16Data: Device\'s LBP enabled = %d\n",
1561 cachedData->LBProvisioningEnabled));
1562 }
1563
1564 return status;
1565}
1566
1571 )
1572/*
1573 This routine may send down a READ CAPACITY 16 command to retrieve info.
1574 The info will be cached in FdoExtension->LowerLayerSupport->AccessAlignment.
1575
1576 After info retrieving finished, this function sets following field:
1577 FdoExtension->LowerLayerSupport->AccessAlignment.LowerLayerSupported = Supported;
1578 to indicate that info has been cached.
1579
1580 NOTE: some future processes may use this function to send the command anyway, it will be caller's decision
1581 on checking 'AccessAlignment.LowerLayerSupported' in case the cached info is good enough.
1582*/
1583{
1587 ULONG allocationBufferLength = bufferLength; //DMA buffer size for alignment
1588 PCDB cdb;
1589 ULONG dataTransferLength = 0;
1590
1591 //
1592 // If the information retrieval has already been attempted, return the cached status.
1593 //
1594 if (FdoExtension->FunctionSupportInfo->ReadCapacity16Data.CommandStatus != -1) {
1595 // get cached NTSTATUS from previous call.
1596 return FdoExtension->FunctionSupportInfo->ReadCapacity16Data.CommandStatus;
1597 }
1598
1600 FdoExtension->FunctionSupportInfo->ReadCapacity16Data.CommandStatus = STATUS_NOT_IMPLEMENTED;
1602 }
1603
1604#if defined(_ARM_) || defined(_ARM64_)
1605 //
1606 // ARM has specific alignment requirements, although this will not have a functional impact on x86 or amd64
1607 // based platforms. We are taking the conservative approach here.
1608 //
1609 allocationBufferLength = ALIGN_UP_BY(allocationBufferLength,KeGetRecommendedSharedDataAlignment());
1610 dataBuffer = (PREAD_CAPACITY16_DATA)ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned, allocationBufferLength, '4CcS');
1611#else
1613#endif
1614
1615 if (dataBuffer == NULL) {
1616 // return without updating FdoExtension->FunctionSupportInfo->ReadCapacity16Data.CommandStatus
1617 // the field will remain value as "-1", so that the command will be attempted next time this function is called.
1619 }
1620
1621 RtlZeroMemory(dataBuffer, allocationBufferLength);
1622
1623 //
1624 // Initialize the SRB.
1625 //
1626 if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1630 1,
1632 if (NT_SUCCESS(status)) {
1634 } else {
1635 //
1636 // Should not occur.
1637 //
1639 }
1640 } else {
1642 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
1644 }
1645
1646 //prepare the Srb
1647 if (NT_SUCCESS(status))
1648 {
1649
1650 SrbSetTimeOutValue(Srb, FdoExtension->TimeOutValue);
1654
1655 SrbSetCdbLength(Srb, 16);
1656
1657 cdb = SrbGetCdb(Srb);
1658 cdb->READ_CAPACITY16.OperationCode = SCSIOP_READ_CAPACITY16;
1660 cdb->READ_CAPACITY16.AllocationLength[3] = bufferLength;
1661
1663 Srb,
1664 dataBuffer,
1665 allocationBufferLength,
1666 FALSE);
1667
1668 dataTransferLength = SrbGetDataTransferLength(Srb);
1669 }
1670
1671 if (NT_SUCCESS(status) && (dataTransferLength < 16))
1672 {
1673 // the device should return at least 16 bytes of data for this command.
1675 }
1676
1677 //
1678 // Handle the case where we get back STATUS_DATA_OVERRUN b/c the input
1679 // buffer was larger than necessary.
1680 //
1681 if (status == STATUS_DATA_OVERRUN && dataTransferLength < bufferLength)
1682 {
1684 }
1685
1686 if (NT_SUCCESS(status))
1687 {
1688 // cache data into FdoExtension
1690 }
1691
1692 // cache the status indicates that this funciton has been called.
1693 FdoExtension->FunctionSupportInfo->ReadCapacity16Data.CommandStatus = status;
1694
1696
1697 return status;
1698}
1699
1702 _In_ PIRP Irp,
1704 )
1705/*
1706 At first time of receiving the request, this function will forward it to lower stack to determine if it's supportted.
1707 If it's not supported, SCSIOP_READ_CAPACITY16 will be sent down to retrieve the information.
1708*/
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}
1885
1886static
1889 _In_ USHORT MediumRotationRate,
1891 )
1892{
1894
1895 if (MediumRotationRate == 0x0001) {
1896 // Non-rotating media (e.g., solid state device)
1899 } else if ( (MediumRotationRate >= 0x401) &&
1900 (MediumRotationRate <= 0xFFFE) ) {
1901 // Nominal media rotation rate in rotations per minute (rpm)
1904 } else {
1905 // Unknown cases:
1906 // 0 - Rate not reported
1907 // 0002h-0400h - Reserved
1908 // FFFFh - Reserved
1910 }
1911
1912 return status;
1913}
1914
1915
1921 )
1922/*++
1923
1924Routine Description:
1925
1926 This routine returns the medium product type reported by the device for the associated LU.
1927
1928 This function must be called at IRQL < DISPATCH_LEVEL.
1929
1930Arguments:
1931
1932 DeviceObject - Supplies the device object associated with this request
1933 Irp - The IRP to be processed
1934 Srb - The SRB associated with the request
1935
1936Return Value:
1937
1938 NTSTATUS code
1939
1940--*/
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}
2071
2075 )
2076/*
2077Routine Description:
2078
2079 This function sends an INQUIRY command request for VPD_BLOCK_DEVICE_CHARACTERISTICS to
2080 the device. Relevant data from the response is cached in the FDO extension.
2081
2082Arguments:
2083 FdoExtension: The FDO extension of the device to which the INQUIRY command will be sent.
2084 Srb: Allocated by the caller.
2085 SrbSize: The size of the Srb buffer in bytes.
2086
2087Return Value:
2088
2089 STATUS_INVALID_PARAMETER: May be returned if the LogPage buffer is NULL or
2090 not large enough.
2091 STATUS_SUCCESS: The log page was obtained and placed in the LogPage buffer.
2092
2093 This function may return other NTSTATUS codes from internal function calls.
2094--*/
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}
2171
2174 _In_ PIRP Irp,
2176 )
2177/*
2178 At first time of receiving the request, this function will forward it to lower stack to determine if it's supportted.
2179 If it's not supported, INQUIRY (Block Device Characteristics VPD page) will be sent down to retrieve the information.
2180*/
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}
2349
2353 )
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}
2519
2520
2524 _In_ ULONG SrbSize,
2525 _Out_ PCLASS_VPD_B0_DATA BlockLimitsData
2526 )
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}
2728
2729
2732 _In_ PIRP Irp,
2734 )
2735/*
2736 At first time of receiving the request, this function will forward it to lower stack to determine if it's supportted.
2737 If it's not supported, INQUIRY (Block Limits VPD page) will be sent down to retrieve the information.
2738*/
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
2777 //
2778 // Request validation.
2779 // Note that InputBufferLength and IsFdo have been validated beforing entering this routine.
2780 //
2781
2785 goto Exit;
2786 }
2787
2788 // do not touch this buffer because it can still be used as input buffer for lower layer in 'SupportUnknown' case.
2789 trimDescr = (PDEVICE_TRIM_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
2790
2791 length = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
2792
2793 if (length < sizeof(DEVICE_TRIM_DESCRIPTOR)) {
2794
2795 if (length >= sizeof(STORAGE_DESCRIPTOR_HEADER)) {
2796
2798 trimDescr->Version = sizeof(DEVICE_TRIM_DESCRIPTOR);
2799 trimDescr->Size = sizeof(DEVICE_TRIM_DESCRIPTOR);
2801 goto Exit;
2802 }
2803
2805 goto Exit;
2806 }
2807
2808 //
2809 // note that 'Supported' case has been handled at the beginning of this function.
2810 //
2811 switch (fdoExtension->FunctionSupportInfo->LowerLayerSupport.TrimProperty) {
2812 case SupportUnknown: {
2813 // send down request and wait for the request to complete.
2814 status = ClassForwardIrpSynchronous(commonExtension, Irp);
2815
2816 if ( (status == STATUS_NOT_SUPPORTED) ||
2820 // case 1: the request is not supported by lower layer, sends down command
2821 // some port drivers (or filter drivers) return STATUS_INVALID_DEVICE_REQUEST if a request is not supported.
2822 status = fdoExtension->FunctionSupportInfo->LBProvisioningData.CommandStatus;
2823 NT_ASSERT(status != -1);
2824
2825 // data is ready in fdoExtension
2826 // set the support status after the SCSI command is executed to avoid racing condition between multiple same type of requests.
2827 fdoExtension->FunctionSupportInfo->LowerLayerSupport.TrimProperty = NotSupported;
2828
2829 if (NT_SUCCESS(status)) {
2830 // fill output buffer
2831 RtlZeroMemory(trimDescr, length);
2832 trimDescr->Version = sizeof(DEVICE_TRIM_DESCRIPTOR);
2833 trimDescr->Size = sizeof(DEVICE_TRIM_DESCRIPTOR);
2834 trimDescr->TrimEnabled = ClasspSupportsUnmap(fdoExtension->FunctionSupportInfo);
2835
2836 // set returned data length
2838 } else {
2839 // there was error retrieving TrimProperty. Surface the error up from 'status' variable.
2840 information = 0;
2841 }
2842 goto Exit;
2843 } else {
2844 // case 2: the request is supported and it completes successfully
2845 // case 3: the request is supported by lower stack but other failure status is returned.
2846 // from now on, the same request will be send down to lower stack directly.
2847 fdoExtension->FunctionSupportInfo->LowerLayerSupport.TrimProperty = Supported;
2848 information = (ULONG)Irp->IoStatus.Information;
2849 goto Exit;
2850 }
2851 break;
2852 }
2853
2854 case NotSupported: {
2855 status = fdoExtension->FunctionSupportInfo->LBProvisioningData.CommandStatus;
2856 NT_ASSERT(status != -1);
2857
2858 if (NT_SUCCESS(status)) {
2859 RtlZeroMemory(trimDescr, length);
2860 trimDescr->Version = sizeof(DEVICE_TRIM_DESCRIPTOR);
2861 trimDescr->Size = sizeof(DEVICE_TRIM_DESCRIPTOR);
2862 trimDescr->TrimEnabled = ClasspSupportsUnmap(fdoExtension->FunctionSupportInfo);
2863
2865 } else {
2866 information = 0;
2867 }
2868 goto Exit;
2869
2870 break;
2871 }
2872
2873 case Supported: {
2874 NT_ASSERT(FALSE); // this case is handled at the begining of the function.
2875 break;
2876 }
2877
2878 } // end of switch (fdoExtension->FunctionSupportInfo->LowerLayerSupport.TrimProperty)
2879
2880Exit:
2881
2882 //
2883 // Set the size and status in IRP
2884 //
2885 Irp->IoStatus.Information = information;
2886 Irp->IoStatus.Status = status;
2887
2890
2891 return status;
2892}
2893
2898 )
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}
3044
3045
3046VOID
3051 _In_ ULONG MaxBlockDescrIndex,
3055 )
3056/*++
3057
3058Routine Description:
3059
3060 Convert DEVICE_DATA_SET_RANGE entry to be UNMAP_BLOCK_DESCRIPTOR entries.
3061
3062 As LengthInBytes field in DEVICE_DATA_SET_RANGE structure is 64 bits (bytes)
3063 and LbaCount field in UNMAP_BLOCK_DESCRIPTOR structure is 32 bits (sectors),
3064 it's possible that one DEVICE_DATA_SET_RANGE entry needs multiple UNMAP_BLOCK_DESCRIPTOR entries.
3065 We must also take the unmap granularity into consideration and split up the
3066 the given ranges so that they are aligned with the specified granularity.
3067
3068Arguments:
3069 All arguments must be validated by the caller.
3070
3071 FdoExtension - The FDO extension of the device to which the unmap
3072 command that will use the resulting unmap block descriptors will be
3073 sent.
3074 BlockDescr - Pointer to a buffer that will contain the unmap block
3075 descriptors. This buffer should be allocated by the caller and the
3076 caller should also ensure that it is large enough to contain all the
3077 requested descriptors. Its size is implied by MaxBlockDescrIndex.
3078 CurrentBlockDescrIndex - This contains the next block descriptor index to
3079 be processed when this function returns. This function should be called
3080 again with the same parameter to continue processing.
3081 MaxBlockDescrIndex - This is the index of the last unmap block descriptor,
3082 provided so that the function does not go off the end of BlockDescr.
3083 CurrentLbaCount - This contains the number of LBAs left to be processed
3084 when this function returns. This function should be called again with
3085 the same parameter to continue processing.
3086 MaxLbaCount - This is the max number of LBAs that can be sent in a single
3087 unmap command.
3088 DataSetRange - This range will be modified to reflect the un-converted part.
3089 It must be valid (including being granularity-aligned) when it is first
3090 passed to this function.
3091
3092Return Value:
3093
3094 Count of UNMAP_BLOCK_DESCRIPTOR entries converted.
3095
3096 NOTE: if LengthInBytes does not reach to 0, the conversion for DEVICE_DATA_SET_RANGE entry
3097 is not completed. Further conversion is needed by calling this function again.
3098
3099--*/
3100{
3101
3102 ULONGLONG startingSector;
3104
3105 TracePrint((TRACE_LEVEL_INFORMATION,
3106 TRACE_FLAG_IOCTL,
3107 "ConvertDataSetRangeToUnmapBlockDescr (%p): Generating UNMAP Block Descriptors from DataSetRange: \
3108 \n\t\tStartingOffset = %I64u bytes \
3109 \n\t\tLength = %I64u bytes\n",
3110 FdoExtension->DeviceObject,
3111 DataSetRange->StartingOffset,
3112 DataSetRange->LengthInBytes));
3113
3114 while ( (DataSetRange->LengthInBytes > 0) &&
3115 (*CurrentBlockDescrIndex < MaxBlockDescrIndex) &&
3117
3118 //
3119 // Convert the starting offset and length from bytes to blocks.
3120 //
3121 startingSector = (ULONGLONG)(DataSetRange->StartingOffset / FdoExtension->DiskGeometry.BytesPerSector);
3122 sectorCount = (DataSetRange->LengthInBytes / FdoExtension->DiskGeometry.BytesPerSector);
3123
3124 //
3125 // Make sure the sector count isn't more than can be specified with a
3126 // single descriptor.
3127 //
3128 if (sectorCount > MAXULONG) {
3130 }
3131
3132 //
3133 // The max LBA count is the max number of LBAs that can be unmapped with
3134 // a single UNMAP command. Make sure we don't exceed this value.
3135 //
3138 }
3139
3140 REVERSE_BYTES_QUAD(BlockDescr[*CurrentBlockDescrIndex].StartingLba, &startingSector);
3142
3143 DataSetRange->StartingOffset += sectorCount * FdoExtension->DiskGeometry.BytesPerSector;
3144 DataSetRange->LengthInBytes -= sectorCount * FdoExtension->DiskGeometry.BytesPerSector;
3145
3148
3149 TracePrint((TRACE_LEVEL_INFORMATION,
3150 TRACE_FLAG_IOCTL,
3151 "ConvertDataSetRangeToUnmapBlockDescr (%p): Generated UNMAP Block Descriptor: \
3152 \n\t\t\tStartingLBA = %I64u \
3153 \n\t\t\tLBACount = %I64u\n",
3154 FdoExtension->DeviceObject,
3155 startingSector,
3156 sectorCount));
3157 }
3158
3159 return;
3160}
3161
3162
3166 _In_ PDEVICE_DATA_SET_RANGE DataSetRanges,
3167 _In_ ULONG DataSetRangesCount,
3168 _In_ ULONG UnmapGranularity,
3169 _In_ ULONG SrbFlags,
3170 _In_ PIRP Irp,
3173)
3174/*++
3175
3176Routine Description:
3177
3178 Process TRIM request that received from upper layer.
3179
3180Arguments:
3181
3182 FdoExtension
3183 DataSetRanges - this parameter must be already validated in caller.
3184 DataSetRangesCount - this parameter must be already validated in caller.
3185 UnmapGranularity - The unmap granularity in blocks. This is used to split
3186 up the unmap command into chunks that are granularity-aligned.
3187 Srb - The SRB to use for the unmap command. The caller must allocate it,
3188 but this function will take care of initialzing it.
3189
3190Return Value:
3191
3192 status of the operation
3193
3194--*/
3195{
3197
3199 PUNMAP_BLOCK_DESCRIPTOR blockDescrPointer;
3201 ULONG maxBlockDescrCount;
3202 ULONG neededBlockDescrCount;
3203 ULONG i;
3204
3205 BOOLEAN allDataSetRangeFullyConverted;
3206 BOOLEAN needToSendCommand;
3207 BOOLEAN tempDataSetRangeFullyConverted;
3208
3209 ULONG dataSetRangeIndex;
3210 DEVICE_DATA_SET_RANGE tempDataSetRange;
3211
3212 ULONG blockDescrIndex;
3213 ULONGLONG lbaCount;
3214 ULONGLONG maxLbaCount;
3215 ULONGLONG maxParameterListLength;
3216
3217
3218 UNREFERENCED_PARAMETER(UnmapGranularity);
3221
3222 //
3223 // The given LBA ranges are in DEVICE_DATA_SET_RANGE format and need to be converted into UNMAP Block Descriptors.
3224 // The UNMAP command is able to carry 0xFFFF bytes (0xFFF8 in reality as there are 8 bytes of header plus n*16 bytes of Block Descriptors) of data.
3225 // The actual size will also be constrained by the Maximum LBA Count and Maximum Transfer Length.
3226 //
3227
3228 //
3229 // 1.1 Calculate how many Block Descriptors are needed to complete this request.
3230 //
3231 neededBlockDescrCount = 0;
3232 for (i = 0; i < DataSetRangesCount; i++) {
3233 lbaCount = DataSetRanges[i].LengthInBytes / FdoExtension->DiskGeometry.BytesPerSector;
3234
3235 //
3236 // 1.1.1 the UNMAP_BLOCK_DESCRIPTOR LbaCount is 32 bits, the max value is 0xFFFFFFFF
3237 //
3238 if (lbaCount > 0) {
3239 neededBlockDescrCount += (ULONG)((lbaCount - 1) / MAXULONG + 1);
3240 }
3241 }
3242
3243 //
3244 // Honor Max Unmap Block Descriptor Count if it has been specified. Otherwise,
3245 // use the maximum value that the Parameter List Length field will allow (0xFFFF).
3246 // If the count is 0xFFFFFFFF, then no maximum is specified.
3247 //
3248 if (FdoExtension->FunctionSupportInfo->BlockLimitsData.MaxUnmapBlockDescrCount != 0 &&
3249 FdoExtension->FunctionSupportInfo->BlockLimitsData.MaxUnmapBlockDescrCount != MAXULONG)
3250 {
3251 maxParameterListLength = (ULONGLONG)(FdoExtension->FunctionSupportInfo->BlockLimitsData.MaxUnmapBlockDescrCount * sizeof(UNMAP_BLOCK_DESCRIPTOR))
3252 + sizeof(UNMAP_LIST_HEADER);
3253
3254 //
3255 // In the SBC-3, the Max Unmap Block Descriptor Count field in the 0xB0
3256 // page is 4 bytes and the Parameter List Length in the UNMAP command is
3257 // 2 bytes, therefore it is possible that the Max Unmap Block Descriptor
3258 // Count could imply more bytes than can be specified in the Parameter
3259 // List Length field. Adjust for that here.
3260 //
3261 maxParameterListLength = min(maxParameterListLength, MAXUSHORT);
3262 }
3263 else
3264 {
3265 maxParameterListLength = MAXUSHORT;
3266 }
3267
3268 //
3269 // 1.2 Calculate the buffer size needed, capped by the device's limitations.
3270 //
3271 bufferLength = min(FdoExtension->PrivateFdoData->HwMaxXferLen, (ULONG)maxParameterListLength);
3272 bufferLength = min(bufferLength, (neededBlockDescrCount * sizeof(UNMAP_BLOCK_DESCRIPTOR) + sizeof(UNMAP_LIST_HEADER)));
3273
3274 maxBlockDescrCount = (bufferLength - sizeof(UNMAP_LIST_HEADER)) / sizeof(UNMAP_BLOCK_DESCRIPTOR);
3275
3276 if (maxBlockDescrCount == 0) {
3277 //
3278 // This shouldn't happen since we've already done validation.
3279 //
3280 TracePrint((TRACE_LEVEL_INFORMATION,
3281 TRACE_FLAG_IOCTL,
3282 "DeviceProcessDsmTrimRequest (%p): Max Block Descriptor count is Zero\n",
3283 FdoExtension->DeviceObject));
3284
3285 NT_ASSERT(maxBlockDescrCount != 0);
3287 goto Exit;
3288 }
3289
3290 //
3291 // The Maximum LBA Count is set during device initialization.
3292 //
3293 maxLbaCount = (ULONGLONG)FdoExtension->FunctionSupportInfo->BlockLimitsData.MaxUnmapLbaCount;
3294 if (maxLbaCount == 0) {
3295 //
3296 // This shouldn't happen since we've already done validation.
3297 //
3298 TracePrint((TRACE_LEVEL_INFORMATION,
3299 TRACE_FLAG_IOCTL,
3300 "DeviceProcessDsmTrimRequest (%p): Max LBA count is Zero\n",
3301 FdoExtension->DeviceObject));
3302
3303 NT_ASSERT(maxLbaCount != 0);
3305 goto Exit;
3306 }
3307
3308 //
3309 // Finally, allocate the buffer we'll use to send the UNMAP command.
3310 //
3311
3312#if defined(_ARM_) || defined(_ARM64_)
3313 //
3314 // ARM has specific alignment requirements, although this will not have a functional impact on x86 or amd64
3315 // based platforms. We are taking the conservative approach here.
3316 //
3319#else
3321#endif
3322
3323 if (buffer == NULL) {
3325 goto Exit;
3326 }
3327
3329
3330 blockDescrPointer = &buffer->Descriptors[0];
3331
3332 allDataSetRangeFullyConverted = FALSE;
3333 needToSendCommand = FALSE;
3334 tempDataSetRangeFullyConverted = TRUE;
3335 dataSetRangeIndex = 0;
3336 RtlZeroMemory(&tempDataSetRange, sizeof(tempDataSetRange));
3337
3338 blockDescrIndex = 0;
3339 lbaCount = 0;
3340
3341
3342 while (!allDataSetRangeFullyConverted) {
3343
3344 //
3345 // If the previous entry conversion completed, go on to the next one;
3346 // otherwise, continue processing the current entry.
3347 //
3348 if (tempDataSetRangeFullyConverted) {
3349 tempDataSetRange.StartingOffset = DataSetRanges[dataSetRangeIndex].StartingOffset;
3350 tempDataSetRange.LengthInBytes = DataSetRanges[dataSetRangeIndex].LengthInBytes;
3351 dataSetRangeIndex++;
3352 }
3353
3355 blockDescrPointer,
3356 &blockDescrIndex,
3357 maxBlockDescrCount,
3358 &lbaCount,
3359 maxLbaCount,
3360 &tempDataSetRange
3361 );
3362
3363 tempDataSetRangeFullyConverted = (tempDataSetRange.LengthInBytes == 0) ? TRUE : FALSE;
3364
3365 allDataSetRangeFullyConverted = tempDataSetRangeFullyConverted && (dataSetRangeIndex == DataSetRangesCount);
3366
3367 //
3368 // Send the UNMAP command when the buffer is full or when all input entries are converted.
3369 //
3370 if ((blockDescrIndex == maxBlockDescrCount) || // Buffer full or block descriptor count reached
3371 (lbaCount == maxLbaCount) || // Block LBA count reached
3372 allDataSetRangeFullyConverted) { // All DataSetRanges have been converted
3373
3374 USHORT transferSize;
3375 USHORT tempSize;
3376 PCDB cdb;
3377
3378 //
3379 // Get the transfer size, including the header.
3380 //
3381 transferSize = (USHORT)(blockDescrIndex * sizeof(UNMAP_BLOCK_DESCRIPTOR) + sizeof(UNMAP_LIST_HEADER));
3382 if (transferSize > bufferLength)
3383 {
3384 //
3385 // This should never happen.
3386 //
3387 NT_ASSERT(transferSize <= bufferLength);
3389 break;
3390 }
3391
3392 tempSize = transferSize - (USHORT)FIELD_OFFSET(UNMAP_LIST_HEADER, BlockDescrDataLength);
3393 REVERSE_BYTES_SHORT(buffer->DataLength, &tempSize);
3394 tempSize = transferSize - (USHORT)FIELD_OFFSET(UNMAP_LIST_HEADER, Descriptors[0]);
3395 REVERSE_BYTES_SHORT(buffer->BlockDescrDataLength, &tempSize);
3396
3397 //
3398 // Initialize the SRB.
3399 //
3400 if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
3404 1,
3406 if (NT_SUCCESS(status)) {
3408 } else {
3409 //
3410 // Should not occur.
3411 //
3413 break;
3414 }
3415
3416 } else {
3418 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
3420 }
3421
3422 //
3423 // Prepare the Srb
3424 //
3425 SrbSetTimeOutValue(Srb, FdoExtension->TimeOutValue);
3428
3429 //
3430 // Set the SrbFlags to indicate that it's a data-out operation.
3431 // Also set any passed-in SrbFlags.
3432 //
3436 SrbSetSrbFlags(Srb, SrbFlags);
3437
3438 SrbSetCdbLength(Srb, 10);
3439
3440 cdb = SrbGetCdb(Srb);
3441 cdb->UNMAP.OperationCode = SCSIOP_UNMAP;
3442 cdb->UNMAP.Anchor = 0;
3443 cdb->UNMAP.GroupNumber = 0;
3444 cdb->UNMAP.AllocationLength[0] = (UCHAR)(transferSize >> 8);
3445 cdb->UNMAP.AllocationLength[1] = (UCHAR)transferSize;
3446
3448 Srb,
3449 buffer,
3450 transferSize,
3451 TRUE);
3452
3453 TracePrint((TRACE_LEVEL_INFORMATION,
3454 TRACE_FLAG_IOCTL,
3455 "DeviceProcessDsmTrimRequest (%p): UNMAP command issued. Returned NTSTATUS: %!STATUS!.\n",
3456 FdoExtension->DeviceObject,
3457 status
3458 ));
3459
3460 //
3461 // Clear the buffer so we can re-use it.
3462 //
3463 blockDescrIndex = 0;
3464 lbaCount = 0;
3466 }
3467 }
3468
3469Exit:
3470
3472
3473 return status;
3474}
3475
3478 _In_ PIRP Irp,
3481 )
3482/*
3483 This function is to process IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES with DeviceDsmAction_Trim.
3484 At first time of receiving the request, this function will forward it to lower stack to determine if it's supportted.
3485 If it's not supported, UNMAP (with anchor attribute set) will be sent down to process the request.
3486*/
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}
3770
3775 _In_ ULONGLONG StartingLBA,
3776 _Inout_ PLBA_STATUS_LIST_HEADER LBAStatusHeader,
3777 _In_ ULONG LBAStatusSize,
3778 _In_ BOOLEAN ConsolidateableBlocksOnly
3779 )
3780/*++
3781
3782Routine Description:
3783
3784 Send down a Get LBA Status command for the given range.
3785
3786Arguments:
3787 FdoExtension: The FDO extension of the device to which Get LBA Status will
3788 be sent.
3789 Srb: This should be allocated and initialized before it's passed in. It
3790 will be used for the Get LBA Status command.
3791 StartingLBA: The LBA that is at the beginning of the requested range.
3792 LBAStatusHeader: Caller-allocated output buffer.
3793 LBASTatusSize: Size of the caller-allocated output buffer.
3794
3795Return Value:
3796
3797 Status of the operation.
3798
3799--*/
3800{
3802 PCDB cdb;
3803
3804 if (LBAStatusHeader == NULL || LBAStatusSize == 0)
3805 {
3807 }
3808
3809 //
3810 // Build and send down the Get LBA Status command.
3811 //
3812 SrbSetTimeOutValue(Srb, FdoExtension->TimeOutValue);
3816 SrbSetCdbLength(Srb, sizeof(cdb->GET_LBA_STATUS));
3817
3818
3819 cdb = SrbGetCdb(Srb);
3820 cdb->GET_LBA_STATUS.OperationCode = SCSIOP_GET_LBA_STATUS;
3821 cdb->GET_LBA_STATUS.ServiceAction = SERVICE_ACTION_GET_LBA_STATUS;
3822 REVERSE_BYTES_QUAD(&(cdb->GET_LBA_STATUS.StartingLBA), &StartingLBA);
3823 REVERSE_BYTES(&(cdb->GET_LBA_STATUS.AllocationLength), &LBAStatusSize);
3824
3825 TracePrint((TRACE_LEVEL_INFORMATION,
3826 TRACE_FLAG_IOCTL,
3827 "GetLBAStatus (%p): sending command with StartingLBA = 0x%I64x, AllocationLength = 0x%I64x, ConsolidateableBlocksOnly = %u\n",
3828 FdoExtension->DeviceObject,
3829 StartingLBA,
3830 LBAStatusSize,
3831 ConsolidateableBlocksOnly));
3832
3834 Srb,
3835 LBAStatusHeader,
3836 LBAStatusSize,
3837 FALSE);
3838
3839 //
3840 // Handle the case where we get back STATUS_DATA_OVERRUN b/c the input
3841 // buffer was larger than necessary.
3842 //
3843 if (status == STATUS_DATA_OVERRUN &&
3844 SrbGetDataTransferLength(Srb) < LBAStatusSize)
3845 {
3847 }
3848
3849 // log command.
3850 TracePrint((TRACE_LEVEL_INFORMATION,
3851 TRACE_FLAG_IOCTL,
3852 "GetLBAStatus (%p): command returned NT Status: %!STATUS!\n",
3853 FdoExtension->DeviceObject,
3854 status
3855 ));
3856
3857 return status;
3858}
3859
3860
3865 )
3866/*
3867Routine Description:
3868
3869 This function is to process IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES with DeviceDsmAction_Allocation.
3870
3871 1. This function will only handle the first dataset range.
3872 2. This function will not handle dataset ranges whose LengthInBytes is greater than:
3873 ((MAXULONG - sizeof(LBA_STATUS_LIST_HEADER)) / sizeof(LBA_STATUS_DESCRIPTOR)) * BytesPerSlab
3874
3875 The input buffer should consist of a DEVICE_MANAGE_DATA_SET_ATTRIBUTES followed
3876 in memory by a single DEVICE_DATA_SET_RANGE that specifies the requested range
3877 of slabs for which mapping status is desired.
3878
3879 The output buffer will consist of a DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT
3880 followed in memory by a single DEVICE_DATA_SET_LB_PROVISIONING_STATE that
3881 contains a bitmap that represents the mapped status of the slabs in the requested
3882 range. Note that the number of slabs returned may be less than the number
3883 requested.
3884
3885 Thus function will automatically re-align the given range offset if it was
3886 not slab-aligned. The delta between the given range offset and the properly
3887 aligned offset will be given in returned DEVICE_DATA_SET_LB_PROVISIONING_STATE.
3888
3889Arguments:
3890 DeviceObject: The FDO of the device to which Get LBA Status will be sent.
3891 Irp: The IRP for the request. This function will read the input buffer and
3892 write to the output buffer at the current IRP stack location.
3893 Srb: This should be allocated and initialized before it's passed in. It
3894 will be used for the Get LBA Status command.
3895
3896Return Value:
3897
3898 STATUS_INVALID_PARAMETER: May be returned under the following conditions:
3899 - If the requested range was too large. The caller should try again with a
3900 smaller range. See above for how to calculate the maximum range.
3901 - If the given starting offset was not within the valid range of the device.
3902 STATUS_NOT_SUPPORTED: The storage did not report some information critical to
3903 the execution of this function (e.g. Optimal Unmap Granularity).
3904 STATUS_BUFFER_TOO_SMALL: The output buffer is not large enough to hold the max
3905 data that could be returned from this function. If the output buffer is
3906 at least the size of a ULONG, we will write the required output buffer size
3907 to the first ULONG bytes of the output buffer.
3908 STATUS_UNSUCCESSFUL: The Get LBA Status command succeeded but did not
3909 return data as expected.
3910--*/
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}
4077
4081 _In_ PCLASS_VPD_B0_DATA BlockLimitsData,
4083 _In_ ULONGLONG LengthInBytes,
4085 _Inout_ PULONG DsmOutputLength,
4087 _In_ BOOLEAN ConsolidateableBlocksOnly,
4088 _In_ ULONG OutputVersion,
4089 _Out_ PBOOLEAN BlockLimitsDataMayHaveChanged
4090 )
4091/*
4092Routine Description:
4093
4094 This function is to process IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES with DeviceDsmAction_Allocation.
4095
4096 1. This function will only handle the first dataset range.
4097 2. This function will not handle dataset ranges whose LengthInBytes is greater than:
4098 ((MAXULONG - sizeof(LBA_STATUS_LIST_HEADER)) / sizeof(LBA_STATUS_DESCRIPTOR)) * BytesPerSlab
4099
4100 The input buffer should consist of a DEVICE_MANAGE_DATA_SET_ATTRIBUTES followed
4101 in memory by a single DEVICE_DATA_SET_RANGE that specifies the requested range
4102 of slabs for which mapping status is desired.
4103
4104 The output buffer will consist of a DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT
4105 followed in memory by a single DEVICE_DATA_SET_LB_PROVISIONING_STATE that
4106 contains a bitmap that represents the mapped status of the slabs in the requested
4107 range. Note that the number of slabs returned may be less than the number
4108 requested.
4109
4110 Thus function will automatically re-align the given range offset if it was
4111 not slab-aligned. The delta between the given range offset and the properly
4112 aligned offset will be given in returned DEVICE_DATA_SET_LB_PROVISIONING_STATE.
4113
4114Arguments:
4115 DeviceObject: The FDO of the device to which Get LBA Status will be sent.
4116 BlockLimitsData: Block limits data of the device
4117 StartingOffset: Starting byte offset of byte range to query LBA status (must be sector aligned)
4118 LengthInBytes: Length of byte range to query LBA status (multiple of sector size)
4119 DsmOutput: Output data buffer
4120 DsmOutputLength: output data buffer size. It will be updated with actual bytes used.
4121 Srb: This should be allocated and initialized before it's passed in. It
4122 will be used for the Get LBA Status command.
4123 ConsolidateableBlocksOnly: Only blocks that are eligible for consolidation
4124 should be returned.
4125 OutputVersion: The version of the DEVICE_DATA_SET_LB_PROVISIONING_STATE
4126 structure to return. This should be one of:
4127 - DEVICE_DATA_SET_LB_PROVISIONING_STATE_VERSION_V1
4128 - DEVICE_DATA_SET_LB_PROVISIONING_STATE_VERSION_V2
4129 BlockLimitsDataMayHaveChanged: if this function fails, this flag indicates
4130 if the failure can be caused by changes in device's block limit data.
4131
4132Return Value:
4133
4134 STATUS_INVALID_PARAMETER: May be returned under the following conditions:
4135 - If the requested range was too large. The caller should try again with a
4136 smaller range. See above for how to calculate the maximum range.
4137 - If the given starting offset was not within the valid range of the device.
4138 STATUS_NOT_SUPPORTED: The storage did not report some information critical to
4139 the execution of this function (e.g. Optimal Unmap Granularity).
4140 STATUS_BUFFER_TOO_SMALL: The output buffer is not large enough to hold the max
4141 data that could be returned from this function. If the output buffer is
4142 at least the size of a ULONG, we will write the required output buffer size
4143 to the first ULONG bytes of the output buffer.
4144 STATUS_DEVICE_DATA_ERROR: The Get LBA Status command succeeded but did not
4145 return data as expected.
4146--*/
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}
4678
4682 _In_ ULONG LogPageSize,
4684 )
4685/*
4686Routine Description:
4687
4688 This function sends a LOG SENSE command to the given device and returns the
4689 Logical Block Provisioning Log Page, if available.
4690
4691Arguments:
4692 DeviceObject: The FDO of the device to which the Log Sense command will be sent.
4693 Srb: This should be allocated before it is passed in, but it does not have
4694 to be initialized. This function will initialize it.
4695 LogPageSize: The size of the LogPage buffer in bytes.
4696 LogPage: A pointer to an already allocated output buffer that may contain
4697 the LBP log page when this function returns.
4698
4699Return Value:
4700
4701 STATUS_INVALID_PARAMETER: May be returned if the LogPage buffer is NULL or
4702 not large enough.
4703 STATUS_SUCCESS: The log page was obtained and placed in the LogPage buffer.
4704
4705 This function may return other NTSTATUS codes from internal function calls.
4706--*/
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}
4799
4802 _In_ ULONG LogPageSize,
4804 _In_ ULONG ResourcesSize,
4806 )
4807/*
4808Routine Description:
4809
4810 This function takes a Logical Block Provisioning log page (returned by
4811 ClassGetLBProvisioningLogPage(), for example), interprets its contents,
4812 and returns the interpreted data in a STORAGE_LB_PROVISIONING_MAP_RESOURCES
4813 structure.
4814
4815 None, some, or all of the data in the output buffer may be valid. The
4816 caller must look at the individual "Valid" fields to see which fields have
4817 valid data.
4818
4819Arguments:
4820 DeviceObject: The FDO of the device from which the log page was obtained.
4821 LogPageSize: The size of the LogPage buffer in bytes.
4822 LogPage: A pointer to a valid LBP log page structure.
4823 ResourcesSize: The size of the Resources buffer in bytes.
4824 Resources: A pointer to an already allocated output buffer that may contain
4825 the interpreted log page data when this function returns.
4826
4827Return Value:
4828
4829 STATUS_NOT_SUPPORTED: May be returned if the threshold exponent from the
4830 0xB2 page is invalid.
4831 STATUS_INVALID_PARAMETER: May be returned if either the LogPage or Resources
4832 buffers are NULL or too small.
4833 STATUS_SUCCESS: The log page data was interpreted and the Resources output
4834 buffer has data in it.
4835
4836 This function may return other NTSTATUS codes from internal function calls.
4837--*/
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}
4957
4961 _In_ ULONG ResourcesSize,
4963 )
4964/*
4965Routine Description:
4966
4967 This function obtains the Logical Block Provisioning log page, interprets
4968 its contents, and returns the interpreted data in a
4969 STORAGE_LB_PROVISIONING_MAP_RESOURCES structure.
4970
4971 None, some, or all of the data in the output buffer may be valid. The
4972 caller must look at the individual "Valid" fields to see which fields have
4973 valid data.
4974
4975Arguments:
4976 DeviceObject: The target FDO.
4977 Srb: This should be allocated before it is passed in, but it does not have
4978 to be initialized.
4979 ResourcesSize: The size of the Resources buffer in bytes.
4980 Resources: A pointer to an already allocated output buffer that may contain
4981 the interpreted log page data when this function returns.
4982
4983Return Value:
4984
4985 STATUS_NOT_SUPPORTED: May be returned if the device does not have LBP enabled.
4986 STATUS_INVALID_PARAMETER: May be returned if either the Resources buffer is
4987 NULL or too small.
4988 STATUS_INSUFFICIENT_RESOURCES: May be returned if a log page buffer could not
4989 be allocated.
4990 STATUS_SUCCESS: The log page data was obtained and the Resources output
4991 buffer has data in it.
4992
4993 This function may return other NTSTATUS codes from internal function calls.
4994--*/
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}
5085
5091 )
5092/*
5093Routine Description:
5094
5095 This function returns the LBP resource counts in a
5096 STORAGE_LB_PROVISIONING_MAP_RESOURCES structure in the IRP.
5097
5098 None, some, or all of the data in the output buffer may be valid. The
5099 caller must look at the individual "Valid" fields to see which fields have
5100 valid data.
5101
5102Arguments:
5103 DeviceObject: The target FDO.
5104 Irp: The IRP which will contain the output buffer upon completion.
5105 Srb: This should be allocated before it is passed in, but it does not have
5106 to be initialized.
5107
5108Return Value:
5109
5110 Some NTSTATUS code.
5111
5112--*/
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}
5135
5136_Function_class_(IO_WORKITEM_ROUTINE)
5139VOID
5140NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
5144 )
5145/*
5146 Routine Description:
5147
5148 This function logs a logical block provisioning soft threshold event to the
5149 system event log.
5150
5151Arguments:
5152 DeviceObject: The FDO that represents the device that reported the soft
5153 threshold.
5154 Context: A pointer to the IO_WORKITEM in which this function is running.
5155
5156--*/
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}
5352
5356 _In_ NTSTATUS IoErrorCode
5357 )
5358/*
5359 Routine Description:
5360
5361 This function is a helper routine to log any system events that require
5362 the DeviceNumber (e.g. disk number). It is basically a wrapper for the
5363 IoWriteErrorLogEntry call.
5364
5365Arguments:
5366 DeviceObject: The FDO that represents the device for which the event needs to be logged.
5367 IoErrorCode: The IO error code for the event.
5368
5369Return Value:
5370 STATUS_SUCCESS - if the event was logged
5371 STATUS_INSUFFICIENT_RESOURCES - otherwise
5372
5373--*/
5374{
5377 PIO_ERROR_LOG_PACKET errorLogEntry = NULL;
5378 ULONG logEntrySize = sizeof(IO_ERROR_LOG_PACKET);
5379 PWCHAR stringIndex = NULL;
5380 LONG stringSize = 0;
5381
5382 //
5383 // We need to allocate enough space for one insertion string: a ULONG
5384 // representing the disk number in decimal, which means a max of 10 digits,
5385 // plus one for the NULL character.
5386 // Make sure we do not exceed the max error log size or the max size of a
5387 // UCHAR since the size gets truncated to a UCHAR when we pass it to
5388 // IoAllocateErrorLogEntry().
5389 //
5390 logEntrySize = sizeof(IO_ERROR_LOG_PACKET) + (11 * sizeof(WCHAR));
5391 logEntrySize = min(logEntrySize, ERROR_LOG_MAXIMUM_SIZE);
5392 logEntrySize = min(logEntrySize, MAXUCHAR);
5393
5394 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(DeviceObject, (UCHAR)logEntrySize);
5395 if (errorLogEntry) {
5396
5397 RtlZeroMemory(errorLogEntry, logEntrySize);
5398 errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
5399 errorLogEntry->ErrorCode = IoErrorCode;
5400
5401 stringIndex = (PWCHAR)((ULONG_PTR)errorLogEntry + sizeof(IO_ERROR_LOG_PACKET));
5402 stringSize = logEntrySize - sizeof(IO_ERROR_LOG_PACKET);
5403
5404 //
5405 // Add the disk number to the insertion strings.
5406 //
5407 status = RtlStringCbPrintfW(stringIndex, stringSize, L"%d", fdoExtension->DeviceNumber);
5408
5409 if (NT_SUCCESS(status)) {
5410 errorLogEntry->NumberOfStrings++;
5411 }
5412
5413 //
5414 // Write the error log packet to the system error logging thread.
5415 // It will be freed automatically.
5416 //
5417 IoWriteErrorLogEntry(errorLogEntry);
5418
5420 }
5421
5422 return status;
5423}
5424
5425_Function_class_(IO_WORKITEM_ROUTINE)
5428VOID
5429NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
5433 )
5434/*
5435 Routine Description:
5436
5437 This function logs a logical block provisioning permanent resource exhaustion
5438 event to the system event log.
5439
5440Arguments:
5441 DeviceObject: The FDO that represents the device that reported the permanent
5442 resource exhaustion.
5443 Context: A pointer to the IO_WORKITEM in which this function is running.
5444
5445--*/
5446{
5447 PIO_WORKITEM workItem = (PIO_WORKITEM)Context;
5448
5450
5451 TracePrint((TRACE_LEVEL_INFORMATION,
5452 TRACE_FLAG_GENERAL,
5453 "ClassLogResourceExhaustionEvent: DO (%p), Permanent resource exhaustion logged.\n",
5454 DeviceObject));
5455 } else {
5456 TracePrint((TRACE_LEVEL_ERROR,
5457 TRACE_FLAG_GENERAL,
5458 "ClassLogResourceExhaustionEvent: DO (%p), Failed to allocate memory for error log entry.\n",
5459 DeviceObject));
5460 }
5461
5462
5464
5465 if (workItem != NULL) {
5466 IoFreeWorkItem(workItem);
5467 }
5468}
5469
5470
5473 )
5474/*
5475Routine Description:
5476
5477 This function queues a delayed work item that will eventually log a
5478 logical block provisioning soft threshold event to the system event log.
5479
5480Arguments:
5481 DeviceObject: The FDO that represents the device that reported the soft
5482 threshold.
5483
5484--*/
5485{
5486 PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)(DeviceObject->DeviceExtension);
5488 PIO_WORKITEM workItem = NULL;
5489
5490 if (commonExtension->IsFdo &&
5491 InterlockedCompareExchange((PLONG)&(fdoExtension->FunctionSupportInfo->LBProvisioningData.SoftThresholdEventPending), 1, 0) == 0)
5492 {
5493 workItem = IoAllocateWorkItem(DeviceObject);
5494
5495 if (workItem)
5496 {
5497
5498 TracePrint((TRACE_LEVEL_INFORMATION,
5499 TRACE_FLAG_GENERAL,
5500 "ClassQueueThresholdEventWorker: DO (%p), Queueing soft threshold notification work item.\n",
5501 DeviceObject));
5502
5503
5505
5506 //
5507 // Queue a work item to write the threshold notification to the
5508 // system event log.
5509 //
5511 }
5512 else
5513 {
5514 //
5515 // Clear the soft threshold event pending flag since this is normally
5516 // done when the work item completes.
5517 //
5518 InterlockedExchange((PLONG)&(fdoExtension->FunctionSupportInfo->LBProvisioningData.SoftThresholdEventPending), 0);
5519
5520 TracePrint((TRACE_LEVEL_ERROR,
5521 TRACE_FLAG_GENERAL,
5522 "ClassQueueThresholdEventWorker: DO (%p), Failed to allocate memory for the work item.\n",
5523 DeviceObject));
5524 }
5525 }
5526}
5527
5530 )
5531/*
5532Routine Description:
5533
5534 This function queues a delayed work item that will eventually log a
5535 logical block provisioning permanent resource exhaustion event to the
5536 system event log.
5537
5538Arguments:
5539 DeviceObject: The FDO that represents the device that reported the resource
5540 exhaustion.
5541
5542--*/
5543{
5544 PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)(DeviceObject->DeviceExtension);
5545 PIO_WORKITEM workItem = NULL;
5546
5547 if (commonExtension->IsFdo)
5548 {
5549 workItem = IoAllocateWorkItem(DeviceObject);
5550
5551 if (workItem)
5552 {
5553
5554 TracePrint((TRACE_LEVEL_INFORMATION,
5555 TRACE_FLAG_GENERAL,
5556 "ClassQueueResourceExhaustionEventWorker: DO (%p), Queueing permanent resource exhaustion event work item.\n",
5557 DeviceObject));
5558
5560
5561 //
5562 // Queue a work item to write the threshold notification to the
5563 // system event log.
5564 //
5566 }
5567 else
5568 {
5569 TracePrint((TRACE_LEVEL_ERROR,
5570 TRACE_FLAG_GENERAL,
5571 "ClassQueueResourceExhaustionEventWorker: DO (%p), Failed to allocate memory for the work item.\n",
5572 DeviceObject));
5573 }
5574 }
5575}
5576
5577_Function_class_(IO_WORKITEM_ROUTINE)
5580VOID
5581NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
5582ClassLogCapacityChangedProcess(
5585 )
5586/*
5587 Routine Description:
5588
5589 This function logs a capacity changed event to the system event log.
5590
5591Arguments:
5592 DeviceObject: The FDO that represents the device that reported the capacity change.
5593 Context: A pointer to the IO_WORKITEM in which this function is running.
5594
5595--*/
5596{
5598 PIO_WORKITEM workItem = (PIO_WORKITEM)Context;
5599
5601
5602 if (NT_SUCCESS(status)) {
5603
5604 TracePrint((TRACE_LEVEL_INFORMATION,
5605 TRACE_FLAG_GENERAL,
5606 "ClassLogCapacityChangedEvent: DO (%p), Capacity changed logged.\n",
5607 DeviceObject));
5608 } else {
5609 TracePrint((TRACE_LEVEL_ERROR,
5610 TRACE_FLAG_GENERAL,
5611 "ClassLogCapacityChangedEvent: DO (%p), Failed to allocate memory for error log entry.\n",
5612 DeviceObject));
5613 }
5614
5615 //
5616 // Get disk capacity and notify upper layer if capacity is changed.
5617 //
5619
5620 if (!NT_SUCCESS(status)) {
5621 TracePrint((TRACE_LEVEL_ERROR,
5622 TRACE_FLAG_GENERAL,
5623 "ClassLogCapacityChangedEvent: DO (%p), ClassReadDriveCapacity returned %!STATUS!.\n",
5625 status));
5626 }
5627
5629
5630 if (workItem != NULL) {
5631 IoFreeWorkItem(workItem);
5632 }
5633}
5634
5635
5636VOID
5639 )
5640/*
5641Routine Description:
5642
5643 This function queues a delayed work item that will eventually log a
5644 disk capacity changed event to the system event log.
5645
5646Arguments:
5647 DeviceObject: The FDO that represents the device that reported the capacity change.
5648
5649--*/
5650{
5651 PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)(DeviceObject->DeviceExtension);
5652 PIO_WORKITEM workItem = NULL;
5653
5654 if (commonExtension->IsFdo)
5655 {
5656 workItem = IoAllocateWorkItem(DeviceObject);
5657
5658 if (workItem)
5659 {
5660
5661 TracePrint((TRACE_LEVEL_INFORMATION,
5662 TRACE_FLAG_GENERAL,
5663 "ClassQueueCapacityChangedEventWorker: DO (%p), Queueing capacity changed event work item.\n",
5664 DeviceObject));
5665
5667
5668 //
5669 // Queue a work item to write the threshold notification to the
5670 // system event log.
5671 //
5672 IoQueueWorkItem(workItem, ClassLogCapacityChangedProcess, DelayedWorkQueue, workItem);
5673 }
5674 else
5675 {
5676 TracePrint((TRACE_LEVEL_ERROR,
5677 TRACE_FLAG_GENERAL,
5678 "ClassQueueCapacityChangedEventWorker: DO (%p), Failed to allocate memory for the work item.\n",
5679 DeviceObject));
5680 }
5681 }
5682}
5683
5684_Function_class_(IO_WORKITEM_ROUTINE)
5687VOID
5688NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
5689ClassLogProvisioningTypeChangedEvent(
5692 )
5693/*
5694 Routine Description:
5695
5696 This function logs a provisioning type changed event to the system event log.
5697
5698Arguments:
5699 DeviceObject: The FDO that represents the device that reported the provisioning type change.
5700 Context: A pointer to the IO_WORKITEM in which this function is running.
5701
5702--*/
5703{
5704 PIO_WORKITEM workItem = (PIO_WORKITEM)Context;
5705
5707
5708 TracePrint((TRACE_LEVEL_INFORMATION,
5709 TRACE_FLAG_GENERAL,
5710 "ClassLogProvisioningTypeChangedEvent: DO (%p), LB Provisioning Type changed logged.\n",
5711 DeviceObject));
5712 } else {
5713 TracePrint((TRACE_LEVEL_ERROR,
5714 TRACE_FLAG_GENERAL,
5715 "ClassLogProvisioningTypeChangedEvent: DO (%p), Failed to allocate memory for error log entry.\n",
5716 DeviceObject));
5717 }
5718
5720
5721 IoFreeWorkItem(workItem);
5722}
5723
5724
5725VOID
5728 )
5729/*
5730Routine Description:
5731
5732 This function queues a delayed work item that will eventually log a
5733 provisioning type changed event to the system event log.
5734
5735Arguments:
5736 DeviceObject: The FDO that represents the device that reported the provisioning type change.
5737
5738--*/
5739{
5740 PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)(DeviceObject->DeviceExtension);
5741 PIO_WORKITEM workItem = NULL;
5742
5743 if (commonExtension->IsFdo)
5744 {
5745 workItem = IoAllocateWorkItem(DeviceObject);
5746
5747 if (workItem)
5748 {
5749
5750 TracePrint((TRACE_LEVEL_INFORMATION,
5751 TRACE_FLAG_GENERAL,
5752 "ClassQueueProvisioningTypeChangedEventWorker: DO (%p), Queueing LB provisioning type changed event work item.\n",
5753 DeviceObject));
5754
5756
5757 //
5758 // Queue a work item to write the threshold notification to the
5759 // system event log.
5760 //
5761 IoQueueWorkItem(workItem, ClassLogProvisioningTypeChangedEvent, DelayedWorkQueue, workItem);
5762 }
5763 else
5764 {
5765 TracePrint((TRACE_LEVEL_ERROR,
5766 TRACE_FLAG_GENERAL,
5767 "ClassQueueProvisioningTypeChangedEventWorker: DO (%p), Failed to allocate memory for the work item.\n",
5768 DeviceObject));
5769 }
5770 }
5771}
5772
5773_Function_class_(IO_WORKITEM_ROUTINE)
5776VOID
5777NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
5781 )
5782/*
5783 Routine Description:
5784
5785 This function logs an event to the system event log with dumpdata containing opcode and
5786 sense data.
5787
5788Arguments:
5789 DeviceObject: The FDO that represents the device that retried the IO.
5790 Context: A pointer to the OPCODE_SENSE_DATA_IO_LOG_MESSAGE_CONTEXT that has data to be logged as part of the message.
5791
5792--*/
5793{
5797 PIO_WORKITEM workItem;
5798 PIO_ERROR_LOG_PACKET errorLogEntry = NULL;
5799 ULONG logEntrySize;
5800 PWCHAR stringIndex = NULL;
5801 LONG stringSize = 0;
5802 ULONG senseBufferSize;
5803 ULONG stringsBufferLength = 0;
5804 ULONG pdoNameLength = 0;
5805
5806 NT_ASSERT(ioLogMessageContextHeader != NULL);
5807 _Analysis_assume_(ioLogMessageContextHeader != NULL);
5808
5809 switch (ioLogMessageContextHeader->ErrorCode) {
5810
5813
5814 //
5815 // We need to allocate enough space for 3 insertion strings:
5816 // 1. A ULONGLONG in Hex representing the LBA which means a max of 16 digits,
5817 // plus two for "0x" plus one for the NULL character.
5818 // 2. A ULONG representing the disk number in decimal, which means
5819 // a max of 10 digits, plus one for the NULL character.
5820 // 3. The PDO name, so that if the disk number is hidden from the
5821 // user for some reason, there is still a way to associate the
5822 // event with the correct device.
5823 //
5824 stringsBufferLength = (19 + 11) * sizeof(WCHAR);
5825
5826 //
5827 // Query for the size of the PDO name.
5828 //
5829 status = IoGetDeviceProperty(fdoExtension->LowerPdo,
5831 0,
5832 NULL,
5833 &pdoNameLength);
5834
5835 if (status == STATUS_BUFFER_TOO_SMALL && pdoNameLength > 0) {
5836 stringsBufferLength += pdoNameLength;
5837 } else {
5838 pdoNameLength = 0;
5839 }
5840
5841 break;
5842 }
5843
5844 }
5845
5846 workItem = ioLogMessageContextHeader->WorkItem;
5847
5848 //
5849 // DumpData[0] which is of ULONG size and will contain opcode|srbstatus|scsistatus.
5850 // Then we will have sensebuffer, hence
5851 // DumpDataSize = senseBufferSize + sizeof(ULONG)
5852 // and DumpDataSize must be multiple of sizeof(ULONG)
5853 // which means senseBufferSize needs to ULONG aligned
5854 // Please note we will use original buffersize for padding later
5855 //
5856 senseBufferSize = ALIGN_UP_BY(ioLogMessageContextHeader->SenseDataSize, sizeof(ULONG));
5857
5858 logEntrySize = FIELD_OFFSET( IO_ERROR_LOG_PACKET, DumpData ) + sizeof(ULONG) + senseBufferSize;
5859
5860 //
5861 // We need to make sure the string offset is WCHAR-aligned (the insertion strings
5862 // come after the sense buffer in the dump data, if any).
5863 // But we don't need to do anything special for it,
5864 // since FIELD_OFFSET( IO_ERROR_LOG_PACKET, DumpData) is currently ULONG aligned
5865 // and SenseBufferSize is also ULONG aligned. This means buffer that precedes the insertion string is ULONG aligned
5866 // note stringoffset = FIELD_OFFSET( IO_ERROR_LOG_PACKET, DumpData ) + DumpDataSize
5867 // This leads us to fact that stringoffset will always be ULONG aligned and effectively WCHAR aligned
5868 //
5869
5870 //
5871 // We need to allocate enough space for the insertion strings provided in the passed in Context
5872 // as well as the opcode and the sense data, while making sure we cap at max error log size.
5873 // The log packet is followed by the opcode, then the sense data, and then the
5874 // insertion strings.
5875 //
5876 logEntrySize = logEntrySize + stringsBufferLength;
5877
5878 if (logEntrySize > ERROR_LOG_MAXIMUM_SIZE) {
5879 if (senseBufferSize) {
5880 if (logEntrySize - ERROR_LOG_MAXIMUM_SIZE < senseBufferSize) {
5881 //
5882 // In below steps, senseBufferSize will become same or less than as ioLogMessageContextHeader->SenseDataSize
5883 // it can't be more than that.
5884 //
5885 senseBufferSize -= logEntrySize - ERROR_LOG_MAXIMUM_SIZE;
5886
5887 //
5888 // Decrease the sensebuffersize further, if needed, to keep senseBufferSize ULONG aligned
5889 //
5890 senseBufferSize = ALIGN_DOWN_BY(senseBufferSize, sizeof(ULONG));
5891
5892 } else {
5893 senseBufferSize = 0;
5894 }
5895 }
5896 logEntrySize = ERROR_LOG_MAXIMUM_SIZE;
5897 }
5898
5899 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(DeviceObject, (UCHAR)logEntrySize);
5900
5901 if (errorLogEntry) {
5902
5903 RtlZeroMemory(errorLogEntry, logEntrySize);
5904 errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI;
5905 errorLogEntry->RetryCount = 1;
5906 errorLogEntry->DumpDataSize = (USHORT)(sizeof(ULONG) + senseBufferSize);
5907 errorLogEntry->StringOffset = (USHORT)(FIELD_OFFSET( IO_ERROR_LOG_PACKET, DumpData ) + errorLogEntry->DumpDataSize);
5908 errorLogEntry->ErrorCode = ioLogMessageContextHeader->ErrorCode;
5909 errorLogEntry->DumpData[0] = (((ULONG)(ioLogMessageContextHeader->OpCode)) << 24) |
5910 (((ULONG)(ioLogMessageContextHeader->SrbStatus)) << 16) |
5911 (((ULONG)(ioLogMessageContextHeader->ScsiStatus)) << 8);
5912
5913 //
5914 // Copy sense data and do padding for sense data if needed, with '-'
5915 //
5916 if (senseBufferSize > ioLogMessageContextHeader->SenseDataSize) {
5917 RtlCopyMemory(&errorLogEntry->DumpData[1], ioLogMessageContextHeader->SenseData, ioLogMessageContextHeader->SenseDataSize);
5918 RtlFillMemory( (PCHAR)&errorLogEntry->DumpData[1] + ioLogMessageContextHeader->SenseDataSize , (senseBufferSize - ioLogMessageContextHeader->SenseDataSize) , '-' );
5919 } else {
5920 RtlCopyMemory(&errorLogEntry->DumpData[1], ioLogMessageContextHeader->SenseData, senseBufferSize);
5921 }
5922
5923 stringIndex = (PWCHAR)((PCHAR)errorLogEntry->DumpData + errorLogEntry->DumpDataSize);
5924 stringSize = logEntrySize - errorLogEntry->StringOffset;
5925
5926 //
5927 // Add the strings
5928 //
5929 switch (ioLogMessageContextHeader->ErrorCode) {
5932
5934
5935 //
5936 // The first is a "0x" plus ULONGLONG in hex representing the LBA plus the NULL character.
5937 // The second is a ULONG representing the disk number plus the NULL character.
5938 //
5939 status = RtlStringCbPrintfW(stringIndex, stringSize, L"0x%I64x", ioLogMessageContext->Lba.QuadPart);
5940 if (NT_SUCCESS(status)) {
5941 errorLogEntry->NumberOfStrings++;
5942
5943 //
5944 // Add the disk number to the insertion strings.
5945 //
5946 stringSize -= (ULONG)(wcslen(stringIndex) + 1) * sizeof(WCHAR);
5947 stringIndex += (wcslen(stringIndex) + 1);
5948
5949 if (stringSize > 0) {
5950
5951 status = RtlStringCbPrintfW(stringIndex, stringSize, L"%d", ioLogMessageContext->DeviceNumber);
5952
5953 if (NT_SUCCESS(status)) {
5954
5955 errorLogEntry->NumberOfStrings++;
5956
5957 stringSize -= (ULONG)(wcslen(stringIndex) + 1) * sizeof(WCHAR);
5958 stringIndex += (wcslen(stringIndex) + 1);
5959
5960 if (stringSize >= (LONG)pdoNameLength && pdoNameLength > 0) {
5961 ULONG resultLength;
5962
5963 //
5964 // Get the PDO name and place it in the insertion string buffer.
5965 //
5966 status = IoGetDeviceProperty(fdoExtension->LowerPdo,
5968 pdoNameLength,
5969 stringIndex,
5970 &resultLength);
5971
5972 if (NT_SUCCESS(status) && resultLength > 0) {
5973 errorLogEntry->NumberOfStrings++;
5974 }
5975 }
5976 }
5977 }
5978 }
5979
5980 break;
5981 }
5982
5983 }
5984
5985 //
5986 // Write the error log packet to the system error logging thread.
5987 // It will be freed automatically.
5988 //
5989 IoWriteErrorLogEntry(errorLogEntry);
5990
5991 TracePrint((TRACE_LEVEL_INFORMATION,
5992 TRACE_FLAG_GENERAL,
5993 "ClasspLogIORetriedEvent: DO (%p), Soft threshold notification logged.\n",
5994 DeviceObject));
5995 }
5996
5998
5999 if (ioLogMessageContextHeader->SenseData) {
6000 ExFreePool(ioLogMessageContextHeader->SenseData);
6001 }
6002 if (workItem) {
6003 IoFreeWorkItem(workItem);
6004 }
6005 ExFreePool(ioLogMessageContextHeader);
6006}
6007
6008
6009VOID
6012 _In_ ULONG SenseBufferSize,
6013 _In_ PVOID SenseData,
6014 _In_ UCHAR SrbStatus,
6015 _In_ UCHAR ScsiStatus,
6017 _In_ ULONG CdbLength,
6020 )
6021/*
6022Routine Description:
6023
6024 Helper function that queues a delayed work item that will eventually
6025 log an event to the system event log corresponding to passed in ErrorCode.
6026 The dumpdata is fixed to include the opcode and the sense information.
6027 But the number of insertion strings varies based on the passed in ErrorCode.
6028
6029Arguments:
6030 DeviceObject: The FDO that represents the device that was the target of the IO.
6031 SesneBufferSize: Size of the SenseData buffer.
6032 SenseData: Error information from the target (to be included in the dump data).
6033 SrbStatus: Srb status returned by the miniport.
6034 ScsiStatus: SCSI status associated with the request upon completion from lower layers.
6035 ErrorCode: Numerical value of the error code.
6036 CdbLength: Number of bytes of Cdb.
6037 Cdb: Pointer to the CDB.
6038 Pkt: The tranfer packet representing the IO of interest. This may be NULL.
6039
6040--*/
6041{
6042 PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)(DeviceObject->DeviceExtension);
6044 POPCODE_SENSE_DATA_IO_LOG_MESSAGE_CONTEXT_HEADER ioLogMessageContextHeader = NULL;
6045 PVOID senseData = NULL;
6046 PIO_WORKITEM workItem = NULL;
6047 ULONG senseBufferSize = 0;
6048 LARGE_INTEGER lba = {0};
6049
6050 if (!commonExtension->IsFdo) {
6051 return;
6052 }
6053
6054 if (!Cdb) {
6055 return;
6056 }
6057
6058 workItem = IoAllocateWorkItem(DeviceObject);
6059 if (!workItem) {
6060 goto __ClasspQueueLogIOEventWithContextWorker_ExitWithMessage;
6061 }
6062
6063 if (SenseBufferSize) {
6064 senseData = ExAllocatePoolWithTag(NonPagedPoolNx, SenseBufferSize, CLASSPNP_POOL_TAG_LOG_MESSAGE);
6065 if (senseData) {
6066 senseBufferSize = SenseBufferSize;
6067 }
6068 }
6069
6070 if (CdbLength == 16) {
6071 REVERSE_BYTES_QUAD(&lba, Cdb->CDB16.LogicalBlock);
6072 } else {
6073 ((PFOUR_BYTE)&lba.LowPart)->Byte3 = Cdb->CDB10.LogicalBlockByte0;
6074 ((PFOUR_BYTE)&lba.LowPart)->Byte2 = Cdb->CDB10.LogicalBlockByte1;
6075 ((PFOUR_BYTE)&lba.LowPart)->Byte1 = Cdb->CDB10.LogicalBlockByte2;
6076 ((PFOUR_BYTE)&lba.LowPart)->Byte0 = Cdb->CDB10.LogicalBlockByte3;
6077 }
6078
6079 //
6080 // Calculate the amount of buffer required for the insertion strings.
6081 //
6082 switch (ErrorCode) {
6085
6086 PIO_RETRIED_LOG_MESSAGE_CONTEXT ioLogMessageContext = NULL;
6087
6088 ioLogMessageContext = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(IO_RETRIED_LOG_MESSAGE_CONTEXT), CLASSPNP_POOL_TAG_LOG_MESSAGE);
6089 if (!ioLogMessageContext) {
6090 goto __ClasspQueueLogIOEventWithContextWorker_ExitWithMessage;
6091 }
6092
6093 ioLogMessageContext->Lba.QuadPart = lba.QuadPart;
6094 ioLogMessageContext->DeviceNumber = fdoExtension->DeviceNumber;
6095
6096 ioLogMessageContextHeader = (POPCODE_SENSE_DATA_IO_LOG_MESSAGE_CONTEXT_HEADER)ioLogMessageContext;
6097
6098 break;
6099 }
6100
6101 default: goto __ClasspQueueLogIOEventWithContextWorker_Exit;
6102 }
6103
6104 TracePrint((TRACE_LEVEL_INFORMATION,
6105 TRACE_FLAG_GENERAL,
6106 "ClasspQueueLogIOEventWithContextWorker: DO (%p), Pkt (%p), Queueing IO retried event log message work item.\n",
6108 Pkt));
6109
6110 ioLogMessageContextHeader->WorkItem = workItem;
6111 if (senseData) {
6112 RtlCopyMemory(senseData, SenseData, SenseBufferSize);
6113 }
6114 ioLogMessageContextHeader->SenseData = senseData;
6115 ioLogMessageContextHeader->SenseDataSize = senseBufferSize;
6116 ioLogMessageContextHeader->SrbStatus = SrbStatus;
6117 ioLogMessageContextHeader->ScsiStatus = ScsiStatus;
6118 ioLogMessageContextHeader->OpCode = Cdb->CDB6GENERIC.OperationCode;
6119 ioLogMessageContextHeader->Reserved = 0;
6120 ioLogMessageContextHeader->ErrorCode = ErrorCode;
6121
6123
6124 //
6125 // Queue a work item to write the system event log.
6126 //
6127 IoQueueWorkItem(workItem, ClasspLogIOEventWithContext, DelayedWorkQueue, ioLogMessageContextHeader);
6128
6129 return;
6130
6131__ClasspQueueLogIOEventWithContextWorker_ExitWithMessage:
6132
6133 TracePrint((TRACE_LEVEL_ERROR,
6134 TRACE_FLAG_GENERAL,
6135 "ClasspQueueLogIOEventWithContextWorker: DO (%p), Failed to allocate memory for the log message.\n",
6136 DeviceObject));
6137
6138__ClasspQueueLogIOEventWithContextWorker_Exit:
6139 if (senseData) {
6140 ExFreePool(senseData);
6141 }
6142 if (workItem) {
6143 IoFreeWorkItem(workItem);
6144 }
6145 if (ioLogMessageContextHeader) {
6146 ExFreePool(ioLogMessageContextHeader);
6147 }
6148}
6149
6150static
6151BOOLEAN
6153 UCHAR Scope)
6154{
6155 switch (Scope) {
6158
6159 return TRUE;
6160
6161 default:
6162
6163 break;
6164 }
6165
6166 return FALSE;
6167}
6168
6169static
6170BOOLEAN
6172 UCHAR Type)
6173{
6174 switch (Type) {
6179
6180 return TRUE;
6181
6182 default:
6183
6184 break;
6185 }
6186
6187 return FALSE;
6188}
6189
6190
6191/*++
6192
6193ClasspPersistentReserve
6194
6195Routine Description:
6196
6197 Handles IOCTL_STORAGE_PERSISTENT_RESERVE_IN and IOCTL_STORAGE_PERSISTENT_RESERVE_OUT.
6198
6199Arguments:
6200
6201 DeviceObject - a pointer to the device object
6202 Irp - a pointer to the I/O request packet
6203 Srb - pointer to preallocated SCSI_REQUEST_BLOCK.
6204
6205Return Value:
6206
6207 Status Code
6208
6209--*/
6213 _In_ PIRP Irp,
6215 )
6216{
6218 PCDB cdb = NULL;
6219 PPERSISTENT_RESERVE_COMMAND prCommand = Irp->AssociatedIrp.SystemBuffer;
6220 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
6221
6223
6224 ULONG dataBufLen;
6225 ULONG controlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
6226
6227 BOOLEAN writeToDevice;
6228
6229 //
6230 // Check common input buffer parameters.
6231 //
6232
6233 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
6235 prCommand->Size < sizeof(PERSISTENT_RESERVE_COMMAND)) {
6236
6238 Irp->IoStatus.Status = status;
6239 Irp->IoStatus.Information = 0;
6240
6241 FREE_POOL(Srb);
6242
6245 goto ClasspPersistentReserve_Exit;
6246 }
6247
6248 //
6249 // Check buffer alignment. Only an issue if another kernel mode component
6250 // (not the I/O manager) allocates the buffer.
6251 //
6252
6253 if ((ULONG_PTR)prCommand & fdoExtension->AdapterDescriptor->AlignmentMask) {
6254
6256 Irp->IoStatus.Status = status;
6257 Irp->IoStatus.Information = 0;
6258
6259 FREE_POOL(Srb);
6260
6263 goto ClasspPersistentReserve_Exit;
6264 }
6265
6266 //
6267 // Check additional parameters.
6268 //
6269
6271
6272 SrbSetCdbLength(Srb, 10);
6273 cdb = SrbGetCdb(Srb);
6274
6275 if (controlCode == IOCTL_STORAGE_PERSISTENT_RESERVE_IN) {
6276
6277 //
6278 // Check output buffer for PR In.
6279 //
6280
6281 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
6282 prCommand->PR_IN.AllocationLength) {
6283
6285 }
6286
6287 switch (prCommand->PR_IN.ServiceAction) {
6288
6290
6291 if (prCommand->PR_IN.AllocationLength < sizeof(PRI_REGISTRATION_LIST)) {
6292
6294 }
6295
6296 break;
6297
6299
6300 if (prCommand->PR_IN.AllocationLength < sizeof(PRI_RESERVATION_LIST)) {
6301
6303 }
6304
6305 break;
6306
6307 default:
6308
6310 break;
6311 }
6312
6313 if (!NT_SUCCESS(status)) {
6314
6315 Irp->IoStatus.Status = status;
6316 Irp->IoStatus.Information = 0;
6317
6318 FREE_POOL(Srb);
6319
6322 goto ClasspPersistentReserve_Exit;
6323 }
6324
6325 //
6326 // Fill in the CDB.
6327 //
6328
6330 cdb->PERSISTENT_RESERVE_IN.ServiceAction = prCommand->PR_IN.ServiceAction;
6331
6332 REVERSE_BYTES_SHORT(&(cdb->PERSISTENT_RESERVE_IN.AllocationLength),
6333 &(prCommand->PR_IN.AllocationLength));
6334
6335 dataBufLen = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
6336 writeToDevice = FALSE;
6337
6338
6339 } else {
6340
6341 //
6342 // Verify ServiceAction, Scope, and Type
6343 //
6344
6345 switch (prCommand->PR_OUT.ServiceAction) {
6346
6350
6351 // Scope and type ignored.
6352
6353 break;
6354
6359
6360 if (!ValidPersistentReserveScope(prCommand->PR_OUT.Scope) ||
6361 !ValidPersistentReserveType(prCommand->PR_OUT.Type)) {
6362
6364
6365 }
6366
6367 break;
6368
6369 default:
6370
6372
6373 break;
6374 }
6375
6376 //
6377 // Check input buffer for PR Out.
6378 // Caller must include the PR parameter list.
6379 //
6380
6381 if (NT_SUCCESS(status)) {
6382
6383 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
6385 sizeof(PRO_PARAMETER_LIST)) ||
6386 prCommand->Size <
6387 irpStack->Parameters.DeviceIoControl.InputBufferLength) {
6388
6390
6391 }
6392 }
6393
6394
6395 if (!NT_SUCCESS(status)) {
6396
6397 Irp->IoStatus.Status = status;
6398 Irp->IoStatus.Information = 0;
6399
6400 FREE_POOL(Srb);
6401
6404 goto ClasspPersistentReserve_Exit;
6405 }
6406
6407 //
6408 // Fill in the CDB.
6409 //
6410
6412 cdb->PERSISTENT_RESERVE_OUT.ServiceAction = prCommand->PR_OUT.ServiceAction;
6413 cdb->PERSISTENT_RESERVE_OUT.Scope = prCommand->PR_OUT.Scope;
6414 cdb->PERSISTENT_RESERVE_OUT.Type = prCommand->PR_OUT.Type;
6415
6416 cdb->PERSISTENT_RESERVE_OUT.ParameterListLength[1] = (UCHAR)sizeof(PRO_PARAMETER_LIST);
6417
6418 //
6419 // Move the parameter list to the beginning of the data buffer (so it is aligned
6420 // correctly and that the MDL describes it correctly).
6421 //
6422
6423 RtlMoveMemory(prCommand,
6424 prCommand->PR_OUT.ParameterList,
6425 sizeof(PRO_PARAMETER_LIST));
6426
6427 dataBufLen = sizeof(PRO_PARAMETER_LIST);
6428 writeToDevice = TRUE;
6429 }
6430
6431 //
6432 // Fill in the SRB
6433 //
6434
6435 //
6436 // Set timeout value.
6437 //
6438
6439 SrbSetTimeOutValue(Srb, fdoExtension->TimeOutValue);
6440
6441 //
6442 // Send as a tagged request.
6443 //
6444
6447
6449 Srb,
6450 Irp,
6451 prCommand,
6452 dataBufLen,
6453 writeToDevice);
6454
6455ClasspPersistentReserve_Exit:
6456
6457 return status;
6458
6459}
6460
6461/*++
6462
6463ClasspPriorityHint
6464
6465Routine Description:
6466
6467 Handles IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT.
6468
6469Arguments:
6470
6471 DeviceObject - a pointer to the device object
6472 Irp - a pointer to the I/O request packet
6473
6474Return Value:
6475
6476 Status Code
6477
6478--*/
6482 PIRP Irp
6483 )
6484{
6485 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
6486 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
6487 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
6488 PSTORAGE_PRIORITY_HINT_SUPPORT priSupport = Irp->AssociatedIrp.SystemBuffer;
6491
6492 Irp->IoStatus.Information = 0;
6493
6494 //
6495 // Check whether this device supports idle priority.
6496 //
6497 if (!fdoData->IdlePrioritySupported) {
6499 goto PriorityHintExit;
6500 }
6501
6502 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
6504
6506 goto PriorityHintExit;
6507 }
6508
6509 RtlZeroMemory(priSupport, sizeof(STORAGE_PRIORITY_HINT_SUPPORT));
6510
6511 status = ClassForwardIrpSynchronous(commonExtension, Irp);
6512 if (!NT_SUCCESS(status)) {
6513 //
6514 // If I/O priority is not supported by lower drivers, just set the
6515 // priorities supported by class driver.
6516 //
6517 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_IOCTL, "ClasspPriorityHint: I/O priority not supported by port driver.\n"));
6518 priSupport->SupportFlags = 0;
6520 }
6521
6522 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_IOCTL, "ClasspPriorityHint: I/O priorities supported by port driver: %X\n", priSupport->SupportFlags));
6523
6524 priSupport->SupportFlags |= (1 << IoPriorityVeryLow) |
6525 (1 << IoPriorityLow) |
6526 (1 << IoPriorityNormal) ;
6527
6528 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_IOCTL, "ClasspPriorityHint: I/O priorities supported: %X\n", priSupport->SupportFlags));
6529 Irp->IoStatus.Information = sizeof(STORAGE_PRIORITY_HINT_SUPPORT);
6530
6531PriorityHintExit:
6532
6533 Irp->IoStatus.Status = status;
6536 return status;
6537}
6538
6539/*++
6540
6541ClasspConvertToScsiRequestBlock
6542
6543Routine Description:
6544
6545 Convert an extended SRB to a SCSI_REQUEST_BLOCK. This function handles only
6546 a single SRB and will not converted SRBs that are linked.
6547
6548Arguments:
6549
6550 Srb - a pointer to a SCSI_REQUEST_BLOCK
6551 SrbEx - a pointer to an extended SRB
6552
6553Return Value:
6554
6555 None
6556
6557--*/
6558VOID
6562 )
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}
6709
6710
6711
6714ClasspGetMaximumTokenListIdentifier(
6718 )
6719
6720/*++
6721
6722Routine Description:
6723
6724 This routine returns the maximum ListIdentifier (to be used when building TokenOperation
6725 requests) by querying the value MaximumListIdentifier under the key 'RegistryPath'.
6726
6727Arguments:
6728
6729 DeviceObject - The device handling the request.
6730 RegistryPath - The absolute registry path under which MaximumListIdentifier resides.
6731 MaximumListIdentifier - Returns the value being queried.
6732
6733Return Value:
6734
6735 STATUS_SUCCESS or appropriate error status returned by Registry API.
6736
6737--*/
6738
6739{
6740 RTL_QUERY_REGISTRY_TABLE queryTable[2];
6741 ULONG value = 0;
6743
6744 TracePrint((TRACE_LEVEL_VERBOSE,
6745 TRACE_FLAG_PNP,
6746 "ClasspGetMaximumTokenListIdentifier (%p): Entering function.\n",
6747 DeviceObject));
6748
6749 //
6750 // Zero the table entries.
6751 //
6752 RtlZeroMemory(queryTable, sizeof(queryTable));
6753
6754 //
6755 // The query table has two entries. One for the MaximumListIdentifier and
6756 // the second which is the 'NULL' terminator.
6757 //
6758 // Indicate that there is NO call-back routine.
6759 //
6761
6762 //
6763 // The value to query.
6764 //
6765 queryTable[0].Name = REG_MAX_LIST_IDENTIFIER_VALUE;
6766
6767 //
6768 // Where to put the value, the type of the value, default value and length.
6769 //
6770 queryTable[0].EntryContext = &value;
6772 queryTable[0].DefaultData = &value;
6773 queryTable[0].DefaultLength = sizeof(value);
6774
6775 //
6776 // Try to get the maximum listIdentifier.
6777 //
6780 queryTable,
6781 NULL,
6782 NULL);
6783
6784 if (NT_SUCCESS(status)) {
6786 } else {
6788 }
6789
6790 TracePrint((TRACE_LEVEL_VERBOSE,
6791 TRACE_FLAG_PNP,
6792 "ClasspGetMaximumTokenListIdentifier (%p): Exiting function with status %x (maxListId %u).\n",
6794 status,
6796
6797 return status;
6798}
6799
6802ClasspGetCopyOffloadMaxDuration(
6806 )
6807
6808 /*++
6809
6810 Routine Description:
6811
6812 This routine returns the maximum time (in seconds) that a Copy Offload
6813 operation should take to complete by a target.
6814
6815 Arguments:
6816
6817 DeviceObject - The device handling the request.
6818 RegistryPath - The absolute registry path under which MaxDuration resides.
6819 MaxDuration - Returns the value being queried, in seconds.
6820
6821 Return Value:
6822
6823 STATUS_SUCCESS or appropriate error status returned by Registry API.
6824
6825 --*/
6826
6827{
6828 RTL_QUERY_REGISTRY_TABLE queryTable[2];
6829 ULONG value = 0;
6831
6832 TracePrint((TRACE_LEVEL_VERBOSE,
6833 TRACE_FLAG_PNP,
6834 "ClasspGetCopyOffloadMaxDuration (%p): Entering function.\n",
6835 DeviceObject));
6836
6837 //
6838 // Zero the table entries.
6839 //
6840 RtlZeroMemory(queryTable, sizeof(queryTable));
6841
6842 //
6843 // The query table has two entries. One for CopyOffloadMaxDuration and
6844 // the second which is the 'NULL' terminator.
6845 //
6846 // Indicate that there is NO call-back routine.
6847 //
6849
6850 //
6851 // The value to query.
6852 //
6854
6855 //
6856 // Where to put the value, the type of the value, default value and length.
6857 //
6858 queryTable[0].EntryContext = &value;
6860 queryTable[0].DefaultData = &value;
6861 queryTable[0].DefaultLength = sizeof(value);
6862
6863 //
6864 // Try to get the max target duration.
6865 //
6868 queryTable,
6869 NULL,
6870 NULL);
6871
6872 //
6873 // Don't allow the user to set the value to lower than the default (4s) so
6874 // they don't break ODX functionality if they accidentally set it too low.
6875 //
6876 if (NT_SUCCESS(status) &&
6878 *MaxDuration = value;
6879 } else {
6881 }
6882
6883 TracePrint((TRACE_LEVEL_VERBOSE,
6884 TRACE_FLAG_PNP,
6885 "ClasspGetCopyOffloadMaxDuration (%p): Exiting function with status %x (Max Duration %u seconds).\n",
6887 status,
6888 *MaxDuration));
6889
6890 return status;
6891}
6892
6893
6898ClasspDeviceCopyOffloadProperty(
6902 )
6903
6904/*++
6905
6906Routine Description:
6907
6908 This routine returns the copy offload parameters associated with the device.
6909
6910 This function must be called at IRQL < DISPATCH_LEVEL.
6911
6912Arguments:
6913
6914 DeviceObject - Supplies the device object associated with this request
6915 Irp - The IRP to be processed
6916 Srb - The SRB associated with the request
6917
6918Return Value:
6919
6920 NTSTATUS code
6921
6922--*/
6923
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}
7086
7087
7092ClasspValidateOffloadSupported(
7094 _In_ PIRP Irp
7095 )
7096
7097/*++
7098
7099Routine Description:
7100
7101 This routine validates if this device supports offload requests.
7102
7103 This function must be called at IRQL < DISPATCH_LEVEL.
7104
7105Arguments:
7106
7107 DeviceObject - Supplies the device object associated with this request
7108 Irp - The IRP to be processed
7109
7110Return Value:
7111
7112 NTSTATUS code
7113
7114--*/
7115
7116{
7119
7120 PAGED_CODE();
7121
7122 TracePrint((TRACE_LEVEL_VERBOSE,
7123 TRACE_FLAG_IOCTL,
7124 "ClasspValidateOffloadSupported (%p): Entering function. Irp %p\n",
7126 Irp));
7127
7128 fdoExt = DeviceObject->DeviceExtension;
7130
7131 //
7132 // For now this command is only supported by disk devices
7133 //
7134 if ((DeviceObject->DeviceType == FILE_DEVICE_DISK) &&
7135 (!TEST_FLAG(DeviceObject->Characteristics, FILE_FLOPPY_DISKETTE))) {
7136
7137 if (!fdoExt->FunctionSupportInfo->ValidInquiryPages.BlockDeviceRODLimits) {
7138
7139 TracePrint((TRACE_LEVEL_ERROR,
7140 TRACE_FLAG_IOCTL,
7141 "ClasspValidateOffloadSupported (%p): Command not supported on this disk device.\n",
7142 DeviceObject));
7143
7145 goto __ClasspValidateOffloadSupported_Exit;
7146 }
7147
7148 if (!NT_SUCCESS(fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.CommandStatus)) {
7149
7150 status = fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.CommandStatus;
7151
7152 TracePrint((TRACE_LEVEL_ERROR,
7153 TRACE_FLAG_IOCTL,
7154 "ClasspValidateOffloadSupported (%p): VPD retrieval failed with %x.\n",
7156 status));
7157
7158 goto __ClasspValidateOffloadSupported_Exit;
7159 }
7160 } else {
7161
7162 TracePrint((TRACE_LEVEL_WARNING,
7163 TRACE_FLAG_IOCTL,
7164 "ClasspValidateOffloadSupported (%p): Suported only on Disk devices.\n",
7165 DeviceObject));
7166
7168 goto __ClasspValidateOffloadSupported_Exit;
7169 }
7170
7171__ClasspValidateOffloadSupported_Exit:
7172 TracePrint((TRACE_LEVEL_VERBOSE,
7173 TRACE_FLAG_IOCTL,
7174 "ClasspValidateOffloadSupported (%p): Exiting function Irp %p with status %x.\n",
7176 Irp,
7177 status));
7178
7179 return status;
7180}
7181
7182
7187ClasspValidateOffloadInputParameters(
7189 _In_ PIRP Irp
7190 )
7191
7192/*++
7193
7194Routine Description:
7195
7196 This routine does some basic validation of the input parameters of the offload request.
7197
7198 This function must be called at IRQL < DISPATCH_LEVEL.
7199
7200Arguments:
7201
7202 DeviceObject - Supplies the device object associated with this request
7203 Irp - The IRP to be processed
7204
7205Return Value:
7206
7207 NTSTATUS code
7208
7209--*/
7210
7211{
7212 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
7213 PIO_STACK_LOCATION irpStack;
7215 PDEVICE_DATA_SET_RANGE dataSetRanges;
7216 ULONG dataSetRangesCount;
7217 ULONG i;
7219
7220 PAGED_CODE();
7221
7222 TracePrint((TRACE_LEVEL_VERBOSE,
7223 TRACE_FLAG_IOCTL,
7224 "ClasspValidateOffloadInputParameters (%p): Entering function Irp %p.\n",
7226 Irp));
7227
7228 fdoExtension = DeviceObject->DeviceExtension;
7229 irpStack = IoGetCurrentIrpStackLocation (Irp);
7230 dsmAttributes = Irp->AssociatedIrp.SystemBuffer;
7232
7233 if (!dsmAttributes) {
7234
7235 TracePrint((TRACE_LEVEL_ERROR,
7236 TRACE_FLAG_IOCTL,
7237 "ClasspValidateOffloadInputParameters (%p): NULL DsmAttributes passed in.\n",
7238 DeviceObject));
7239
7241 goto __ClasspValidateOffloadInputParameters_Exit;
7242 }
7243
7244 if ((irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES)) ||
7245 (irpStack->Parameters.DeviceIoControl.InputBufferLength <
7246 (sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES) + dsmAttributes->ParameterBlockLength + dsmAttributes->DataSetRangesLength))) {
7247
7248 TracePrint((TRACE_LEVEL_ERROR,
7249 TRACE_FLAG_IOCTL,
7250 "ClasspValidateOffloadInputParameters (%p): Input buffer size (%u) too small.\n",
7252 irpStack->Parameters.DeviceIoControl.InputBufferLength));
7253
7255 goto __ClasspValidateOffloadInputParameters_Exit;
7256 }
7257
7258 if ((dsmAttributes->DataSetRangesOffset == 0) ||
7259 (dsmAttributes->DataSetRangesLength == 0)) {
7260
7261 TracePrint((TRACE_LEVEL_ERROR,
7262 TRACE_FLAG_IOCTL,
7263 "ClasspValidateOffloadInputParameters (%p): Incorrect DataSetRanges [offset %u, length %u].\n",
7265 dsmAttributes->DataSetRangesOffset,
7266 dsmAttributes->DataSetRangesLength));
7267
7269 goto __ClasspValidateOffloadInputParameters_Exit;
7270 }
7271
7272 dataSetRanges = Add2Ptr(dsmAttributes, dsmAttributes->DataSetRangesOffset);
7273 dataSetRangesCount = dsmAttributes->DataSetRangesLength / sizeof(DEVICE_DATA_SET_RANGE);
7274
7275 if (dataSetRangesCount == 0) {
7276
7277 TracePrint((TRACE_LEVEL_ERROR,
7278 TRACE_FLAG_IOCTL,
7279 "ClasspValidateOffloadInputParameters (%p): DataSetRanges specifies no extents.\n",
7280 DeviceObject));
7281
7283 goto __ClasspValidateOffloadInputParameters_Exit;
7284 }
7285
7286 //
7287 // Some third party disk class drivers do not query the geometry at initialization time,
7288 // so this information may not be available at this time. If that is the case, we'll
7289 // first query that information before proceeding with the rest of our validations.
7290 //
7291 if (fdoExtension->DiskGeometry.BytesPerSector == 0) {
7293 if ((!NT_SUCCESS(status)) || (fdoExtension->DiskGeometry.BytesPerSector == 0)) {
7294 TracePrint((TRACE_LEVEL_ERROR,
7295 TRACE_FLAG_IOCTL,
7296 "ClasspValidateOffloadInputParameters (%p): Couldn't retrieve disk geometry, status: %x, bytes/sector: %u.\n",
7298 status,
7299 fdoExtension->DiskGeometry.BytesPerSector));
7300
7302 goto __ClasspValidateOffloadInputParameters_Exit;
7303 }
7304 }
7305
7306 //
7307 // Data must be aligned to sector boundary and
7308 // LengthInBytes must be > 0 for it to be a valid LBA entry
7309 //
7310 for (i = 0; i < dataSetRangesCount; i++) {
7311 if ((dataSetRanges[i].StartingOffset % fdoExtension->DiskGeometry.BytesPerSector != 0) ||
7312 (dataSetRanges[i].LengthInBytes % fdoExtension->DiskGeometry.BytesPerSector != 0) ||
7313 (dataSetRanges[i].LengthInBytes == 0) ) {
7314 TracePrint((TRACE_LEVEL_ERROR,
7315 TRACE_FLAG_IOCTL,
7316 "ClasspValidateOffloadInputParameters (%p): Incorrect DataSetRanges entry %u [offset %I64x, length %I64x].\n",
7318 i,
7319 dataSetRanges[i].StartingOffset,
7320 dataSetRanges[i].LengthInBytes));
7321
7323 goto __ClasspValidateOffloadInputParameters_Exit;
7324 }
7325
7326 if ((ULONGLONG)dataSetRanges[i].StartingOffset + dataSetRanges[i].LengthInBytes > (ULONGLONG)fdoExtension->CommonExtension.PartitionLength.QuadPart) {
7327
7328 TracePrint((TRACE_LEVEL_ERROR,
7329 TRACE_FLAG_IOCTL,
7330 "ClasspValidateOffloadInputParameters (%p): Error! DataSetRange %u (starting LBA %I64x) specified length %I64x exceeds the medium's capacity (%I64x).\n",
7332 i,
7333 dataSetRanges[i].StartingOffset,
7334 dataSetRanges[i].LengthInBytes,
7336
7338 goto __ClasspValidateOffloadInputParameters_Exit;
7339 }
7340 }
7341
7342__ClasspValidateOffloadInputParameters_Exit:
7343 TracePrint((TRACE_LEVEL_VERBOSE,
7344 TRACE_FLAG_IOCTL,
7345 "ClasspValidateOffloadInputParameters (%p): Exiting function Irp %p with status %x.\n",
7347 Irp,
7348 status));
7349
7350 return status;
7351}
7352
7353
7358 _In_ ULONG ServiceAction,
7359 _Inout_ PULONG CommandBufferLength,
7360 _Out_opt_ PULONG TokenOperationBufferLength,
7361 _Out_opt_ PULONG ReceiveTokenInformationBufferLength
7362 )
7363
7364/*++
7365
7366Routine description:
7367
7368 This routine calculates the buffer length required to service a TokenOperation and its
7369 corresponding ReceiveTokenInformation command.
7370
7371Arguments:
7372
7373 Fdo - The functional device object processing the PopulateToken/WriteUsingToken request
7374 ServiceAction - Used to distinguish between a PopulateToken and a WriteUsingToken operation
7375 CommandBufferLength - Returns the length of the buffer needed to service the token request (i.e. TokenOperation and its corresponding ReceiveTokenInformation command)
7376 TokenOperationBufferLength - Optional parameter, which returns the length of the buffer needed to service just the TokenOperation command.
7377 ReceiveTokenInformationBufferLength - Optional parameter, which returns the length of the buffer needed to service just the ReceiveTokenInformation command.
7378
7379Return Value:
7380
7381 STATUS_SUCCESS
7382
7383--*/
7384
7385{
7386 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
7387 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
7388 ULONG tokenOperationBufferLength;
7389 ULONG receiveTokenInformationBufferLength;
7390 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
7391 PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExtension->PartitionZeroExtension->AdapterDescriptor;
7392 ULONG hwMaxXferLen;
7393 ULONG bufferLength = 0;
7394 ULONG tokenOperationHeaderSize;
7395 ULONG responseSize;
7396
7397 TracePrint((TRACE_LEVEL_VERBOSE,
7398 TRACE_FLAG_IOCTL,
7399 "ClasspGetTokenOperationCommandBufferLengths (%p): Entering function.\n",
7400 Fdo));
7401
7402 NT_ASSERT(fdoExt->FunctionSupportInfo->ValidInquiryPages.BlockDeviceRODLimits &&
7403 NT_SUCCESS(fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.CommandStatus));
7404
7405 if (ServiceAction == SERVICE_ACTION_POPULATE_TOKEN) {
7406 tokenOperationHeaderSize = FIELD_OFFSET(POPULATE_TOKEN_HEADER, BlockDeviceRangeDescriptor);
7408 } else {
7409 tokenOperationHeaderSize = FIELD_OFFSET(WRITE_USING_TOKEN_HEADER, BlockDeviceRangeDescriptor);
7410 responseSize = 0;
7411 }
7412
7413 //
7414 // The TokenOperation command can specify a parameter length of max 2^16.
7415 // If the device has a max limit on the number of range descriptors that can be specified in
7416 // the TokenOperation command, we are limited to the lesser of these two values.
7417 //
7418 if (fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumRangeDescriptors == 0) {
7419
7420 tokenOperationBufferLength = MAX_TOKEN_OPERATION_PARAMETER_DATA_LENGTH;
7421
7422 } else {
7423
7424 tokenOperationBufferLength = MIN(tokenOperationHeaderSize + fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumRangeDescriptors * sizeof(BLOCK_DEVICE_RANGE_DESCRIPTOR),
7426 }
7427
7428
7429 //
7430 // The ReceiveTokenInformation command can specify a parameter length of max 2 ^ 32
7431 // Also, since the sense data can be of variable size, we'll use MAX_SENSE_BUFFER_SIZE.
7432 //
7433 receiveTokenInformationBufferLength = MIN(FIELD_OFFSET(RECEIVE_TOKEN_INFORMATION_HEADER, SenseData) + MAX_SENSE_BUFFER_SIZE + responseSize,
7435
7436 //
7437 // Since we're going to reuse the buffer for both the TokenOperation and the ReceiveTokenInformation
7438 // commands, the buffer length needs to handle both operations.
7439 //
7440 bufferLength = MAX(tokenOperationBufferLength, receiveTokenInformationBufferLength);
7441
7442 //
7443 // The buffer length needs to be further limited to the adapter's capability though.
7444 //
7445 hwMaxXferLen = MIN(fdoData->HwMaxXferLen, adapterDesc->MaximumTransferLength);
7446 bufferLength = MIN(bufferLength, hwMaxXferLen);
7447
7448 *CommandBufferLength = bufferLength;
7449
7450 if (TokenOperationBufferLength) {
7451 *TokenOperationBufferLength = tokenOperationBufferLength;
7452 }
7453
7454 if (ReceiveTokenInformationBufferLength) {
7455 *ReceiveTokenInformationBufferLength = receiveTokenInformationBufferLength;
7456 }
7457
7458 TracePrint((TRACE_LEVEL_VERBOSE,
7459 TRACE_FLAG_IOCTL,
7460 "ClasspGetTokenOperationCommandBufferLengths (%p): Exiting function with bufferLength %u (tokenOpBufLen %u, recTokenInfoBufLen %u).\n",
7461 Fdo,
7463 tokenOperationBufferLength,
7464 receiveTokenInformationBufferLength));
7465
7466 return STATUS_SUCCESS;
7467}
7468
7469
7474 _In_ ULONG ServiceAction,
7475 _In_ ULONG MaxParameterBufferLength,
7476 _Out_ PULONG MaxBlockDescriptorsCount,
7477 _Out_ PULONGLONG MaxBlockDescriptorsLength
7478 )
7479
7480/*++
7481
7482Routine description:
7483
7484 This routine calculates the maximum block descriptors and the maximum token transfer size
7485 that can be accomodated in a single TokenOperation command.
7486
7487Arguments:
7488
7489 Fdo - The functional device object processing the PopulateToken/WriteUsingToken request
7490 ServiceAction - Used to distinguish between a PopulateToken and a WriteUsingToken operation
7491 MaxParameterBufferLength - The length constraint of the entire buffer for the parameter list based on other limitations (e.g. adapter max transfer length)
7492 MaxBlockDescriptorsCount - Returns the maximum number of the block range descriptors that can be passed in a single TokenOperation command.
7493 MaxBlockDescriptorsLength - Returns the maximum cumulative number of blocks across all the descriptors that must not be exceeded in a single TokenOperation command.
7494
7495Return Value:
7496
7497 STATUS_SUCCESS
7498
7499--*/
7500
7501{
7502 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
7503 ULONG tokenOperationHeaderSize = (ServiceAction == SERVICE_ACTION_POPULATE_TOKEN) ?
7504 FIELD_OFFSET(POPULATE_TOKEN_HEADER, BlockDeviceRangeDescriptor) :
7505 FIELD_OFFSET(WRITE_USING_TOKEN_HEADER, BlockDeviceRangeDescriptor);
7506
7507 TracePrint((TRACE_LEVEL_VERBOSE,
7508 TRACE_FLAG_IOCTL,
7509 "ClasspGetTokenOperationDescriptorLimits (%p): Entering function.\n",
7510 Fdo));
7511
7512 NT_ASSERT(fdoExt->FunctionSupportInfo->ValidInquiryPages.BlockDeviceRODLimits &&
7513 NT_SUCCESS(fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.CommandStatus));
7514
7515 *MaxBlockDescriptorsCount = (MaxParameterBufferLength - tokenOperationHeaderSize) / sizeof(BLOCK_DEVICE_RANGE_DESCRIPTOR);
7516 *MaxBlockDescriptorsLength = (fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumTokenTransferSize == 0) ?
7517 MAX_TOKEN_TRANSFER_SIZE : fdoExt->FunctionSupportInfo->BlockDeviceRODLimitsData.MaximumTokenTransferSize;
7518
7519 TracePrint((TRACE_LEVEL_VERBOSE,
7520 TRACE_FLAG_IOCTL,
7521 "ClasspGetTokenOperationDescriptorLimits (%p): Exiting function with MaxDescr %u, MaxXferBlocks %I64u.\n",
7522 Fdo,
7523 *MaxBlockDescriptorsCount,
7524 *MaxBlockDescriptorsLength));
7525
7526 return STATUS_SUCCESS;
7527}
7528
7529
7530
7534VOID
7535ClasspConvertDataSetRangeToBlockDescr(
7544 )
7545
7546/*++
7547
7548Routine Description:
7549
7550 Convert DEVICE_DATA_SET_RANGE entry to be WINDOWS_BLOCK_DEVICE_RANGE_DESCRIPTOR entries.
7551
7552 As LengthInBytes field in DEVICE_DATA_SET_RANGE structure is 64 bits (bytes)
7553 and LbaCount field in WINDOWS_BLOCK_DEVICE_RANGE_DESCRIPTOR structure is 32 bits (sectors),
7554 it's possible that one DEVICE_DATA_SET_RANGE entry needs multiple
7555 WINDOWS_BLOCK_DEVICE_RANGE_DESCRIPTOR entries. This routine handles the need for that
7556 potential split.
7557
7558Arguments:
7559
7560 Fdo - The functional device object
7561 BlockDescr - Pointer to the start of the Token Operation command's block descriptor
7562 CurrentBlockDescrIndex - Index into the block descriptor at which to update the DataSetRange info
7563 It also gets updated to return the index to the next empty one.
7564 MaxBlockDescrCount - Maximum number of block descriptors that the device can handle in a single TokenOperation command
7565 CurrentLbaCount - Returns the LBA of the last successfully processed DataSetRange
7566 MaxLbaCount - Maximum transfer size that the device is capable of handling in a single TokenOperation command
7567 DataSetRange - Contains information about one range extent that needs to be converted into a block descriptor
7568 TotalSectorsProcessed - Returns the number of sectors corresponding to the DataSetRange that were succesfully mapped into block descriptors
7569
7570Return Value:
7571
7572 Nothing.
7573
7574 NOTE: if LengthInBytes does not reach to 0, the conversion for DEVICE_DATA_SET_RANGE entry
7575 is not completed. Further conversion is needed by calling this function again.
7576
7577--*/
7578
7579{
7580 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
7582 ULONGLONG startingSector;
7584 ULONGLONG totalSectorCount;
7585 ULONGLONG numberOfOptimalChunks;
7586 USHORT optimalLbaPerDescrGranularity;
7587 ULONG optimalLbaPerDescr;
7588 ULONG maxLbaPerDescr;
7589
7590 TracePrint((TRACE_LEVEL_VERBOSE,
7591 TRACE_FLAG_IOCTL,
7592 "ClasspConvertDataSetRangeToBlockDescr (%p): Entering function. Starting offset %I64x.\n",
7593 Fdo,
7594 DataSetRange->StartingOffset));
7595
7596 fdoExtension = Fdo->DeviceExtension;
7598 totalSectorCount = 0;
7599
7600
7601 //
7602 // Since the OptimalTransferLength and the MaximumTransferLength are overloaded parameters for
7603 // offloaded data transfers and regular read/write requests, it is not safe to use these values
7604 // as they may report back what is used by regular read/write, which will cause a perf degradation
7605 // in the offloaded case, since we may end up limiting the per block range descriptor length
7606 // specified as opposed to what the target can actually handle in a single request.
7607 // So until the SPC spec introduces these values specific to offloaded data transfers, we shall
7608 // ignore them completely. The expectation we have from the target is as follows:
7609 // 1. If the length specified in any of the block range descriptors is greater than the OTL that
7610 // applies to ODX, the target will internally split into additional descriptors.
7611 // 2. If the above causes it to run out of descriptors, or if the length specified in any of the
7612 // descriptors is greater than the MTL that applies to ODX, the target will operate on as much
7613 // data as possible and truncate the request to that point.
7614 //
7615 optimalLbaPerDescrGranularity = 0;
7616 optimalLbaPerDescr = 0;
7617 maxLbaPerDescr = 0;
7618
7619 if (optimalLbaPerDescr && maxLbaPerDescr) {
7620
7621 NT_ASSERT(optimalLbaPerDescr <= maxLbaPerDescr);
7622 }
7623
7624 while ((DataSetRange->LengthInBytes > 0) &&
7627
7628 startingSector = (ULONGLONG)(DataSetRange->StartingOffset / fdoExtension->DiskGeometry.BytesPerSector);
7629
7630 //
7631 // Since the block descriptor has only 4 bytes for the number of logical blocks, we are
7632 // constrained by that theoretical maximum.
7633 //
7634 sectorCount = MIN(DataSetRange->LengthInBytes / fdoExtension->DiskGeometry.BytesPerSector,
7636
7637 //
7638 // We are constrained by MaxLbaCount.
7639 //
7641
7643 }
7644
7645 //
7646 // For each descriptor, the block count should be lesser than the MaximumTransferSize
7647 //
7648 if (maxLbaPerDescr > 0) {
7649
7650 //
7651 // Each block device range descriptor can specify a max number of LBAs
7652 //
7653 sectorCount = MIN(sectorCount, maxLbaPerDescr);
7654 }
7655
7656 //
7657 // If the number of LBAs specified in the descriptor is greater than the OptimalTransferLength,
7658 // processing of this descriptor by the target may incur a significant delay.
7659 // So in order to allow the target to perform optimally, we'll further limit the number
7660 // of blocks specified in any descriptor to be maximum OptimalTranferLength.
7661 //
7662 if (optimalLbaPerDescr > 0) {
7663
7664 sectorCount = MIN(sectorCount, optimalLbaPerDescr);
7665 }
7666
7667 //
7668 // In addition, it should either be an exact multiple of the OptimalTransferLengthGranularity,
7669 // or be lesser than the OptimalTransferLengthGranularity (taken care of here).
7670 //
7671 if (optimalLbaPerDescrGranularity > 0) {
7672
7673 numberOfOptimalChunks = sectorCount / optimalLbaPerDescrGranularity;
7674
7675 if (numberOfOptimalChunks > 0) {
7676 sectorCount = numberOfOptimalChunks * optimalLbaPerDescrGranularity;
7677 }
7678 }
7679
7681
7682 REVERSE_BYTES_QUAD(blockDescr[*CurrentBlockDescrIndex].LogicalBlockAddress, &startingSector);
7683 REVERSE_BYTES(blockDescr[*CurrentBlockDescrIndex].TransferLength, &sectorCount);
7684
7685 totalSectorCount += sectorCount;
7686
7687 DataSetRange->StartingOffset += sectorCount * fdoExtension->DiskGeometry.BytesPerSector;
7688 DataSetRange->LengthInBytes -= sectorCount * fdoExtension->DiskGeometry.BytesPerSector;
7689
7692
7693 TracePrint((TRACE_LEVEL_INFORMATION,
7694 TRACE_FLAG_IOCTL,
7695 "ClasspConvertDataSetRangeToBlockDescr (%p): Descriptor: %u, starting LBA: %I64x, length: %I64x bytes, media size: %I64x.\n",
7696 Fdo,
7698 startingSector,
7699 sectorCount * fdoExtension->DiskGeometry.BytesPerSector,
7701 }
7702
7703 *TotalSectorsProcessed = totalSectorCount;
7704
7705 TracePrint((TRACE_LEVEL_VERBOSE,
7706 TRACE_FLAG_IOCTL,
7707 "ClasspConvertDataSetRangeToBlockDescr (%p): Exiting function (starting offset %I64x). Total sectors processed %I64u.\n",
7708 Fdo,
7709 DataSetRange->StartingOffset,
7710 totalSectorCount));
7711
7712 return;
7713}
7714
7716PUCHAR
7718 _In_reads_(Length) PUCHAR HexBuffer,
7720 _Inout_ PULONG UpdateLength
7721 )
7722
7723/*++
7724
7725Routine Description:
7726
7727 This routine will convert HexBuffer into an ascii NULL-terminated string.
7728
7729 Note: This routine will allocate memory for storing the ascii string. It is
7730 the responsibility of the caller to free this buffer.
7731
7732Arguments:
7733
7734 HexBuffer - Pointer to the binary data.
7735 Length - Length, in bytes, of HexBuffer.
7736 UpdateLength - Storage to place the actual length of the returned string.
7737
7738Return Value:
7739
7740 ASCII string equivalent of the hex buffer, or NULL if an error occurred.
7741
7742--*/
7743
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}
7823
7828 _In_ PIRP Irp
7829 )
7830
7831/*++
7832
7833Routine Description:
7834
7835 This routine handles an asynchronous event notification (most likely from
7836 port drivers). Currently, we only care about media status change events.
7837
7838Arguments:
7839
7840 DeviceObject - Supplies the device object associated with this request
7841 Irp - The IRP to be processed
7842
7843Return Value:
7844
7845 NTSTATUS code
7846
7847--*/
7848
7849{
7850 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
7851 PIO_STACK_LOCATION irpStack;
7852 PSTORAGE_EVENT_NOTIFICATION storageEvents;
7854
7855 TracePrint((TRACE_LEVEL_VERBOSE,
7856 TRACE_FLAG_IOCTL,
7857 "ClasspStorageEventNotification (%p): Entering function Irp %p.\n",
7859 Irp));
7860
7861 fdoExtension = DeviceObject->DeviceExtension;
7862 irpStack = IoGetCurrentIrpStackLocation (Irp);
7863 storageEvents = Irp->AssociatedIrp.SystemBuffer;
7865
7866 if (!storageEvents) {
7867
7868 TracePrint((TRACE_LEVEL_ERROR,
7869 TRACE_FLAG_IOCTL,
7870 "ClasspStorageEventNotification (%p): NULL storage events passed in.\n",
7871 DeviceObject));
7872
7874 goto __ClasspStorageEventNotification_Exit;
7875 }
7876
7877 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_EVENT_NOTIFICATION)) {
7878
7879 TracePrint((TRACE_LEVEL_ERROR,
7880 TRACE_FLAG_IOCTL,
7881 "ClasspStorageEventNotification (%p): Input buffer size (%u) too small.\n",
7883 irpStack->Parameters.DeviceIoControl.InputBufferLength));
7884
7886 goto __ClasspStorageEventNotification_Exit;
7887 }
7888
7889 if ((storageEvents->Version != STORAGE_EVENT_NOTIFICATION_VERSION_V1) ||
7890 (storageEvents->Size != sizeof(STORAGE_EVENT_NOTIFICATION))) {
7891
7892 TracePrint((TRACE_LEVEL_ERROR,
7893 TRACE_FLAG_IOCTL,
7894 "ClasspStorageEventNotification (%p): Invalid version/size [version %u, size %u].\n",
7896 storageEvents->Version,
7897 storageEvents->Size));
7898
7900 goto __ClasspStorageEventNotification_Exit;
7901 }
7902
7903 //
7904 // Handle a media status event.
7905 //
7906 if (storageEvents->Events & STORAGE_EVENT_MEDIA_STATUS) {
7907
7908 //
7909 // Only initiate operation if underlying port driver supports asynchronous notification
7910 // and this is the FDO.
7911 //
7912 if ((fdoExtension->CommonExtension.IsFdo == TRUE) &&
7913 (fdoExtension->FunctionSupportInfo->AsynchronousNotificationSupported)) {
7914 ClassCheckMediaState(fdoExtension);
7915 } else {
7917 }
7918
7919 }
7920
7921__ClasspStorageEventNotification_Exit:
7922 TracePrint((TRACE_LEVEL_VERBOSE,
7923 TRACE_FLAG_IOCTL,
7924 "ClasspStorageEventNotification (%p): Exiting function Irp %p with status %x.\n",
7926 Irp,
7927 status));
7928
7929 Irp->IoStatus.Information = 0;
7930 Irp->IoStatus.Status = status;
7933
7934 return status;
7935}
7936
7937VOID
7940 )
7941/*++
7942
7943Routine Description:
7944
7945 This routine will attempt to set the QERR bit of the mode Control page to
7946 zero.
7947
7948Arguments:
7949
7950 DeviceObject - Supplies the device object associated with this request
7951
7952Return Value:
7953
7954 None
7955
7956--*/
7957{
7958 PMODE_PARAMETER_HEADER modeData = NULL;
7959 PMODE_CONTROL_PAGE pageData = NULL;
7960 ULONG size = 0;
7961
7962 modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
7965
7966 if (modeData == NULL) {
7967 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_SCSI, "ClasspZeroQERR: Unable to allocate mode data buffer\n"));
7968 goto ClasspZeroQERR_Exit;
7969 }
7970
7972
7974 (PCHAR) modeData,
7977
7978 if (size < sizeof(MODE_PARAMETER_HEADER)) {
7979
7980 //
7981 // Retry the request in case of a check condition.
7982 //
7983
7985 (PCHAR) modeData,
7988
7989 if (size < sizeof(MODE_PARAMETER_HEADER)) {
7990 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_SCSI, "ClasspZeroQERR: Mode Sense failed\n"));
7991 goto ClasspZeroQERR_Exit;
7992 }
7993 }
7994
7995 //
7996 // If the size is greater than size indicated by the mode data reset
7997 // the data to the mode data.
7998 //
7999
8000 if (size > (ULONG) (modeData->ModeDataLength + 1)) {
8001 size = modeData->ModeDataLength + 1;
8002 }
8003
8004 //
8005 // Look for control page in the returned mode page data.
8006 //
8007
8008 pageData = ClassFindModePage((PCHAR) modeData,
8009 size,
8011 TRUE);
8012
8013 if (pageData) {
8014 TracePrint((TRACE_LEVEL_VERBOSE,
8015 TRACE_FLAG_SCSI,
8016 "ClasspZeroQERR (%p): Current settings: QERR = %u, TST = %u, TAS = %u.\n",
8018 pageData->QERR,
8019 pageData->TST,
8020 pageData->TAS));
8021
8022 if (pageData->QERR != 0) {
8024 UCHAR pageSavable = 0;
8025
8026 //
8027 // Set QERR to 0 with a Mode Select command. Re-use the modeData
8028 // and pageData structures.
8029 //
8030 pageData->QERR = 0;
8031
8032 //
8033 // We use the original Page Savable (PS) value for the Save Pages
8034 // (SP) bit due to behavior described under the MODE SELECT(6)
8035 // section of SPC-4.
8036 //
8037 pageSavable = pageData->PageSavable;
8038
8040 (PCHAR)modeData,
8041 size,
8042 pageSavable);
8043
8044 if (!NT_SUCCESS(status)) {
8045 TracePrint((TRACE_LEVEL_WARNING,
8046 TRACE_FLAG_SCSI,
8047 "ClasspZeroQERR (%p): Failed to set QERR = 0 with status %x\n",
8049 status));
8050 }
8051 }
8052 }
8053
8054ClasspZeroQERR_Exit:
8055
8056 if (modeData != NULL) {
8057 ExFreePool(modeData);
8058 }
8059}
8060
8063ClasspPowerActivateDevice(
8065 )
8066/*++
8067
8068Routine Description:
8069
8070 This routine synchronously sends an IOCTL_STORAGE_POWER_ACTIVE to the port
8071 PDO in order to take an active reference on the given device. The device
8072 will remain powered up and active for as long as this active reference is
8073 taken.
8074
8075 The caller should ensure idle power management is enabled for the device
8076 before calling this function.
8077
8078 Call ClasspPowerIdleDevice to release the active reference.
8079
8080Arguments:
8081
8082 DeviceObject - Supplies the FDO associated with this request.
8083
8084Return Value:
8085
8086 STATUS_SUCCESS if the active reference was successfully taken.
8087
8088--*/
8089{
8091 PIRP irp;
8092 KEVENT event;
8093 IO_STATUS_BLOCK ioStatus;
8095
8096 NT_ASSERT(fdoExtension->CommonExtension.IsFdo);
8097 NT_ASSERT(fdoExtension->FunctionSupportInfo->IdlePower.IdlePowerEnabled);
8098
8100
8102 fdoExtension->LowerPdo,
8103 NULL,
8104 0,
8105 NULL,
8106 0,
8107 FALSE,
8108 &event,
8109 &ioStatus);
8110
8111 if (irp != NULL) {
8112 status = IoCallDriver(fdoExtension->LowerPdo, irp);
8113 if (status == STATUS_PENDING) {
8115 status = ioStatus.Status;
8116 }
8117 } else {
8119 }
8120
8121 return status;
8122}
8123
8126ClasspPowerIdleDevice(
8128 )
8129/*++
8130
8131Routine Description:
8132
8133 This routine synchronously sends an IOCTL_STORAGE_POWER_IDLE to the port
8134 PDO in order to release an active reference on the given device.
8135
8136 A call to ClasspPowerActivateDevice *must* have preceded a call to this
8137 function.
8138
8139 The caller should ensure idle power management is enabled for the device
8140 before calling this function.
8141
8142Arguments:
8143
8144 DeviceObject - Supplies the FDO associated with this request.
8145
8146Return Value:
8147
8148 STATUS_SUCCESS if the active reference was successfully released.
8149
8150--*/
8151{
8153 PIRP irp;
8154 KEVENT event;
8155 IO_STATUS_BLOCK ioStatus;
8157
8158 NT_ASSERT(fdoExtension->CommonExtension.IsFdo);
8159 NT_ASSERT(fdoExtension->FunctionSupportInfo->IdlePower.IdlePowerEnabled);
8160
8162
8164 fdoExtension->LowerPdo,
8165 NULL,
8166 0,
8167 NULL,
8168 0,
8169 FALSE,
8170 &event,
8171 &ioStatus);
8172
8173 if (irp != NULL) {
8174 status = IoCallDriver(fdoExtension->LowerPdo, irp);
8175 if (status == STATUS_PENDING) {
8177 status = ioStatus.Status;
8178 }
8179 } else {
8181 }
8182
8183 return status;
8184}
8185
8186
8187#if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
8188
8192 )
8193{
8194 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
8195 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
8196
8197 PSTORAGE_HW_FIRMWARE_INFO firmwareInfo = NULL;
8198 PSTORAGE_HW_FIRMWARE_INFO_QUERY query = NULL;
8199
8200 IO_STATUS_BLOCK ioStatus = {0};
8201 ULONG dataLength = sizeof(STORAGE_HW_FIRMWARE_INFO);
8202 ULONG iteration = 1;
8203
8204 CLASS_FUNCTION_SUPPORT oldState;
8205 KLOCK_QUEUE_HANDLE lockHandle;
8206
8207 //
8208 // Try to get firmware information that contains only one slot.
8209 // We will retry the query if the required buffer size is bigger than that.
8210 //
8211retry:
8212
8213 firmwareInfo = ExAllocatePoolWithTag(NonPagedPoolNx, dataLength, CLASSPNP_POOL_TAG_FIRMWARE);
8214
8215 if (firmwareInfo == NULL) {
8216 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClasspGetHwFirmwareInfo: cannot allocate memory to hold data. \n"));
8218 }
8219
8220 RtlZeroMemory(firmwareInfo, dataLength);
8221
8222 //
8223 // Set up query data, making sure the "Flags" field indicating the request is for device itself.
8224 //
8225 query = (PSTORAGE_HW_FIRMWARE_INFO_QUERY)firmwareInfo;
8226
8227 query->Version = sizeof(STORAGE_HW_FIRMWARE_INFO_QUERY);
8228 query->Size = sizeof(STORAGE_HW_FIRMWARE_INFO_QUERY);
8229 query->Flags = 0;
8230
8231 //
8232 // On the first pass we just want to get the first few
8233 // bytes of the descriptor so we can read it's size
8234 //
8236 commonExtension->LowerDeviceObject,
8237 query,
8238 sizeof(STORAGE_HW_FIRMWARE_INFO_QUERY),
8239 dataLength,
8240 FALSE,
8241 &ioStatus
8242 );
8243
8244 if (!NT_SUCCESS(ioStatus.Status) &&
8245 (ioStatus.Status != STATUS_BUFFER_OVERFLOW)) {
8246 if (ClasspLowerLayerNotSupport(ioStatus.Status)) {
8247 oldState = InterlockedCompareExchange((PLONG)(&fdoExtension->FunctionSupportInfo->HwFirmwareGetInfoSupport), (LONG)NotSupported, (ULONG)SupportUnknown);
8248 }
8249
8250 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClasspGetHwFirmwareInfo: error %lx trying to "
8251 "query hardware firmware information #%d \n", ioStatus.Status, iteration));
8252 FREE_POOL(firmwareInfo);
8253 return ioStatus.Status;
8254 }
8255
8256 //
8257 // Catch implementation issues from lower level driver.
8258 //
8259 if ((firmwareInfo->Version < sizeof(STORAGE_HW_FIRMWARE_INFO)) ||
8260 (firmwareInfo->Size < sizeof(STORAGE_HW_FIRMWARE_INFO)) ||
8261 (firmwareInfo->SlotCount == 0) ||
8262 (firmwareInfo->ImagePayloadMaxSize > fdoExtension->AdapterDescriptor->MaximumTransferLength)) {
8263
8264 oldState = InterlockedCompareExchange((PLONG)(&fdoExtension->FunctionSupportInfo->HwFirmwareGetInfoSupport), (LONG)NotSupported, (ULONG)SupportUnknown);
8265
8266 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClasspGetHwFirmwareInfo: error in returned data! "
8267 "Version: 0x%X, Size: 0x%X, SlotCount: 0x%X, ActiveSlot: 0x%X, PendingActiveSlot: 0x%X, ImagePayloadMaxSize: 0x%X \n",
8268 firmwareInfo->Version,
8269 firmwareInfo->Size,
8270 firmwareInfo->SlotCount,
8271 firmwareInfo->ActiveSlot,
8272 firmwareInfo->PendingActivateSlot,
8273 firmwareInfo->ImagePayloadMaxSize));
8274
8275 FREE_POOL(firmwareInfo);
8276 return STATUS_UNSUCCESSFUL;
8277 }
8278
8279 //
8280 // If the data size is bigger than sizeof(STORAGE_HW_FIRMWARE_INFO), e.g. device has more than one firmware slot,
8281 // allocate a buffer to get all the data.
8282 //
8283 if ((firmwareInfo->Size > sizeof(STORAGE_HW_FIRMWARE_INFO)) &&
8284 (iteration < 2)) {
8285
8286 dataLength = max(firmwareInfo->Size, sizeof(STORAGE_HW_FIRMWARE_INFO) + sizeof(STORAGE_HW_FIRMWARE_SLOT_INFO) * (firmwareInfo->SlotCount - 1));
8287
8288 //
8289 // Retry the query with required buffer length.
8290 //
8291 FREE_POOL(firmwareInfo);
8292 iteration++;
8293 goto retry;
8294 }
8295
8296
8297 //
8298 // Set the support status and use the memory we've allocated as caching buffer.
8299 // In case of a competing thread already set the state, it will assign the caching buffer so release the current allocated one.
8300 //
8301 KeAcquireInStackQueuedSpinLock(&fdoExtension->FunctionSupportInfo->SyncLock, &lockHandle);
8302
8303 oldState = InterlockedCompareExchange((PLONG)(&fdoExtension->FunctionSupportInfo->HwFirmwareGetInfoSupport), (LONG)Supported, (ULONG)SupportUnknown);
8304
8305 if (oldState == SupportUnknown) {
8306 fdoExtension->FunctionSupportInfo->HwFirmwareInfo = firmwareInfo;
8307 } else if (oldState == Supported) {
8308 //
8309 // swap the buffers to keep the latest version.
8310 //
8311 PSTORAGE_HW_FIRMWARE_INFO cachedInfo = fdoExtension->FunctionSupportInfo->HwFirmwareInfo;
8312
8313 fdoExtension->FunctionSupportInfo->HwFirmwareInfo = firmwareInfo;
8314
8315 FREE_POOL(cachedInfo);
8316 } else {
8317 FREE_POOL(firmwareInfo);
8318 }
8319
8320 KeReleaseInStackQueuedSpinLock(&lockHandle);
8321
8322 return ioStatus.Status;
8323} // end ClasspGetHwFirmwareInfo()
8324
8325#endif // #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
8326
8327#ifndef __REACTOS__ // the functions is not used
8328__inline
8329BOOLEAN
8332 )
8333/*
8334Routine Description:
8335
8336 This function informs the caller whether the port driver supports hardware firmware requests.
8337
8338Arguments:
8339 DeviceObject: The target object.
8340
8341Return Value:
8342
8343 TRUE if the port driver is supported.
8344
8345--*/
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}
8363#endif
8364
8369 )
8370/*
8371Routine Description:
8372
8373 This function processes the Storage Hardware Firmware Get Information request.
8374 If the information is not cached yet, it gets from lower level driver.
8375
8376Arguments:
8377 DeviceObject: The target FDO.
8378 Irp: The IRP which will contain the output buffer upon completion.
8379
8380Return Value:
8381
8382 NTSTATUS code.
8383
8384--*/
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}
8499
8500
8501#if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
8505ClassHwFirmwareDownloadComplete (
8507 _In_ PIRP Irp,
8508 _In_reads_opt_(_Inexpressible_("varies")) PVOID Context
8509 )
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()
8537#endif // #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
8538
8539
8545 )
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}
8900
8906 )
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}
9124
9125
9126BOOLEAN
9129 )
9130/*++
9131
9132Routine Description:
9133
9134 This routine checks whether the completed SRB Srb was completed with a thin provisioning
9135 soft threshold error.
9136
9137Arguments:
9138
9139 Srb - the SRB to be checked.
9140
9141Return Value:
9142
9143 BOOLEAN
9144
9145--*/
9146{
9148 PVOID senseBuffer = SrbGetSenseInfoBuffer(Srb);
9149 if (senseBuffer) {
9150 UCHAR senseKey = 0;
9151 UCHAR addlSenseCode = 0;
9152 UCHAR addlSenseCodeQual = 0;
9153 BOOLEAN validSense = ScsiGetSenseKeyAndCodes(senseBuffer,
9156 &senseKey,
9157 &addlSenseCode,
9158 &addlSenseCodeQual);
9159
9160 return (validSense
9162 && (addlSenseCode == SCSI_ADSENSE_LB_PROVISIONING)
9163 && (addlSenseCodeQual == SCSI_SENSEQ_SOFT_THRESHOLD_REACHED));
9164 }
9165 }
9166 return FALSE;
9167}
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
#define PAGED_CODE()
#define ALIGN_DOWN_BY(size, align)
#define ALIGN_UP_BY(size, align)
unsigned char BOOLEAN
static int iteration
Definition: StackOverflow.c:16
Type
Definition: Type.h:7
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
#define VOID
Definition: acefi.h:82
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedExchange
Definition: armddk.h:54
#define InterlockedDecrement
Definition: armddk.h:52
LONG NTSTATUS
Definition: precomp.h:26
#define MIN(x, y)
Definition: rdesktop.h:171
#define MAX(x, y)
Definition: rdesktop.h:175
@ Reserved2
Definition: bcd.h:202
@ Reserved1
Definition: bcd.h:201
_In_ PFCB _In_ LONGLONG StartingOffset
Definition: cdprocs.h:291
_In_ PSCSI_REQUEST_BLOCK Srb
Definition: cdrom.h:989
_In_opt_ PWSTR _In_ PWSTR ParameterName
Definition: cdrom.h:961
#define FREE_POOL(_PoolPtr)
Definition: cdrom.h:782
#define DEV_POWER_PROTECTED
Definition: cdrom.h:143
_In_opt_ PWSTR _In_ PWSTR _Inout_ PULONG ParameterValue
Definition: cdrom.h:963
_In_ PSCSI_REQUEST_BLOCK _In_opt_ PVOID _In_ ULONG _In_ BOOLEAN WriteToDevice
Definition: cdrom.h:992
_In_ CDROM_SCAN_FOR_SPECIAL_INFO _In_ PCDROM_SCAN_FOR_SPECIAL_HANDLER Function
Definition: cdrom.h:1156
_In_opt_ PWSTR SubkeyName
Definition: cdrom.h:960
_In_z_ PCHAR TargetString
Definition: cdrom.h:954
#define TEST_FLAG(Flags, Bit)
Definition: cdrom.h:1495
#define CLEAR_FLAG(Flags, Bit)
Definition: cdrom.h:1494
#define SET_FLAG(Flags, Bit)
Definition: cdrom.h:1493
#define CLASS_ERROR_LEVEL_2
Definition: cdromp.h:131
#define MODE_PAGE_DATA_SIZE
Definition: cdromp.h:376
#define CLASS_ERROR_LEVEL_1
Definition: cdromp.h:130
#define CDB10GENERIC_LENGTH
Definition: cdrw_hw.h:831
#define SCSIOP_INQUIRY
Definition: cdrw_hw.h:888
#define MODE_DSP_FUA_SUPPORTED
Definition: cdrw_hw.h:2522
#define MODE_SENSE_CHANGEABLE_VALUES
Definition: cdrw_hw.h:860
#define SCSIOP_WRITE_DATA_BUFF
Definition: cdrw_hw.h:922
#define MODE_PAGE_CACHING
Definition: cdrw_hw.h:846
#define SCSI_SENSE_UNIT_ATTENTION
Definition: cdrw_hw.h:1193
#define SCSIOP_SYNCHRONIZE_CACHE
Definition: cdrw_hw.h:918
#define SCSIOP_LOG_SENSE
Definition: cdrw_hw.h:937
Definition: bufpool.h:45
#define CLASSPNP_POOL_TAG_LOG_MESSAGE
Definition: classp.h:196
NTSTATUS InitializeStorageRequestBlock(_Inout_bytecount_(ByteSize) PSTORAGE_REQUEST_BLOCK Srb, _In_ USHORT AddressType, _In_ ULONG ByteSize, _In_ ULONG NumSrbExData,...)
Definition: srblib.c:206
struct _OPCODE_SENSE_DATA_IO_LOG_MESSAGE_CONTEXT_HEADER * POPCODE_SENSE_DATA_IO_LOG_MESSAGE_CONTEXT_HEADER
IO_WORKITEM_ROUTINE ClassLogResourceExhaustionEvent
Definition: classp.h:2306
_In_z_ PWSTR _Out_ PULONG MaximumListIdentifier
Definition: classp.h:1932
#define MAX_TOKEN_OPERATION_PARAMETER_DATA_LENGTH
Definition: classp.h:207
#define REG_MAX_LIST_IDENTIFIER_VALUE
Definition: classp.h:219
_In_ PVOID _Inout_ PULONG _In_ ULONG MaxBlockDescrCount
Definition: classp.h:1998
FORCEINLINE BOOLEAN ClasspSupportsUnmap(_In_ PCLASS_FUNCTION_SUPPORT_INFO SupportInfo)
Definition: classp.h:1308
_In_ PTRANSFER_PACKET Pkt
Definition: classp.h:1754
#define MAX_NUMBER_BLOCKS_PER_BLOCK_DEVICE_RANGE_DESCRIPTOR
Definition: classp.h:210
#define CLASSPNP_POOL_TAG_TOKEN_OPERATION
Definition: classp.h:193
struct _IO_RETRIED_LOG_MESSAGE_CONTEXT * PIO_RETRIED_LOG_MESSAGE_CONTEXT
IO_WORKITEM_ROUTINE ClassLogThresholdEvent
Definition: classp.h:2298
FORCEINLINE BOOLEAN ClasspLowerLayerNotSupport(_In_ NTSTATUS Status)
Definition: classp.h:2638
FORCEINLINE BOOLEAN ClasspIsObsoletePortDriver(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: classp.h:1335
#define MAX_RECEIVE_TOKEN_INFORMATION_PARAMETER_DATA_LENGTH
Definition: classp.h:208
_In_ PVOID _Inout_ PULONG _In_ ULONG _Inout_ PULONG _In_ ULONGLONG _Inout_ PDEVICE_DATA_SET_RANGE _Inout_ PULONGLONG TotalSectorsProcessed
Definition: classp.h:2003
#define MAX_TOKEN_TRANSFER_SIZE
Definition: classp.h:209
IO_WORKITEM_ROUTINE ClasspLogIOEventWithContext
Definition: classp.h:1905
_In_ PVOID BlockDescr
Definition: classp.h:1996
FORCEINLINE BOOLEAN ClasspIsThinProvisioned(_In_ PCLASS_FUNCTION_SUPPORT_INFO SupportInfo)
Definition: classp.h:1317
#define CLASSPNP_POOL_TAG_FIRMWARE
Definition: classp.h:198
_In_ PVOID _Inout_ PULONG _In_ ULONG _Inout_ PULONG _In_ ULONGLONG MaxLbaCount
Definition: classp.h:2000
#define GET_LBA_STATUS_RETRY_COUNT_MAX
Definition: classp.h:229
_In_z_ PWSTR _Out_ PULONG MaxDuration
Definition: classp.h:1940
#define DEFAULT_MAX_TARGET_DURATION
Definition: classp.h:211
#define CLASSP_REG_COPY_OFFLOAD_MAX_TARGET_DURATION
Definition: classp.h:128
_In_ PVOID _Inout_ PULONG CurrentBlockDescrIndex
Definition: classp.h:1997
_In_ PVOID _Inout_ PULONG _In_ ULONG _Inout_ PULONG _In_ ULONGLONG _Inout_ PDEVICE_DATA_SET_RANGE DataSetRange
Definition: classp.h:2001
_In_ PVOID _Inout_ PULONG _In_ ULONG _Inout_ PULONG CurrentLbaCount
Definition: classp.h:1999
VOID NTAPI ClassCheckMediaState(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: autorun.c:1752
#define CLASS_TAG_MODE_DATA
Definition: classpnp.h:86
#define CLASS_SPECIAL_FUA_NOT_SUPPORTED
Definition: classpnp.h:174
#define CLASS_TAG_LB_PROVISIONING
Definition: classpnp.h:89
#define ClassAcquireRemoveLock(devobj, tag)
Definition: classpnp.h:100
struct _FUNCTIONAL_DEVICE_EXTENSION * PFUNCTIONAL_DEVICE_EXTENSION
#define CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE
Definition: classpnp.h:695
CLASS_FUNCTION_SUPPORT
Definition: classpnp.h:731
@ Supported
Definition: classpnp.h:733
@ SupportUnknown
Definition: classpnp.h:732
@ 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)
_In_ PIRP Irp
Definition: csq.h:116
static PDB_INFORMATION information
Definition: db.cpp:178
UINT sectorCount[1]
Definition: diskio.c:16
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
PDEVICE_LIST DeviceList
Definition: utils.c:27
struct _COMMON_DEVICE_EXTENSION * PCOMMON_DEVICE_EXTENSION
PVOID NTAPI ClassFindModePage(_In_reads_bytes_(Length) PCHAR ModeSenseBuffer, _In_ ULONG Length, _In_ UCHAR PageMode, _In_ BOOLEAN Use6Byte)
Definition: class.c:6798
ULONG NTAPI ClassModeSense(_In_ PDEVICE_OBJECT Fdo, _In_reads_bytes_(Length) PCHAR ModeSenseBuffer, _In_ ULONG Length, _In_ UCHAR PageMode)
Definition: class.c:6637
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
NTSTATUS ClasspBlockLimitsDataSnapshot(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _In_ BOOLEAN ForceQuery, _Out_ PCLASS_VPD_B0_DATA BlockLimitsData, _Out_ PULONG GenerationCount)
Definition: class.c:16504
NTSTATUS ClasspModeSelect(_In_ PDEVICE_OBJECT Fdo, _In_reads_bytes_(Length) PCHAR ModeSelectBuffer, _In_ ULONG Length, _In_ BOOLEAN SavePages)
Definition: class.c:6919
ULONG ClasspModeSense(_In_ PDEVICE_OBJECT Fdo, _In_reads_bytes_(Length) PCHAR ModeSenseBuffer, _In_ ULONG Length, _In_ UCHAR PageMode, _In_ UCHAR PageControl)
Definition: class.c:6681
VOID NTAPI ClassSendDeviceIoControlSynchronous(_In_ ULONG IoControlCode, _In_ PDEVICE_OBJECT TargetDeviceObject, _Inout_updates_opt_(_Inexpressible_(max(InputBufferLength, OutputBufferLength))) PVOID Buffer, _In_ ULONG InputBufferLength, _In_ ULONG OutputBufferLength, _In_ BOOLEAN InternalDeviceIoControl, _Out_ PIO_STATUS_BLOCK IoStatus)
Definition: class.c:11065
_Must_inspect_result_ NTSTATUS NTAPI ClassReadDriveCapacity(_In_ PDEVICE_OBJECT Fdo)
Definition: class.c:2742
NTSTATUS NTAPI ClassForwardIrpSynchronous(_In_ PCOMMON_DEVICE_EXTENSION CommonExtension, _In_ PIRP Irp)
Definition: class.c:11343
VOID NTAPI ClassCompleteRequest(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ CCHAR PriorityBoost)
Definition: lock.c:401
VOID NTAPI ClassReleaseRemoveLock(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PIRP Tag)
Definition: lock.c:251
VOID ClassQueueResourceExhaustionEventWorker(_In_ PDEVICE_OBJECT DeviceObject)
Definition: utils.c:5528
NTSTATUS ClasspDeviceLBProvisioningProperty(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:2894
_IRQL_requires_same_ NTSTATUS ClasspGetTokenOperationDescriptorLimits(_In_ PDEVICE_OBJECT Fdo, _In_ ULONG ServiceAction, _In_ ULONG MaxParameterBufferLength, _Out_ PULONG MaxBlockDescriptorsCount, _Out_ PULONGLONG MaxBlockDescriptorsLength)
Definition: utils.c:7472
NTSTATUS ClasspDuidGetDeviceProperty(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: utils.c:782
NTSTATUS ClasspDuidGetDriveLayout(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: utils.c:875
NTSTATUS ClasspWriteCacheProperty(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:1199
NTSTATUS ClasspDeviceTrimProcess(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PGUID ActivityId, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:3476
VOID ClasspZeroQERR(_In_ PDEVICE_OBJECT DeviceObject)
Definition: utils.c:7938
VOID ClassQueueCapacityChangedEventWorker(_In_ PDEVICE_OBJECT DeviceObject)
Definition: utils.c:5637
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)
Definition: utils.c:6010
_IRQL_requires_same_ NTSTATUS ClasspStorageEventNotification(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp)
Definition: utils.c:7826
VOID ClasspFreeDeviceMdl(PMDL Mdl)
Definition: utils.c:615
NTSTATUS ClassDeviceHwFirmwareDownloadProcess(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:8541
NTSTATUS ClasspDeviceGetLBAStatus(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:3861
VOID FreeDeviceInputMdl(PMDL Mdl)
Definition: utils.c:622
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 ClasspPersistentReserve(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:6211
NTSTATUS InterpretReadCapacity16Data(_Inout_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _In_ PREAD_CAPACITY16_DATA ReadCapacity16Data)
Definition: utils.c:1517
ULONG ClasspCalculateLogicalSectorSize(_In_ PDEVICE_OBJECT Fdo, _In_ ULONG BytesPerBlockInBigEndian)
Definition: utils.c:1483
_IRQL_requires_same_ PUCHAR ClasspBinaryToAscii(_In_reads_(Length) PUCHAR HexBuffer, _In_ ULONG Length, _Inout_ PULONG UpdateLength)
Definition: utils.c:7717
VOID ClasspPerfIncrementSuccessfulIo(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: utils.c:486
NTSTATUS ClasspDuidQueryProperty(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: utils.c:997
NTSTATUS ClasspLogSystemEventWithDeviceNumber(_In_ PDEVICE_OBJECT DeviceObject, _In_ NTSTATUS IoErrorCode)
Definition: utils.c:5354
NTSTATUS ClasspAccessAlignmentProperty(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:1700
NTSTATUS ClasspGetHwFirmwareInfo(_In_ PDEVICE_OBJECT DeviceObject)
Definition: utils.c:8190
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
_IRQL_requires_same_ NTSTATUS ClasspGetTokenOperationCommandBufferLength(_In_ PDEVICE_OBJECT Fdo, _In_ ULONG ServiceAction, _Inout_ PULONG CommandBufferLength, _Out_opt_ PULONG TokenOperationBufferLength, _Out_opt_ PULONG ReceiveTokenInformationBufferLength)
Definition: utils.c:7356
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
PMDL ClasspBuildDeviceMdl(PVOID Buffer, ULONG BufferLen, BOOLEAN WriteToDevice)
Definition: utils.c:582
NTSTATUS ClasspDeviceGetLBProvisioningVPDPage(_In_ PDEVICE_OBJECT DeviceObject, _Inout_opt_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:2350
NTSTATUS ClasspDeviceGetBlockDeviceCharacteristicsVPDPage(_In_ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension, _In_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:2072
static BOOLEAN ValidPersistentReserveScope(UCHAR Scope)
Definition: utils.c:6152
BOOLEAN ClasspIsThinProvisioningError(_In_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:9127
NTSTATUS ClassDeviceHwFirmwareGetInfoProcess(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
Definition: utils.c:8366
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
static BOOLEAN ValidPersistentReserveType(UCHAR Type)
Definition: utils.c:6171
NTSTATUS ClasspPriorityHint(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: utils.c:6480
#define FIRMWARE_ACTIVATE_TIMEOUT_VALUE
Definition: utils.c:37
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
BOOLEAN ClasspMyStringMatches(_In_opt_z_ PCHAR StringToMatch, _In_z_ PCHAR TargetString)
Definition: utils.c:51
NTSTATUS ClasspDeviceSeekPenaltyProperty(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:2172
__inline BOOLEAN ClassDeviceHwFirmwareIsPortDriverSupported(_In_ PDEVICE_OBJECT DeviceObject)
Definition: utils.c:8330
NTSTATUS ClasspDeviceTrimProperty(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:2730
PMDL BuildDeviceInputMdl(PVOID Buffer, ULONG BufferLen)
Definition: utils.c:609
VOID ClassQueueThresholdEventWorker(_In_ PDEVICE_OBJECT DeviceObject)
Definition: utils.c:5471
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)
Definition: utils.c:3047
NTSTATUS ClasspDeviceGetBlockLimitsVPDPage(_In_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _Inout_bytecount_(SrbSize) PSCSI_REQUEST_BLOCK Srb, _In_ ULONG SrbSize, _Out_ PCLASS_VPD_B0_DATA BlockLimitsData)
Definition: utils.c:2521
VOID ClassQueueProvisioningTypeChangedEventWorker(_In_ PDEVICE_OBJECT DeviceObject)
Definition: utils.c:5726
NTSTATUS ClassReadCapacity16(_Inout_ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:1568
NTSTATUS ClassDeviceGetLBProvisioningResources(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:5087
NTSTATUS ClassDeviceHwFirmwareActivateProcess(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:8902
VOID ClasspPerfIncrementErrorCount(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: utils.c:432
VOID ClasspConvertToScsiRequestBlock(_Out_ PSCSI_REQUEST_BLOCK Srb, _In_ PSTORAGE_REQUEST_BLOCK SrbEx)
Definition: utils.c:6559
NTSTATUS ClasspDuidGetDeviceIdProperty(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: utils.c:689
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
static NTSTATUS IncursSeekPenalty(_In_ USHORT MediumRotationRate, _In_ PBOOLEAN IncursSeekPenalty)
Definition: utils.c:1888
NTSTATUS ClasspDeviceMediaTypeProperty(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp, _Inout_ PSCSI_REQUEST_BLOCK Srb)
Definition: utils.c:1917
struct _READ_CAPACITY16_DATA READ_CAPACITY16_DATA
struct _READ_CAPACITY16_DATA * PREAD_CAPACITY16_DATA
#define SRB_FUNCTION_WMI
Definition: srb.h:331
struct _SCSI_REQUEST_BLOCK SCSI_REQUEST_BLOCK
#define SP_UNTAGGED
Definition: srb.h:233
#define SRB_FUNCTION_EXECUTE_SCSI
Definition: srb.h:315
#define SRB_FLAGS_DATA_OUT
Definition: srb.h:401
#define SRB_FLAGS_DISABLE_DISCONNECT
Definition: srb.h:396
#define SRB_SIMPLE_TAG_REQUEST
Definition: srb.h:423
#define SRB_FLAGS_QUEUE_ACTION_ENABLE
Definition: srb.h:395
#define SRB_STATUS_AUTOSENSE_VALID
Definition: srb.h:387
#define SRB_HEAD_OF_QUEUE_TAG_REQUEST
Definition: srb.h:424
#define SRB_FLAGS_DATA_IN
Definition: srb.h:400
struct _SCSI_WMI_REQUEST_BLOCK * PSCSI_WMI_REQUEST_BLOCK
#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER
Definition: srb.h:397
#define SRB_FLAGS_NO_QUEUE_FREEZE
Definition: srb.h:404
@ FdoExtension
Definition: precomp.h:48
#define _IRQL_requires_same_
Definition: driverspecs.h:232
#define _IRQL_requires_min_(irql)
Definition: driverspecs.h:231
#define _IRQL_requires_max_(irql)
Definition: driverspecs.h:230
#define _IRQL_requires_(irql)
Definition: driverspecs.h:229
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
struct _FOUR_BYTE * PFOUR_BYTE
NTSTATUS NTAPI IoReadPartitionTableEx(IN PDEVICE_OBJECT DeviceObject, IN PDRIVE_LAYOUT_INFORMATION_EX *DriveLayout)
Definition: fstubex.c:2279
FxCmResList * resources
MDL * mdl
#define IoFreeMdl
Definition: fxmdl.h:89
#define IoAllocateMdl
Definition: fxmdl.h:88
PVOID dataBuffer
FxIrp * irp
size_t bufferSize
GLsizeiptr size
Definition: glext.h:5919
struct _cl_event * event
Definition: glext.h:7739
GLuint buffer
Definition: glext.h:5915
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLintptr offset
Definition: glext.h:5920
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
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
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
static ULONG ResourceCount
Definition: inbv.c:50
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define RtlFillMemory(Dest, Length, Fill)
Definition: winternl.h:599
NTSYSAPI NTSTATUS WINAPI RtlWriteRegistryValue(ULONG, PCWSTR, PCWSTR, ULONG, PVOID, ULONG)
NTSYSAPI NTSTATUS WINAPI RtlQueryRegistryValues(ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID)
#define InterlockedCompareExchange
Definition: interlocked.h:104
VOID NTAPI IoQueueWorkItem(IN PIO_WORKITEM IoWorkItem, IN PIO_WORKITEM_ROUTINE WorkerRoutine, IN WORK_QUEUE_TYPE QueueType, IN PVOID Context)
Definition: iowork.c:40
VOID NTAPI IoFreeWorkItem(IN PIO_WORKITEM IoWorkItem)
Definition: iowork.c:64
PIO_WORKITEM NTAPI IoAllocateWorkItem(IN PDEVICE_OBJECT DeviceObject)
Definition: iowork.c:75
#define Add2Ptr(PTR, INC)
IoMarkIrpPending(Irp)
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:490
if(dx< 0)
Definition: linetemp.h:194
#define PCHAR
Definition: match.c:90
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
VOID NTAPI MmProbeAndLockPages(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN LOCK_OPERATION Operation)
Definition: mdlsup.c:931
VOID NTAPI MmUnlockPages(IN PMDL Mdl)
Definition: mdlsup.c:1435
@ PARTITION_STYLE_GPT
Definition: imports.h:202
@ PARTITION_STYLE_MBR
Definition: imports.h:201
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
static char * dest
Definition: rtl.c:135
#define min(a, b)
Definition: monoChain.cc:55
#define _Function_class_(x)
Definition: ms_sal.h:2946
#define _Out_opt_
Definition: ms_sal.h:346
#define _Inout_
Definition: ms_sal.h:378
#define _In_z_
Definition: ms_sal.h:313
#define _In_opt_z_
Definition: ms_sal.h:314
#define _Inout_opt_
Definition: ms_sal.h:379
#define _Out_
Definition: ms_sal.h:345
#define _In_reads_opt_(size)
Definition: ms_sal.h:320
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
#define _Inout_bytecount_(size)
Definition: ms_sal.h:936
#define _Analysis_assume_(expr)
Definition: ms_sal.h:2901
#define _In_reads_(size)
Definition: ms_sal.h:319
_In_ NDIS_ERROR_CODE ErrorCode
Definition: ndis.h:4436
#define KernelMode
Definition: asm.h:34
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_REGISTRY_ABSOLUTE
Definition: nt_native.h:161
#define RTL_QUERY_REGISTRY_REQUIRED
Definition: nt_native.h:132
#define RTL_QUERY_REGISTRY_DIRECT
Definition: nt_native.h:144
#define FILE_FLOPPY_DISKETTE
Definition: nt_native.h:809
#define KEY_WRITE
Definition: nt_native.h:1031
#define REG_NONE
Definition: nt_native.h:1492
#define RTL_REGISTRY_HANDLE
Definition: nt_native.h:168
__GNU_EXTENSION typedef unsigned __int64 * PULONGLONG
Definition: ntbasedef.h:383
#define RTL_SIZEOF_THROUGH_FIELD(type, field)
Definition: ntbasedef.h:672
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
struct _DEVICE_DATA_SET_LB_PROVISIONING_STATE DEVICE_DATA_SET_LB_PROVISIONING_STATE
@ WriteThroughSupported
Definition: ntddstor.h:885
@ WriteThroughNotSupported
Definition: ntddstor.h:884
#define DEVICE_DATA_SET_LB_PROVISIONING_STATE_VERSION_V1
Definition: ntddstor.h:939
* PSTORAGE_DESCRIPTOR_HEADER
Definition: ntddstor.h:560
#define IOCTL_STORAGE_POWER_IDLE
Definition: ntddstor.h:223
enum _STORAGE_PROPERTY_ID STORAGE_PROPERTY_ID
STORAGE_DESCRIPTOR_HEADER
Definition: ntddstor.h:560
#define IOCTL_STORAGE_POWER_ACTIVE
Definition: ntddstor.h:220
#define STORAGE_EVENT_NOTIFICATION_VERSION_V1
Definition: ntddstor.h:979
#define DeviceDsmAction_Allocation
Definition: ntddstor.h:280
#define DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE
Definition: ntddstor.h:306
* PSTORAGE_WRITE_CACHE_PROPERTY
Definition: ntddstor.h:898
struct _DEVICE_SEEK_PENALTY_DESCRIPTOR DEVICE_SEEK_PENALTY_DESCRIPTOR
@ WriteCacheChangeUnknown
Definition: ntddstor.h:877
@ WriteCacheChangeable
Definition: ntddstor.h:879
@ WriteCacheNotChangeable
Definition: ntddstor.h:878
#define DEVICE_DSM_FLAG_TRIM_NOT_FS_ALLOCATED
Definition: ntddstor.h:764
struct _DEVICE_SEEK_PENALTY_DESCRIPTOR * PDEVICE_SEEK_PENALTY_DESCRIPTOR
@ WriteCacheTypeWriteBack
Definition: ntddstor.h:866
@ WriteCacheTypeUnknown
Definition: ntddstor.h:864
struct _DEVICE_COPY_OFFLOAD_DESCRIPTOR DEVICE_COPY_OFFLOAD_DESCRIPTOR
struct _DEVICE_COPY_OFFLOAD_DESCRIPTOR * PDEVICE_COPY_OFFLOAD_DESCRIPTOR
struct _DEVICE_DATA_SET_RANGE * PDEVICE_DATA_SET_RANGE
struct _STORAGE_LB_PROVISIONING_MAP_RESOURCES STORAGE_LB_PROVISIONING_MAP_RESOURCES
#define DEVICE_DSM_FLAG_ALLOCATION_CONSOLIDATEABLE_ONLY
Definition: ntddstor.h:963
STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR
Definition: ntddstor.h:609
STORAGE_MEDIUM_PRODUCT_TYPE_DESCRIPTOR
Definition: ntddstor.h:615
#define IOCTL_STORAGE_PERSISTENT_RESERVE_IN
Definition: ntddstor.h:169
struct _DEVICE_LB_PROVISIONING_DESCRIPTOR * PDEVICE_LB_PROVISIONING_DESCRIPTOR
struct _STORAGE_PRIORITY_HINT_SUPPORT STORAGE_PRIORITY_HINT_SUPPORT
* PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR
Definition: ntddstor.h:609
* PSTORAGE_DEVICE_DESCRIPTOR
Definition: ntddstor.h:576
struct _DEVICE_MANAGE_DATA_SET_ATTRIBUTES * PDEVICE_MANAGE_DATA_SET_ATTRIBUTES
@ StorageDeviceIdProperty
Definition: ntddstor.h:514
#define STORAGE_EVENT_MEDIA_STATUS
Definition: ntddstor.h:981
struct _DEVICE_DATA_SET_LB_PROVISIONING_STATE_V2 * PDEVICE_DATA_SET_LB_PROVISIONING_STATE_V2
#define IOCTL_STORAGE_FIRMWARE_GET_INFO
Definition: ntddstor.h:205
struct _STORAGE_PROPERTY_QUERY * PSTORAGE_PROPERTY_QUERY
struct _DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT DEVICE_MANAGE_DATA_SET_ATTRIBUTES_OUTPUT
struct _DEVICE_TRIM_DESCRIPTOR DEVICE_TRIM_DESCRIPTOR
struct _DEVICE_LB_PROVISIONING_DESCRIPTOR DEVICE_LB_PROVISIONING_DESCRIPTOR
@ WriteCacheEnableUnknown
Definition: ntddstor.h:871
@ WriteCacheDisabled
Definition: ntddstor.h:872
@ WriteCacheEnabled
Definition: ntddstor.h:873
#define DEVICE_LB_PROVISIONING_DESCRIPTOR_V1_SIZE
Definition: ntddstor.h:661
@ PropertyExistsQuery
Definition: ntddstor.h:506
@ PropertyStandardQuery
Definition: ntddstor.h:505
struct _STORAGE_LB_PROVISIONING_MAP_RESOURCES * PSTORAGE_LB_PROVISIONING_MAP_RESOURCES
struct _DEVICE_TRIM_DESCRIPTOR * PDEVICE_TRIM_DESCRIPTOR
@ StoragePortCodeSetStorport
Definition: ntddstor.h:619
@ StoragePortCodeSetSpaceport
Definition: ntddstor.h:621
@ StoragePortCodeSetSDport
Definition: ntddstor.h:625
#define DEVICE_DATA_SET_LB_PROVISIONING_STATE_VERSION_V2
Definition: ntddstor.h:953
STORAGE_WRITE_CACHE_PROPERTY
Definition: ntddstor.h:898
struct _DEVICE_DATA_SET_RANGE DEVICE_DATA_SET_RANGE
* PSTORAGE_MEDIUM_PRODUCT_TYPE_DESCRIPTOR
Definition: ntddstor.h:615
* PSTORAGE_DEVICE_ID_DESCRIPTOR
Definition: ntddstor.h:742
* PSTORAGE_ADAPTER_DESCRIPTOR
Definition: ntddstor.h:599
struct _DEVICE_DATA_SET_LB_PROVISIONING_STATE_V2 DEVICE_DATA_SET_LB_PROVISIONING_STATE_V2
@ SynchronizationEvent
#define IoCopyCurrentIrpStackLocationToNext(Irp)
Definition: ntifs_ex.h:413
#define IO_WARNING_SOFT_THRESHOLD_REACHED_EX_LUN_POOL
Definition: ntiologc.h:108
#define IO_ERROR_DISK_RESOURCES_EXHAUSTED
Definition: ntiologc.h:111
#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_IO_OPERATION_RETRIED
Definition: ntiologc.h:114
#define IO_WARNING_SOFT_THRESHOLD_REACHED_EX_POOL_LUN
Definition: ntiologc.h:109
#define IO_ERROR_IO_HARDWARE_ERROR
Definition: ntiologc.h:115
#define IO_WARNING_DISK_CAPACITY_CHANGED
Definition: ntiologc.h:112
#define IO_WARNING_SOFT_THRESHOLD_REACHED_EX_LUN_LUN
Definition: ntiologc.h:107
#define IO_WARNING_SOFT_THRESHOLD_REACHED
Definition: ntiologc.h:105
#define IO_WARNING_DISK_PROVISIONING_TYPE_CHANGED
Definition: ntiologc.h:113
VOID NTAPI IoWriteErrorLogEntry(IN PVOID ElEntry)
Definition: error.c:628
PVOID NTAPI IoAllocateErrorLogEntry(IN PVOID IoObject, IN UCHAR EntrySize)
Definition: error.c:528
PIRP NTAPI IoAllocateIrp(IN CCHAR StackSize, IN BOOLEAN ChargeQuota)
Definition: irp.c:615
PIRP NTAPI IoBuildDeviceIoControlRequest(IN ULONG IoControlCode, IN PDEVICE_OBJECT DeviceObject, IN PVOID InputBuffer, IN ULONG InputBufferLength, IN PVOID OutputBuffer, IN ULONG OutputBufferLength, IN BOOLEAN InternalDeviceIoControl, IN PKEVENT Event, IN PIO_STATUS_BLOCK IoStatusBlock)
Definition: irp.c:881
#define IoCallDriver
Definition: irp.c:1225
VOID NTAPI IoFreeIrp(IN PIRP Irp)
Definition: irp.c:1666
ULONG NTAPI KeGetRecommendedSharedDataAlignment(VOID)
Definition: cpu.c:710
#define STATUS_INTERNAL_ERROR
Definition: ntstatus.h:465
#define STATUS_TRIM_READ_ZERO_NOT_SUPPORTED
Definition: ntstatus.h:1000
#define STATUS_PENDING
Definition: ntstatus.h:82
#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_NOT_IMPLEMENTED
Definition: ntstatus.h:239
#define STATUS_INVALID_PARAMETER_1
Definition: ntstatus.h:475
#define STATUS_DATA_ERROR
Definition: ntstatus.h:298
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
unsigned short USHORT
Definition: pedump.c:61
NTSTATUS NTAPI IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject, IN ULONG DevInstKeyType, IN ACCESS_MASK DesiredAccess, OUT PHANDLE DevInstRegKey)
Definition: pnpmgr.c:1621
NTSTATUS NTAPI IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject, IN DEVICE_REGISTRY_PROPERTY DeviceProperty, IN ULONG BufferLength, OUT PVOID PropertyBuffer, OUT PULONG ResultLength)
Definition: pnpmgr.c:1382
#define FILE_DEVICE_DISK
Definition: winioctl.h:113
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
_In_opt_ WDFREQUEST _In_ ULONG _In_ BOOLEAN _In_ PCDB Cdb
Definition: scratch.h:159
#define REG_DWORD
Definition: sdbapi.c:596
#define VPD_BLOCK_DEVICE_CHARACTERISTICS
Definition: scsi.h:2417
#define VPD_MAX_BUFFER_SIZE
Definition: scsi.h:2402
struct _LOG_PAGE_LOGICAL_BLOCK_PROVISIONING * PLOG_PAGE_LOGICAL_BLOCK_PROVISIONING
struct _LBA_STATUS_LIST_HEADER LBA_STATUS_LIST_HEADER
#define RESERVATION_ACTION_REGISTER
Definition: scsi.h:579
#define VPD_LOGICAL_BLOCK_PROVISIONING
Definition: scsi.h:2418
struct _VPD_LOGICAL_BLOCK_PROVISIONING_PAGE * PVPD_LOGICAL_BLOCK_PROVISIONING_PAGE
#define LOG_PAGE_CODE_LOGICAL_BLOCK_PROVISIONING
Definition: scsi.h:3262
struct _LOG_PARAMETER_HEADER LOG_PARAMETER_HEADER
#define SERVICE_ACTION_GET_LBA_STATUS
Definition: scsi.h:475
#define LBA_STATUS_MAPPED
Definition: scsi.h:2786
#define RESERVATION_SCOPE_ELEMENT
Definition: scsi.h:588
#define RESERVATION_SCOPE_LU
Definition: scsi.h:587
#define RESERVATION_ACTION_RESERVE
Definition: scsi.h:580
struct _LOG_PAGE_LOGICAL_BLOCK_PROVISIONING LOG_PAGE_LOGICAL_BLOCK_PROVISIONING
#define SCSI_ADSENSE_LB_PROVISIONING
Definition: scsi.h:680
#define RESERVATION_ACTION_RELEASE
Definition: scsi.h:581
#define MODE_PAGE_CONTROL
Definition: scsi.h:202
#define SERVICE_ACTION_READ_CAPACITY16
Definition: scsi.h:474
#define LOG_PAGE_LBP_PARAMETER_CODE_USED
Definition: scsi.h:3360
#define RESERVATION_ACTION_REGISTER_IGNORE_EXISTING
Definition: scsi.h:585
struct BLOCK_DEVICE_RANGE_DESCRIPTOR * PBLOCK_DEVICE_RANGE_DESCRIPTOR
struct _UNMAP_BLOCK_DESCRIPTOR UNMAP_BLOCK_DESCRIPTOR
struct _UNMAP_LIST_HEADER UNMAP_LIST_HEADER
#define SCSIOP_UNMAP
Definition: scsi.h:296
struct _LOG_PARAMETER_THRESHOLD_RESOURCE_COUNT * PLOG_PARAMETER_THRESHOLD_RESOURCE_COUNT
#define RESERVATION_TYPE_WRITE_EXCLUSIVE
Definition: scsi.h:590
#define RESERVATION_ACTION_READ_KEYS
Definition: scsi.h:576
#define RESERVATION_ACTION_PREEMPT_ABORT
Definition: scsi.h:584
struct STOR_ADDRESS_ALIGN _STOR_ADDR_BTL8 * PSTOR_ADDR_BTL8
#define SERVICE_ACTION_POPULATE_TOKEN
Definition: scsi.h:442
#define RESERVATION_ACTION_CLEAR
Definition: scsi.h:582
#define PROVISIONING_TYPE_UNKNOWN
Definition: scsi.h:2588
#define SCSI_SENSEQ_SOFT_THRESHOLD_REACHED
Definition: scsi.h:828
struct _UNMAP_LIST_HEADER * PUNMAP_LIST_HEADER
struct _VPD_BLOCK_LIMITS_PAGE * PVPD_BLOCK_LIMITS_PAGE
#define SCSIOP_GET_LBA_STATUS
Definition: scsi.h:365
#define VPD_BLOCK_LIMITS
Definition: scsi.h:2416
#define REVERSE_BYTES_QUAD(Destination, Source)
Definition: scsi.h:3452
#define REVERSE_BYTES_SHORT(Destination, Source)
Definition: scsi.h:3474
struct _VPD_BLOCK_DEVICE_CHARACTERISTICS_PAGE VPD_BLOCK_DEVICE_CHARACTERISTICS_PAGE
#define LOG_PAGE_LBP_RESOURCE_SCOPE_NOT_DEDICATED_TO_LUN
Definition: scsi.h:3364
struct _LOG_PARAMETER_HEADER * PLOG_PARAMETER_HEADER
#define STOR_ADDRESS_TYPE_BTL8
Definition: scsi.h:3525
#define LOG_PAGE_LBP_PARAMETER_CODE_AVAILABLE
Definition: scsi.h:3359
#define SCSIOP_PERSISTENT_RESERVE_IN
Definition: scsi.h:329
UCHAR senseKey
Definition: scsi.h:4019
#define LOG_PAGE_LBP_RESOURCE_SCOPE_DEDICATED_TO_LUN
Definition: scsi.h:3363
#define RESERVATION_ACTION_PREEMPT
Definition: scsi.h:583
#define SCSIOP_READ_CAPACITY16
Definition: scsi.h:364
struct _PRO_PARAMETER_LIST PRO_PARAMETER_LIST
#define RESERVATION_TYPE_EXCLUSIVE_REGISTRANTS
Definition: scsi.h:593
#define REVERSE_BYTES(Destination, Source)
Definition: scsi.h:3465
struct _VPD_BLOCK_DEVICE_CHARACTERISTICS_PAGE * PVPD_BLOCK_DEVICE_CHARACTERISTICS_PAGE
struct _LBA_STATUS_DESCRIPTOR LBA_STATUS_DESCRIPTOR
#define SCSIOP_PERSISTENT_RESERVE_OUT
Definition: scsi.h:330
#define RESERVATION_TYPE_EXCLUSIVE
Definition: scsi.h:591
#define MAX_SENSE_BUFFER_SIZE
Definition: scsi.h:598
ULONG dataLength
Definition: scsi.h:3751
#define SCSI_SENSE_OPTIONS_NONE
Definition: scsi.h:3838
BOOLEAN validSense
Definition: scsi.h:4018
#define RESERVATION_ACTION_READ_RESERVATIONS
Definition: scsi.h:577
#define RESERVATION_TYPE_WRITE_EXCLUSIVE_REGISTRANTS
Definition: scsi.h:592
struct _LBA_STATUS_LIST_HEADER * PLBA_STATUS_LIST_HEADER
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:104
#define SRB_TYPE_STORAGE_REQUEST_BLOCK
Definition: srb.h:664
struct _SCSI_POWER_REQUEST_BLOCK * PSCSI_POWER_REQUEST_BLOCK
#define STORAGE_ADDRESS_TYPE_BTL8
Definition: srb.h:666
#define SRB_FUNCTION_PNP
Definition: srb.h:105
* PSTORAGE_REQUEST_BLOCK
Definition: srb.h:661
struct SRB_ALIGN _SRBEX_DATA * PSRBEX_DATA
@ SrbExDataTypeWmi
Definition: srb.h:462
@ SrbExDataTypeScsiCdb32
Definition: srb.h:460
@ SrbExDataTypeScsiCdb16
Definition: srb.h:459
@ SrbExDataTypePower
Definition: srb.h:463
@ SrbExDataTypeScsiCdbVar
Definition: srb.h:461
@ SrbExDataTypePnP
Definition: srb.h:464
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:661
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
#define STATUS_MORE_PROCESSING_REQUIRED
Definition: shellext.h:68
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_NOT_FOUND
Definition: shellext.h:72
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
static void Exit(void)
Definition: sock.c:1330
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
FORCEINLINE VOID SrbAssignSrbFlags(_In_ PVOID Srb, _In_ ULONG Flags)
Definition: srbhelper.h:946
FORCEINLINE VOID SrbClearSrbFlags(_In_ PVOID Srb, _In_ ULONG Flags)
Definition: srbhelper.h:982
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
FORCEINLINE PVOID SrbGetSenseInfoBuffer(_In_ PVOID Srb)
Definition: srbhelper.h:619
#define SrbSetRequestTag
Definition: srbhelper.h:869
FORCEINLINE UCHAR SrbGetSenseInfoBufferLength(_In_ PVOID Srb)
Definition: srbhelper.h:638
FORCEINLINE ULONG SrbGetDataTransferLength(_In_ PVOID Srb)
Definition: srbhelper.h:765
struct _STORAGE_DEVICE_LAYOUT_SIGNATURE STORAGE_DEVICE_LAYOUT_SIGNATURE
FORCEINLINE DUID_MATCH_STATUS CompareStorageDuids(_In_ PSTORAGE_DEVICE_UNIQUE_IDENTIFIER Duid1, _In_ PSTORAGE_DEVICE_UNIQUE_IDENTIFIER Duid2)
Definition: storduid.h:56
struct _STORAGE_DEVICE_UNIQUE_IDENTIFIER STORAGE_DEVICE_UNIQUE_IDENTIFIER
#define DUID_INCLUDE_SOFTWARE_IDS
Definition: storduid.h:23
#define DUID_VERSION_1
Definition: storduid.h:20
@ DuidExactMatch
Definition: storduid.h:6
struct _STORAGE_DEVICE_LAYOUT_SIGNATURE * PSTORAGE_DEVICE_LAYOUT_SIGNATURE
#define DUID_HARDWARE_IDS_ONLY
Definition: storduid.h:22
#define TRACE_LEVEL_WARNING
Definition: storswtr.h:28
#define TRACE_LEVEL_VERBOSE
Definition: storswtr.h:30
#define TRACE_LEVEL_FATAL
Definition: storswtr.h:26
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
#define TRACE_LEVEL_INFORMATION
Definition: storswtr.h:29
BOOLEAN IdlePrioritySupported
Definition: classp.h:808
struct _CLASS_PRIVATE_FDO_DATA::@1052 Perf
KSPIN_LOCK SpinLock
Definition: classp.h:795
BOOLEAN DisableThrottling
Definition: classp.h:981
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
PDEVICE_OBJECT LowerDeviceObject
Definition: classpnp.h:598
struct _FUNCTIONAL_DEVICE_EXTENSION * PartitionZeroExtension
Definition: classpnp.h:599
LARGE_INTEGER PartitionLength
Definition: classpnp.h:618
ULONG SlabAllocationBitMap[ANYSIZE_ARRAY]
Definition: ntddstor.h:948
ULONGLONG LengthInBytes
Definition: ntddstor.h:768
LONGLONG StartingOffset
Definition: ntddstor.h:767
ULONG BytesPerSector
Definition: ntdddisk.h:409
PDEVICE_OBJECT DeviceObject
Definition: classpnp.h:871
DISK_GEOMETRY DiskGeometry
Definition: classpnp.h:888
PDEVICE_OBJECT LowerPdo
Definition: classpnp.h:875
COMMON_DEVICE_EXTENSION CommonExtension
Definition: classpnp.h:873
PSTORAGE_ADAPTER_DESCRIPTOR AdapterDescriptor
Definition: classpnp.h:877
PSTORAGE_DEVICE_DESCRIPTOR DeviceDescriptor
Definition: classpnp.h:876
NTSTATUS ErrorCode
Definition: iotypes.h:2007
USHORT NumberOfStrings
Definition: iotypes.h:2004
struct _IO_STACK_LOCATION::@1564::@1565 DeviceIoControl
struct _IO_STACK_LOCATION::@3978::@4017 Others
union _IO_STACK_LOCATION::@1564 Parameters
IO_STATUS_BLOCK IoStatus
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
UCHAR WriteCacheEnable
Definition: cdrw_hw.h:2779
UCHAR PageSavable
Definition: scsi.h:3388
UCHAR DeviceSpecificParameter
Definition: cdrw_hw.h:2507
struct _PERSISTENT_RESERVE_COMMAND::@3176::@3177 PR_IN
struct _PERSISTENT_RESERVE_COMMAND::@3176::@3178 PR_OUT
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 Function
Definition: srb.h:250
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
USHORT Length
Definition: srb.h:249
UCHAR SrbStatus
Definition: srb.h:251
union _STORAGE_DEVICE_LAYOUT_SIGNATURE::@2217 DeviceSpecific
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
Definition: ps.c:97
#define max(a, b)
Definition: svc.c:63
uint16_t * PWSTR
Definition: typedefs.h:56
#define MAXULONG
Definition: typedefs.h:251
uint32_t * PULONG
Definition: typedefs.h:59
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
unsigned char * PBOOLEAN
Definition: typedefs.h:53
int64_t LONGLONG
Definition: typedefs.h:68
#define NTAPI
Definition: typedefs.h:36
void * PVOID
Definition: typedefs.h:50
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define MAXUSHORT
Definition: typedefs.h:83
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
int32_t * PLONG
Definition: typedefs.h:58
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
uint16_t * PWCHAR
Definition: typedefs.h:56
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
char CCHAR
Definition: typedefs.h:51
char * PCHAR
Definition: typedefs.h:51
#define lba
#define STATUS_IO_DEVICE_ERROR
Definition: udferr_usr.h:179
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define STATUS_DATA_OVERRUN
Definition: udferr_usr.h:152
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_NONEXISTENT_SECTOR
Definition: udferr_usr.h:143
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_INVALID_USER_BUFFER
Definition: udferr_usr.h:166
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133
#define STATUS_DEVICE_DATA_ERROR
Definition: udferr_usr.h:159
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define MAXUCHAR
Definition: umtypes.h:117
CONST char * PCSZ
Definition: umtypes.h:125
Definition: cdrw_hw.h:28
struct _CDB::_CDB10 CDB10
struct _CDB::_PERSISTENT_RESERVE_OUT PERSISTENT_RESERVE_OUT
struct _CDB::_PERSISTENT_RESERVE_IN PERSISTENT_RESERVE_IN
struct _CDB::_READ_CAPACITY16 READ_CAPACITY16
struct _CDB::_CDB6INQUIRY3 CDB6INQUIRY3
struct _CDB::_CDB6GENERIC CDB6GENERIC
struct _CDB::_UNMAP UNMAP
struct _CDB::_GET_LBA_STATUS GET_LBA_STATUS
struct _CDB::_CDB16 CDB16
LONGLONG QuadPart
Definition: typedefs.h:114
Definition: pdh_main.c:94
#define PLUGPLAY_REGKEY_DRIVER
Definition: usbd.c:42
_In_ ULONG ParameterLength
Definition: usbdlib.h:206
#define SrbGetCdb(srb)
Definition: usbstor.h:18
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533
_In_ WDFDEVICE _In_ PVOID _In_opt_ PMDL Mdl
_Must_inspect_result_ _In_ PDRIVER_OBJECT _In_ PCUNICODE_STRING RegistryPath
Definition: wdfdriver.h:215
_In_opt_ PVOID _In_ ULONG bufferLength
Definition: wdfdriver.h:109
_Must_inspect_result_ _In_ WDFDEVICE Fdo
Definition: wdffdo.h:461
_Must_inspect_result_ _In_ WDFQUEUE _In_opt_ WDFREQUEST _In_opt_ WDFFILEOBJECT _Inout_opt_ PWDF_REQUEST_PARAMETERS Parameters
Definition: wdfio.h:869
_In_ PCEVENT_DESCRIPTOR _In_opt_ LPCGUID ActivityId
Definition: wmifuncs.h:120
@ DelayedWorkQueue
Definition: extypes.h:190
FORCEINLINE VOID IoSetNextIrpStackLocation(_Inout_ PIRP Irp)
Definition: iofuncs.h:2680
#define PLUGPLAY_REGKEY_DEVICE
Definition: iofuncs.h:2786
#define IRP_MJ_SCSI
#define ERROR_LOG_MAXIMUM_SIZE
Definition: iotypes.h:2042
#define IO_NO_INCREMENT
Definition: iotypes.h:598
@ IoPriorityNormal
Definition: iotypes.h:1233
@ IoPriorityLow
Definition: iotypes.h:1232
@ IoPriorityVeryLow
Definition: iotypes.h:1231
@ DevicePropertyPhysicalDeviceObjectName
Definition: iotypes.h:1206
struct _IO_WORKITEM * PIO_WORKITEM
Definition: iotypes.h:506
struct _IO_ERROR_LOG_PACKET * PIO_ERROR_LOG_PACKET
#define IO_DISK_INCREMENT
Definition: iotypes.h:600
struct _IO_ERROR_LOG_PACKET IO_ERROR_LOG_PACKET
@ Executive
Definition: ketypes.h:415
@ IoReadAccess
Definition: ketypes.h:863
@ IoWriteAccess
Definition: ketypes.h:864
#define FIELD_SIZE(type, field)
#define NT_ASSERT
Definition: rtlfuncs.h:3310
#define RTL_QUERY_REGISTRY_TYPECHECK
#define RTL_QUERY_REGISTRY_TYPECHECK_SHIFT
unsigned char UCHAR
Definition: xmlstorage.h:181
__wchar_t WCHAR
Definition: xmlstorage.h:180