3 Copyright (C) Microsoft Corporation, 2000
11 This file is used to extend cdrom.sys to detect and use mmc-compatible
12 drives' capabilities more wisely.
20 SCSI Tape, CDRom and Disk class drivers share common routines
21 that can be found in the CLASS directory (..\ntos\dd\class).
31 CdRomGetConfiguration(
32 IN PDEVICE_OBJECT Fdo
,
33 OUT PGET_CONFIGURATION_HEADER
*Buffer
,
34 OUT PULONG BytesReturned
,
35 IN FEATURE_NUMBER StartingFeature
,
36 IN ULONG RequestedType
41 CdRompPrintAllFeaturePages(
42 IN PGET_CONFIGURATION_HEADER Buffer
,
48 CdRomUpdateMmcDriveCapabilitiesCompletion(
49 IN PDEVICE_OBJECT Unused
,
56 CdRomPrepareUpdateCapabilitiesIrp(
62 NOT DOCUMENTED YET - may be called at up to DISPATCH_LEVEL
63 if memory is non-paged
64 PRESUMES ALL DATA IS ACCESSIBLE based on FeatureBuffer
69 CdRomFindProfileInProfiles(
70 IN PFEATURE_DATA_PROFILE_LIST ProfileHeader
,
71 IN FEATURE_PROFILE_TYPE ProfileToFind
,
75 PFEATURE_DATA_PROFILE_LIST_EX profile
;
76 ULONG numberOfProfiles
;
79 ASSERT((ProfileHeader
->Header
.AdditionalLength
% 4) == 0);
83 numberOfProfiles
= ProfileHeader
->Header
.AdditionalLength
/ 4;
84 profile
= ProfileHeader
->Profiles
; // zero-sized array
86 for (i
= 0; i
< numberOfProfiles
; i
++) {
88 FEATURE_PROFILE_TYPE currentProfile
;
91 (profile
->ProfileNumber
[0] << 8) |
92 (profile
->ProfileNumber
[1] & 0xff);
94 if (currentProfile
== ProfileToFind
) {
109 NOT DOCUMENTED YET - may be called at up to DISPATCH_LEVEL
110 if memory is non-paged
115 CdRomFindFeaturePage(
116 IN PGET_CONFIGURATION_HEADER FeatureBuffer
,
118 IN FEATURE_NUMBER Feature
124 if (Length
< sizeof(GET_CONFIGURATION_HEADER
) + sizeof(FEATURE_HEADER
)) {
129 // set limit to point to first illegal address
132 limit
= (PUCHAR
)FeatureBuffer
;
136 // set buffer to point to first page
139 buffer
= FeatureBuffer
->Data
;
142 // loop through each page until we find the requested one, or
143 // until it's not safe to access the entire feature header
144 // (if equal, have exactly enough for the feature header)
146 while (buffer
+ sizeof(FEATURE_HEADER
) <= limit
) {
148 PFEATURE_HEADER header
= (PFEATURE_HEADER
)buffer
;
149 FEATURE_NUMBER thisFeature
;
152 (header
->FeatureCode
[0] << 8) |
153 (header
->FeatureCode
[1]);
155 if (thisFeature
== Feature
) {
160 // if don't have enough memory to safely access all the feature
161 // information, return NULL
164 temp
+= sizeof(FEATURE_HEADER
);
165 temp
+= header
->AdditionalLength
;
170 // this means the transfer was cut-off, an insufficiently
171 // small buffer was given, or other arbitrary error. since
172 // it's not safe to view the amount of data (even though
173 // the header is safe) in this feature, pretend it wasn't
174 // transferred at all...
177 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
178 "Feature %x exists, but not safe to access all its "
179 "data. returning NULL\n", Feature
));
186 if (header
->AdditionalLength
% 4) {
187 ASSERT(!"Feature page AdditionalLength field must be integral multiple of 4!\n");
191 buffer
+= sizeof(FEATURE_HEADER
);
192 buffer
+= header
->AdditionalLength
;
200 Private so we can later expose to someone wanting to use a preallocated buffer
205 CdRompGetConfiguration(
206 IN PDEVICE_OBJECT Fdo
,
207 IN PGET_CONFIGURATION_HEADER Buffer
,
209 OUT PULONG ValidBytes
,
210 IN FEATURE_NUMBER StartingFeature
,
211 IN ULONG RequestedType
214 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
216 SCSI_REQUEST_BLOCK srb
;
228 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
229 RtlZeroMemory(Buffer
, BufferSize
);
231 fdoExtension
= Fdo
->DeviceExtension
;
232 cdData
= (PCDROM_DATA
)(fdoExtension
->CommonExtension
.DriverData
);
234 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_BAD_GET_CONFIG_SUPPORT
)) {
235 return STATUS_INVALID_DEVICE_REQUEST
;
238 srb
.TimeOutValue
= CDROM_GET_CONFIGURATION_TIMEOUT
;
242 cdb
->GET_CONFIGURATION
.OperationCode
= SCSIOP_GET_CONFIGURATION
;
243 cdb
->GET_CONFIGURATION
.RequestType
= (UCHAR
)RequestedType
;
244 cdb
->GET_CONFIGURATION
.StartingFeature
[0] = (UCHAR
)(StartingFeature
>> 8);
245 cdb
->GET_CONFIGURATION
.StartingFeature
[1] = (UCHAR
)(StartingFeature
& 0xff);
246 cdb
->GET_CONFIGURATION
.AllocationLength
[0] = (UCHAR
)(BufferSize
>> 8);
247 cdb
->GET_CONFIGURATION
.AllocationLength
[1] = (UCHAR
)(BufferSize
& 0xff);
249 status
= ClassSendSrbSynchronous(Fdo
, &srb
, Buffer
,
251 returned
= srb
.DataTransferLength
;
253 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
254 "CdromGetConfiguration: Status was %x\n", status
));
256 if (NT_SUCCESS(status
) || status
== STATUS_BUFFER_OVERFLOW
) {
259 // if returned more than can be stored in a ULONG, return false
262 if (returned
> (ULONG
)(-1)) {
263 return STATUS_UNSUCCESSFUL
;
265 ASSERT(returned
<= BufferSize
);
266 *ValidBytes
= (ULONG
)returned
;
267 return STATUS_SUCCESS
;
271 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
272 "CdromGetConfiguration: failed %x\n", status
));
277 return STATUS_UNSUCCESSFUL
;
282 Allocates buffer with configuration info, returns STATUS_SUCCESS
283 or an error if one occurred
285 NOTE: does not handle case where more than 65000 bytes are returned,
286 which requires multiple calls with different starting feature
292 CdRomGetConfiguration(
293 IN PDEVICE_OBJECT Fdo
,
294 OUT PGET_CONFIGURATION_HEADER
*Buffer
,
295 OUT PULONG BytesReturned
,
296 IN FEATURE_NUMBER StartingFeature
,
297 IN ULONG RequestedType
300 //PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
301 GET_CONFIGURATION_HEADER header
; // eight bytes, not a lot
302 PGET_CONFIGURATION_HEADER buffer
;
311 //fdoExtension = Fdo->DeviceExtension;
319 // send the first request down to just get the header
322 status
= CdRompGetConfiguration(Fdo
, &header
, sizeof(header
),
323 &returned
, StartingFeature
, RequestedType
);
325 if (!NT_SUCCESS(status
)) {
330 // now try again, using information returned to allocate
331 // just enough memory
334 size
= header
.DataLength
[0] << 24 |
335 header
.DataLength
[1] << 16 |
336 header
.DataLength
[2] << 8 |
337 header
.DataLength
[3] << 0 ;
340 for (i
= 0; i
< 4; i
++) {
343 // the datalength field is the size *following*
344 // itself, so adjust accordingly
347 size
+= 4*sizeof(UCHAR
);
350 // make sure the size is reasonable
353 if (size
<= sizeof(FEATURE_HEADER
)) {
354 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
355 "CdromGetConfiguration: drive reports only %x bytes?\n",
357 return STATUS_UNSUCCESSFUL
;
361 // allocate the memory
364 buffer
= (PGET_CONFIGURATION_HEADER
)
365 ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
369 if (buffer
== NULL
) {
370 return STATUS_INSUFFICIENT_RESOURCES
;
374 // send the first request down to just get the header
377 status
= CdRompGetConfiguration(Fdo
, buffer
, size
, &returned
,
378 StartingFeature
, RequestedType
);
380 if (!NT_SUCCESS(status
)) {
385 if (returned
> size
) {
387 return STATUS_INTERNAL_ERROR
;
390 returned
= buffer
->DataLength
[0] << 24 |
391 buffer
->DataLength
[1] << 16 |
392 buffer
->DataLength
[2] << 8 |
393 buffer
->DataLength
[3] << 0 ;
394 returned
+= 4*sizeof(UCHAR
);
396 if (returned
<= size
) {
398 *BytesReturned
= size
; // amount of 'safe' memory
399 return STATUS_SUCCESS
;
403 // else retry using the new size....
413 // it failed after a number of attempts, so just fail.
416 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
417 "CdRomGetConfiguration: Failed %d attempts to get all feature "
418 "information\n", i
));
419 return STATUS_IO_DEVICE_ERROR
;
424 CdRomIsDeviceMmcDevice(
425 IN PDEVICE_OBJECT Fdo
,
429 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
430 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
431 PCDROM_DATA cdData
= commonExtension
->DriverData
;
432 GET_CONFIGURATION_HEADER localHeader
;
436 ULONG previouslyFailed
;
439 ASSERT( commonExtension
->IsFdo
);
444 // read the registry in case the drive failed previously,
445 // and a timeout is occurring.
448 previouslyFailed
= FALSE
;
449 ClassGetDeviceParameter(fdoExtension
,
451 CDROM_NON_MMC_DRIVE_NAME
,
455 if (previouslyFailed
) {
456 SET_FLAG(cdData
->HackFlags
, CDROM_HACK_BAD_GET_CONFIG_SUPPORT
);
460 // check for the following profiles:
465 status
= CdRompGetConfiguration(Fdo
,
470 SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL
);
472 if (status
== STATUS_INVALID_DEVICE_REQUEST
||
473 status
== STATUS_NO_MEDIA_IN_DEVICE
||
474 status
== STATUS_IO_DEVICE_ERROR
||
475 status
== STATUS_IO_TIMEOUT
) {
477 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
478 "GetConfiguration Failed (%x), device %p not mmc-compliant\n",
481 previouslyFailed
= TRUE
;
482 ClassSetDeviceParameter(fdoExtension
,
484 CDROM_NON_MMC_DRIVE_NAME
,
489 } else if (!NT_SUCCESS(status
)) {
491 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
492 "GetConfiguration Failed, status %x -- defaulting to -ROM\n",
496 } else if (usable
< sizeof(GET_CONFIGURATION_HEADER
)) {
498 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
499 "GetConfiguration Failed, returned only %x bytes!\n", usable
));
500 previouslyFailed
= TRUE
;
501 ClassSetDeviceParameter(fdoExtension
,
503 CDROM_NON_MMC_DRIVE_NAME
,
510 size
= (localHeader
.DataLength
[0] << 24) |
511 (localHeader
.DataLength
[1] << 16) |
512 (localHeader
.DataLength
[2] << 8) |
513 (localHeader
.DataLength
[3] << 0);
516 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
517 "GetConfiguration Failed, claims MMC support but doesn't "
518 "correctly return config length!\n"));
522 size
+= 4; // sizeof the datalength fields
526 PGET_CONFIGURATION_HEADER dbgBuffer
;
529 dbgBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
532 if (dbgBuffer
!= NULL
) {
533 RtlZeroMemory(dbgBuffer
, size
);
535 dbgStatus
= CdRompGetConfiguration(Fdo
, dbgBuffer
, size
,
536 &size
, FeatureProfileList
,
537 SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL
);
539 if (NT_SUCCESS(dbgStatus
)) {
540 CdRompPrintAllFeaturePages(dbgBuffer
, usable
);
542 ExFreePool(dbgBuffer
);
553 CdRompPrintAllFeaturePages(
554 IN PGET_CONFIGURATION_HEADER Buffer
,
558 PFEATURE_HEADER header
;
560 ////////////////////////////////////////////////////////////////////////////////
561 // items expected to ALWAYS be current
562 ////////////////////////////////////////////////////////////////////////////////
563 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureProfileList
);
564 if (header
!= NULL
) {
565 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
566 "CdromGetConfiguration: CurrentProfile %x "
567 "with %x bytes of data at %p\n",
568 Buffer
->CurrentProfile
[0] << 8 |
569 Buffer
->CurrentProfile
[1],
573 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureCore
);
575 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
576 "CdromGetConfiguration: %s %s\n",
578 "Currently supports" : "Is able to support"),
583 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureMorphing
);
585 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
586 "CdromGetConfiguration: %s %s\n",
588 "Currently supports" : "Is able to support"),
593 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureMultiRead
);
595 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
596 "CdromGetConfiguration: %s %s\n",
598 "Currently supports" : "Is able to support"),
602 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureRemovableMedium
);
604 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
605 "CdromGetConfiguration: %s %s\n",
607 "Currently supports" : "Is able to support"),
612 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureTimeout
);
614 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
615 "CdromGetConfiguration: %s %s\n",
617 "Currently supports" : "Is able to support"),
622 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeaturePowerManagement
);
624 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
625 "CdromGetConfiguration: %s %s\n",
627 "Currently supports" : "Is able to support"),
632 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureEmbeddedChanger
);
634 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
635 "CdromGetConfiguration: %s %s\n",
637 "Currently supports" : "Is able to support"),
642 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureLogicalUnitSerialNumber
);
644 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
645 "CdromGetConfiguration: %s %s\n",
647 "Currently supports" : "Is able to support"),
653 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureMicrocodeUpgrade
);
655 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
656 "CdromGetConfiguration: %s %s\n",
658 "Currently supports" : "Is able to support"),
663 ////////////////////////////////////////////////////////////////////////////////
664 // items expected not to always be current
665 ////////////////////////////////////////////////////////////////////////////////
666 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureCDAudioAnalogPlay
);
668 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
669 "CdromGetConfiguration: %s %s\n",
671 "Currently supports" : "Is able to support"),
672 "Analogue CD Audio Operations"
676 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureCdRead
);
678 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
679 "CdromGetConfiguration: %s %s\n",
681 "Currently supports" : "Is able to support"),
682 "reading from CD-ROM/R/RW"
686 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureCdMastering
);
688 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
689 "CdromGetConfiguration: %s %s\n",
691 "Currently supports" : "Is able to support"),
692 "CD Recording (Mastering)"
696 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureCdTrackAtOnce
);
698 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
699 "CdromGetConfiguration: %s %s\n",
701 "Currently supports" : "Is able to support"),
702 "CD Recording (Track At Once)"
706 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureDvdCSS
);
708 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
709 "CdromGetConfiguration: %s %s\n",
711 "Currently supports" : "Is able to support"),
716 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureDvdRead
);
718 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
719 "CdromGetConfiguration: %s %s\n",
721 "Currently supports" : "Is able to support"),
722 "DVD Structure Reads"
726 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureDvdRecordableWrite
);
728 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
729 "CdromGetConfiguration: %s %s\n",
731 "Currently supports" : "Is able to support"),
732 "DVD Recording (Mastering)"
736 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureDiscControlBlocks
);
738 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
739 "CdromGetConfiguration: %s %s\n",
741 "Currently supports" : "Is able to support"),
742 "DVD Disc Control Blocks"
746 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureFormattable
);
748 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
749 "CdromGetConfiguration: %s %s\n",
751 "Currently supports" : "Is able to support"),
756 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureRandomReadable
);
758 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
759 "CdromGetConfiguration: %s %s\n",
761 "Currently supports" : "Is able to support"),
766 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureRandomWritable
);
768 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
769 "CdromGetConfiguration: %s %s\n",
771 "Currently supports" : "Is able to support"),
776 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureRestrictedOverwrite
);
778 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
779 "CdromGetConfiguration: %s %s\n",
781 "Currently supports" : "Is able to support"),
782 "Restricted Overwrites."
786 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureWriteOnce
);
788 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
789 "CdromGetConfiguration: %s %s\n",
791 "Currently supports" : "Is able to support"),
796 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureSectorErasable
);
798 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
799 "CdromGetConfiguration: %s %s\n",
801 "Currently supports" : "Is able to support"),
802 "Sector Erasable Media"
806 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureIncrementalStreamingWritable
);
808 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
809 "CdromGetConfiguration: %s %s\n",
811 "Currently supports" : "Is able to support"),
812 "Incremental Streaming Writing"
816 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureRealTimeStreaming
);
818 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
819 "CdromGetConfiguration: %s %s\n",
821 "Currently supports" : "Is able to support"),
822 "Real-time Streaming Reads"
826 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureSMART
);
828 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
829 "CdromGetConfiguration: %s %s\n",
831 "Currently supports" : "Is able to support"),
836 header
= CdRomFindFeaturePage(Buffer
, Usable
, FeatureDefectManagement
);
838 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
839 "CdromGetConfiguration: %s %s\n",
841 "Currently supports" : "Is able to support"),
850 CdRomUpdateMmcDriveCapabilitiesCompletion(
851 IN PDEVICE_OBJECT Unused
,
853 IN PDEVICE_OBJECT Fdo
856 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
857 //PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
858 PCDROM_DATA cdData
= fdoExtension
->CommonExtension
.DriverData
;
859 PCDROM_MMC_EXTENSION mmcData
= &(cdData
->Mmc
);
860 PSCSI_REQUEST_BLOCK srb
= &(mmcData
->CapabilitiesSrb
);
861 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
862 NTSTATUS status
= STATUS_UNSUCCESSFUL
;
868 // completion routine should retry as necessary.
869 // when success, clear the flag to allow startio to proceed.
870 // else fail original request when retries are exhausted.
872 ASSERT(mmcData
->CapabilitiesIrp
== Irp
);
874 // for now, if succeeded, just print the new pages.
876 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
879 // ISSUE-2000/4/20-henrygab - should we try to reallocate if size
880 // available became larger than what we
881 // originally allocated? otherwise, it
882 // is possible (not probable) that we
883 // would miss the feature. can check
884 // that by finding out what the last
885 // feature is in the current group.
892 // Release the queue if it is frozen.
895 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
896 ClassReleaseQueue(Fdo
);
899 retry
= ClassInterpretSenseInfo(
902 irpStack
->MajorFunction
,
904 MAXIMUM_RETRIES
- ((ULONG
)(ULONG_PTR
)irpStack
->Parameters
.Others
.Argument4
),
909 // DATA_OVERRUN is not an error in this case....
912 if (status
== STATUS_DATA_OVERRUN
) {
913 status
= STATUS_SUCCESS
;
917 // override verify_volume based on original irp's settings
920 if (TEST_FLAG(irpStack
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
) &&
921 status
== STATUS_VERIFY_REQUIRED
) {
922 status
= STATUS_IO_DEVICE_ERROR
;
927 // get current retry count
929 retryCount
= PtrToUlong(irpStack
->Parameters
.Others
.Argument1
);
931 if (retry
&& retryCount
) {
934 // update retry count
936 irpStack
->Parameters
.Others
.Argument1
= UlongToPtr(retryCount
-1);
939 delay
.QuadPart
= retryInterval
;
940 delay
.QuadPart
*= (LONGLONG
)1000 * 1000 * 10;
946 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
947 "Not using ClassRetryRequest Yet\n"));
948 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
949 "Retry update capabilities %p\n", Irp
));
950 CdRomPrepareUpdateCapabilitiesIrp(Fdo
);
952 CdRomRetryRequest(fdoExtension
, Irp
, retryInterval
, TRUE
);
955 // ClassRetryRequest(Fdo, Irp, delay);
958 return STATUS_MORE_PROCESSING_REQUIRED
;
964 status
= STATUS_SUCCESS
;
968 Irp
->IoStatus
.Status
= status
;
970 KeSetEvent(&mmcData
->CapabilitiesEvent
, IO_CD_ROM_INCREMENT
, FALSE
);
973 return STATUS_MORE_PROCESSING_REQUIRED
;
978 CdRomPrepareUpdateCapabilitiesIrp(
982 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
983 //PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
984 PCDROM_DATA cdData
= fdoExtension
->CommonExtension
.DriverData
;
985 PCDROM_MMC_EXTENSION mmcData
= &(cdData
->Mmc
);
986 PIO_STACK_LOCATION nextStack
;
987 PSCSI_REQUEST_BLOCK srb
;
992 ASSERT(mmcData
->UpdateState
);
993 ASSERT(ExQueryDepthSList(&(mmcData
->DelayedIrps
)) != 0);
994 ASSERT(mmcData
->CapabilitiesIrp
!= NULL
);
995 ASSERT(mmcData
->CapabilitiesMdl
!= NULL
);
996 ASSERT(mmcData
->CapabilitiesBuffer
);
997 ASSERT(mmcData
->CapabilitiesBufferSize
!= 0);
998 ASSERT(fdoExtension
->SenseData
);
1001 // do *NOT* call IoReuseIrp(), since it would zero out our
1002 // current irp stack location, which we really don't want
1003 // to happen. it would also set the current irp stack location
1004 // to one greater than currently exists (to give max irp usage),
1005 // but we don't want that either, since we use the top irp stack.
1007 // IoReuseIrp(mmcData->CapabilitiesIrp, STATUS_UNSUCCESSFUL);
1010 irp
= mmcData
->CapabilitiesIrp
;
1011 srb
= &(mmcData
->CapabilitiesSrb
);
1012 cdb
= (PCDB
)(srb
->Cdb
);
1013 bufferSize
= mmcData
->CapabilitiesBufferSize
;
1019 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1020 RtlZeroMemory(fdoExtension
->SenseData
, sizeof(SENSE_DATA
));
1021 RtlZeroMemory(mmcData
->CapabilitiesBuffer
, bufferSize
);
1027 srb
->TimeOutValue
= CDROM_GET_CONFIGURATION_TIMEOUT
;
1028 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1029 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1030 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1031 srb
->SenseInfoBuffer
= fdoExtension
->SenseData
;
1032 srb
->DataBuffer
= mmcData
->CapabilitiesBuffer
;
1033 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
1034 srb
->DataTransferLength
= mmcData
->CapabilitiesBufferSize
;
1035 srb
->ScsiStatus
= 0;
1037 srb
->NextSrb
= NULL
;
1038 srb
->OriginalRequest
= irp
;
1039 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
1040 srb
->CdbLength
= 10;
1041 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
1042 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_QUEUE_FREEZE
);
1048 cdb
->GET_CONFIGURATION
.OperationCode
= SCSIOP_GET_CONFIGURATION
;
1049 cdb
->GET_CONFIGURATION
.RequestType
= SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT
;
1050 cdb
->GET_CONFIGURATION
.StartingFeature
[0] = 0;
1051 cdb
->GET_CONFIGURATION
.StartingFeature
[1] = 0;
1052 cdb
->GET_CONFIGURATION
.AllocationLength
[0] = (UCHAR
)(bufferSize
>> 8);
1053 cdb
->GET_CONFIGURATION
.AllocationLength
[1] = (UCHAR
)(bufferSize
& 0xff);
1059 nextStack
= IoGetNextIrpStackLocation(irp
);
1060 nextStack
->MajorFunction
= IRP_MJ_SCSI
;
1061 nextStack
->Parameters
.Scsi
.Srb
= srb
;
1062 irp
->MdlAddress
= mmcData
->CapabilitiesMdl
;
1063 irp
->AssociatedIrp
.SystemBuffer
= mmcData
->CapabilitiesBuffer
;
1064 IoSetCompletionRoutine(irp
, (PIO_COMPLETION_ROUTINE
)CdRomUpdateMmcDriveCapabilitiesCompletion
, Fdo
,
1073 CdRomUpdateMmcDriveCapabilities(
1074 IN PDEVICE_OBJECT Fdo
,
1078 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
1079 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
1080 PCDROM_DATA cdData
= fdoExtension
->CommonExtension
.DriverData
;
1081 PCDROM_MMC_EXTENSION mmcData
= &(cdData
->Mmc
);
1082 PIO_STACK_LOCATION thisStack
= IoGetCurrentIrpStackLocation(mmcData
->CapabilitiesIrp
);
1083 PSCSI_REQUEST_BLOCK srb
= &(mmcData
->CapabilitiesSrb
);
1087 ASSERT(Context
== NULL
);
1090 // NOTE: a remove lock is unnecessary, since the delayed irp
1091 // will have said lock held for itself, preventing a remove.
1093 CdRomPrepareUpdateCapabilitiesIrp(Fdo
);
1095 ASSERT(thisStack
->Parameters
.Others
.Argument1
== Fdo
);
1096 ASSERT(thisStack
->Parameters
.Others
.Argument2
== mmcData
->CapabilitiesBuffer
);
1097 ASSERT(thisStack
->Parameters
.Others
.Argument3
== &(mmcData
->CapabilitiesSrb
));
1099 mmcData
->WriteAllowed
= FALSE
; // default to read-only
1102 // set max retries, and also allow volume verify override based on
1103 // original (delayed) irp
1106 thisStack
->Parameters
.Others
.Argument4
= (PVOID
)MAXIMUM_RETRIES
;
1109 // send to self... note that SL_OVERRIDE_VERIFY_VOLUME is not required,
1110 // as this is IRP_MJ_INTERNAL_DEVICE_CONTROL
1113 IoCallDriver(commonExtension
->LowerDeviceObject
, mmcData
->CapabilitiesIrp
);
1115 KeWaitForSingleObject(&mmcData
->CapabilitiesEvent
,
1116 Executive
, KernelMode
, FALSE
, NULL
);
1118 status
= mmcData
->CapabilitiesIrp
->IoStatus
.Status
;
1120 if (!NT_SUCCESS(status
)) {
1122 goto FinishDriveUpdate
;
1127 // we've updated the feature set, so update whether or not reads and writes
1128 // are allowed or not.
1131 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
1132 "CdRomUpdateMmc => Succeeded "
1133 "--------------------"
1134 "--------------------\n"));
1138 NOTE: It is important to only use srb->DataTransferLength worth
1139 of data at this point, since the bufferSize is what is
1140 *available* to use, not what was *actually* used.
1145 CdRompPrintAllFeaturePages(mmcData
->CapabilitiesBuffer
,
1146 srb
->DataTransferLength
);
1150 // update whether or not writes are allowed. this is currently defined
1151 // as requiring TargetDefectManagement and RandomWritable features
1154 PFEATURE_HEADER defectHeader
;
1155 PFEATURE_HEADER writableHeader
;
1157 defectHeader
= CdRomFindFeaturePage(mmcData
->CapabilitiesBuffer
,
1158 srb
->DataTransferLength
,
1159 FeatureDefectManagement
);
1160 writableHeader
= CdRomFindFeaturePage(mmcData
->CapabilitiesBuffer
,
1161 srb
->DataTransferLength
,
1162 FeatureRandomWritable
);
1164 if ((defectHeader
!= NULL
) && (writableHeader
!= NULL
) &&
1165 (defectHeader
->Current
) && (writableHeader
->Current
)) {
1168 // this should be the *ONLY* place writes are set to allowed
1171 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
1172 "CdRomUpdateMmc => Writes *allowed*\n"));
1173 mmcData
->WriteAllowed
= TRUE
;
1177 if (defectHeader
== NULL
) {
1178 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
1179 "CdRomUpdateMmc => No writes - %s = %s\n",
1180 "defect management", "DNE"));
1182 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
1183 "CdRomUpdateMmc => No writes - %s = %s\n",
1184 "defect management", "Not Current"));
1186 if (writableHeader
== NULL
) {
1187 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
1188 "CdRomUpdateMmc => No writes - %s = %s\n",
1189 "sector writable", "DNE"));
1191 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
1192 "CdRomUpdateMmc => No writes - %s = %s\n",
1193 "sector writable", "Not Current"));
1195 } // end of feature checking
1196 } // end of check for writability
1199 // update the cached partition table information
1201 // NOTE: THIS WILL CURRENTLY CAUSE A DEADLOCK!
1203 // ISSUE-2000/06/20-henrygab - partition support not implemented
1204 // IoReadPartitionTable must be done
1205 // at PASSIVE level, requiring a thread
1206 // or worker item or other such method.
1209 status
= IoReadPartitionTable(Fdo
, 1 << fdoExtension
->SectorShift
,
1210 TRUE
, &mmcData
->PartitionList
);
1211 if (!NT_SUCCESS(status
)) {
1213 goto FinishDriveUpdate
;
1218 status
= STATUS_SUCCESS
;
1222 CdRompFlushDelayedList(Fdo
, mmcData
, status
, TRUE
);
1229 CdRompFlushDelayedList(
1230 IN PDEVICE_OBJECT Fdo
,
1231 IN PCDROM_MMC_EXTENSION MmcData
,
1233 IN BOOLEAN CalledFromWorkItem
1236 PSINGLE_LIST_ENTRY list
;
1241 // need to set the new state first to prevent deadlocks.
1242 // this is only done from the workitem, to prevent any
1243 // edge cases where we'd "lose" the UpdateRequired
1245 // then, must ignore the state, since it's not guaranteed to
1246 // be the same any longer. the only thing left is to handle
1247 // all the delayed irps by flushing the queue and sending them
1248 // back onto the StartIo queue for the device.
1251 if (CalledFromWorkItem
) {
1256 if (NT_SUCCESS(Status
)) {
1257 newState
= CdromMmcUpdateComplete
;
1259 newState
= CdromMmcUpdateRequired
;
1262 oldState
= InterlockedCompareExchange(&MmcData
->UpdateState
,
1264 CdromMmcUpdateStarted
);
1265 ASSERT(oldState
== CdromMmcUpdateStarted
);
1270 // just flushing the queue if not called from the workitem,
1271 // and we don't want to ever fail the queue in those cases.
1274 ASSERT(NT_SUCCESS(Status
));
1278 list
= ExInterlockedFlushSList(&MmcData
->DelayedIrps
);
1280 // if this assert fires, it means that we have started
1281 // a workitem when the previous workitem took the delayed
1282 // irp. if this happens, then the logic in HACKHACK #0002
1283 // is either flawed or the rules set within are not being
1284 // followed. this would require investigation.
1286 ASSERT(list
!= NULL
);
1289 // now either succeed or fail all the delayed irps, according
1290 // to the update status.
1293 while (list
!= NULL
) {
1295 irp
= (PIRP
)( ((PUCHAR
)list
) -
1296 FIELD_OFFSET(IRP
, Tail
.Overlay
.DriverContext
[0])
1299 irp
->Tail
.Overlay
.DriverContext
[0] = 0;
1300 irp
->Tail
.Overlay
.DriverContext
[1] = 0;
1301 irp
->Tail
.Overlay
.DriverContext
[2] = 0;
1302 irp
->Tail
.Overlay
.DriverContext
[3] = 0;
1304 if (NT_SUCCESS(Status
)) {
1306 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
1307 "CdRomUpdateMmc => Re-sending delayed irp %p\n",
1309 IoStartPacket(Fdo
, irp
, NULL
, NULL
);
1313 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
1314 "CdRomUpdateMmc => Failing delayed irp %p with "
1315 " status %x\n", irp
, Status
));
1316 irp
->IoStatus
.Information
= 0;
1317 irp
->IoStatus
.Status
= Status
;
1318 ClassReleaseRemoveLock(Fdo
, irp
);
1319 IoCompleteRequest(irp
, IO_CD_ROM_INCREMENT
);
1331 CdRomDeAllocateMmcResources(
1332 IN PDEVICE_OBJECT Fdo
1335 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
1336 PCDROM_DATA cddata
= commonExtension
->DriverData
;
1337 PCDROM_MMC_EXTENSION mmcData
= &cddata
->Mmc
;
1340 if (mmcData
->CapabilitiesWorkItem
) {
1341 IoFreeWorkItem(mmcData
->CapabilitiesWorkItem
);
1342 mmcData
->CapabilitiesWorkItem
= NULL
;
1344 if (mmcData
->CapabilitiesIrp
) {
1345 IoFreeIrp(mmcData
->CapabilitiesIrp
);
1346 mmcData
->CapabilitiesIrp
= NULL
;
1348 if (mmcData
->CapabilitiesMdl
) {
1349 IoFreeMdl(mmcData
->CapabilitiesMdl
);
1350 mmcData
->CapabilitiesMdl
= NULL
;
1352 if (mmcData
->CapabilitiesBuffer
) {
1353 ExFreePool(mmcData
->CapabilitiesBuffer
);
1354 mmcData
->CapabilitiesBuffer
= NULL
;
1356 mmcData
->CapabilitiesBuffer
= 0;
1357 mmcData
->IsMmc
= FALSE
;
1358 mmcData
->WriteAllowed
= FALSE
;
1365 CdRomAllocateMmcResources(
1366 IN PDEVICE_OBJECT Fdo
1369 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
1370 PCDROM_DATA cddata
= commonExtension
->DriverData
;
1371 PCDROM_MMC_EXTENSION mmcData
= &cddata
->Mmc
;
1372 PIO_STACK_LOCATION irpStack
;
1375 ASSERT(mmcData
->CapabilitiesWorkItem
== NULL
);
1376 ASSERT(mmcData
->CapabilitiesIrp
== NULL
);
1377 ASSERT(mmcData
->CapabilitiesMdl
== NULL
);
1378 ASSERT(mmcData
->CapabilitiesBuffer
== NULL
);
1379 ASSERT(mmcData
->CapabilitiesBufferSize
== 0);
1381 status
= CdRomGetConfiguration(Fdo
,
1382 &mmcData
->CapabilitiesBuffer
,
1383 &mmcData
->CapabilitiesBufferSize
,
1385 SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL
);
1386 if (!NT_SUCCESS(status
)) {
1387 ASSERT(mmcData
->CapabilitiesBuffer
== NULL
);
1388 ASSERT(mmcData
->CapabilitiesBufferSize
== 0);
1391 ASSERT(mmcData
->CapabilitiesBuffer
!= NULL
);
1392 ASSERT(mmcData
->CapabilitiesBufferSize
!= 0);
1394 mmcData
->CapabilitiesMdl
= IoAllocateMdl(mmcData
->CapabilitiesBuffer
,
1395 mmcData
->CapabilitiesBufferSize
,
1396 FALSE
, FALSE
, NULL
);
1397 if (mmcData
->CapabilitiesMdl
== NULL
) {
1398 ExFreePool(mmcData
->CapabilitiesBuffer
);
1399 mmcData
->CapabilitiesBufferSize
= 0;
1400 return STATUS_INSUFFICIENT_RESOURCES
;
1404 mmcData
->CapabilitiesIrp
= IoAllocateIrp(Fdo
->StackSize
+ 2, FALSE
);
1405 if (mmcData
->CapabilitiesIrp
== NULL
) {
1406 IoFreeMdl(mmcData
->CapabilitiesMdl
);
1407 ExFreePool(mmcData
->CapabilitiesBuffer
);
1408 mmcData
->CapabilitiesBufferSize
= 0;
1409 return STATUS_INSUFFICIENT_RESOURCES
;
1412 mmcData
->CapabilitiesWorkItem
= IoAllocateWorkItem(Fdo
);
1413 if (mmcData
->CapabilitiesWorkItem
== NULL
) {
1414 IoFreeIrp(mmcData
->CapabilitiesIrp
);
1415 IoFreeMdl(mmcData
->CapabilitiesMdl
);
1416 ExFreePool(mmcData
->CapabilitiesBuffer
);
1417 mmcData
->CapabilitiesBufferSize
= 0;
1418 return STATUS_INSUFFICIENT_RESOURCES
;
1422 // everything has been allocated, so now prepare it all....
1425 MmBuildMdlForNonPagedPool(mmcData
->CapabilitiesMdl
);
1426 ExInitializeSListHead(&mmcData
->DelayedIrps
);
1427 KeInitializeSpinLock(&mmcData
->DelayedLock
);
1430 // use the extra stack for internal bookkeeping
1432 IoSetNextIrpStackLocation(mmcData
->CapabilitiesIrp
);
1433 irpStack
= IoGetCurrentIrpStackLocation(mmcData
->CapabilitiesIrp
);
1434 irpStack
->Parameters
.Others
.Argument1
= Fdo
;
1435 irpStack
->Parameters
.Others
.Argument2
= mmcData
->CapabilitiesBuffer
;
1436 irpStack
->Parameters
.Others
.Argument3
= &(mmcData
->CapabilitiesSrb
);
1437 // arg 4 is the retry count
1440 // set the completion event to FALSE for now
1443 KeInitializeEvent(&mmcData
->CapabilitiesEvent
,
1444 SynchronizationEvent
, FALSE
);
1445 return STATUS_SUCCESS
;