[CMAKE]
[reactos.git] / drivers / storage / class / cdrom_new / cdrom.c
1 /*--
2
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4
5 Module Name:
6
7 cdrom.c
8
9 Abstract:
10
11 The CDROM class driver tranlates IRPs to SRBs with embedded CDBs
12 and sends them to its devices through the port driver.
13
14 Environment:
15
16 kernel mode only
17
18 Notes:
19
20 SCSI Tape, CDRom and Disk class drivers share common routines
21 that can be found in the CLASS directory (..\ntos\dd\class).
22
23 Revision History:
24
25 --*/
26
27 #include "stddef.h"
28 #include "string.h"
29
30 #include "ntddk.h"
31 #include "initguid.h"
32
33 #include "ntddcdvd.h"
34 #include "classpnp.h"
35
36 #include "ntddstor.h"
37 #include "cdrom.h"
38
39 #ifdef ALLOC_PRAGMA
40
41 #pragma alloc_text(INIT, DriverEntry)
42
43 #pragma alloc_text(PAGE, CdRomUnload)
44 #pragma alloc_text(PAGE, CdRomAddDevice)
45 #pragma alloc_text(PAGE, CdRomCreateDeviceObject)
46 #pragma alloc_text(PAGE, CdRomStartDevice)
47 #pragma alloc_text(PAGE, ScanForSpecial)
48 #pragma alloc_text(PAGE, ScanForSpecialHandler)
49 #pragma alloc_text(PAGE, CdRomRemoveDevice)
50 #pragma alloc_text(PAGE, CdRomGetDeviceType)
51 #pragma alloc_text(PAGE, CdRomReadWriteVerification)
52 #pragma alloc_text(PAGE, CdRomGetDeviceParameter)
53 #pragma alloc_text(PAGE, CdRomSetDeviceParameter)
54 #pragma alloc_text(PAGE, CdRomPickDvdRegion)
55 #pragma alloc_text(PAGE, CdRomIsPlayActive)
56
57 #pragma alloc_text(PAGEHITA, HitachiProcessError)
58 #pragma alloc_text(PAGEHIT2, HitachiProcessErrorGD2000)
59
60 #pragma alloc_text(PAGETOSH, ToshibaProcessErrorCompletion)
61 #pragma alloc_text(PAGETOSH, ToshibaProcessError)
62
63 #endif
64
65 #define IS_WRITE_REQUEST(irpStack) \
66 (irpStack->MajorFunction == IRP_MJ_WRITE)
67
68 #define IS_READ_WRITE_REQUEST(irpStack) \
69 ((irpStack->MajorFunction == IRP_MJ_READ) || \
70 (irpStack->MajorFunction == IRP_MJ_WRITE) || \
71 ((irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) && \
72 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_RAW_READ)))
73
74
75 \f
76
77 NTSTATUS
78 NTAPI
79 DriverEntry(
80 IN PDRIVER_OBJECT DriverObject,
81 IN PUNICODE_STRING RegistryPath
82 )
83
84 /*++
85
86 Routine Description:
87
88 This routine initializes the cdrom class driver.
89
90 Arguments:
91
92 DriverObject - Pointer to driver object created by system.
93
94 RegistryPath - Pointer to the name of the services node for this driver.
95
96 Return Value:
97
98 The function value is the final status from the initialization operation.
99
100 --*/
101
102 {
103 CLASS_INIT_DATA InitializationData;
104 PCDROM_DRIVER_EXTENSION driverExtension;
105 NTSTATUS status;
106
107 PAGED_CODE();
108
109 WPP_INIT_TRACING(DriverObject, RegistryPath);
110
111 TraceLog((CdromDebugTrace,
112 "CDROM.SYS DriverObject %p loading\n", DriverObject));
113
114 status = IoAllocateDriverObjectExtension(DriverObject,
115 CDROM_DRIVER_EXTENSION_ID,
116 sizeof(CDROM_DRIVER_EXTENSION),
117 &driverExtension);
118
119 if (!NT_SUCCESS(status)) {
120 TraceLog((CdromDebugWarning,
121 "DriverEntry !! no DriverObjectExtension %x\n", status));
122 return status;
123 }
124
125 //
126 // always zero the memory, since we are now reloading the driver.
127 //
128
129 RtlZeroMemory(driverExtension, sizeof(CDROM_DRIVER_EXTENSION));
130
131 //
132 // Zero InitData
133 //
134
135 RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
136
137 //
138 // Set sizes
139 //
140
141 InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
142
143 InitializationData.FdoData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
144
145 InitializationData.FdoData.DeviceType = FILE_DEVICE_CD_ROM;
146 InitializationData.FdoData.DeviceCharacteristics =
147 FILE_REMOVABLE_MEDIA | FILE_DEVICE_SECURE_OPEN;
148
149 //
150 // Set entry points
151 //
152
153 InitializationData.FdoData.ClassError = CdRomErrorHandler;
154 InitializationData.FdoData.ClassInitDevice = CdRomInitDevice;
155 InitializationData.FdoData.ClassStartDevice = CdRomStartDevice;
156 InitializationData.FdoData.ClassStopDevice = CdRomStopDevice;
157 InitializationData.FdoData.ClassRemoveDevice = CdRomRemoveDevice;
158
159 InitializationData.FdoData.ClassReadWriteVerification = CdRomReadWriteVerification;
160 InitializationData.FdoData.ClassDeviceControl = CdRomDeviceControlDispatch;
161
162 InitializationData.FdoData.ClassPowerDevice = ClassSpinDownPowerHandler;
163 InitializationData.FdoData.ClassShutdownFlush = CdRomShutdownFlush;
164 InitializationData.FdoData.ClassCreateClose = NULL;
165
166 InitializationData.ClassStartIo = CdRomStartIo;
167 InitializationData.ClassAddDevice = CdRomAddDevice;
168
169 InitializationData.ClassTick = CdRomTickHandler;
170 InitializationData.ClassUnload = CdRomUnload;
171
172 //
173 // Call the class init routine
174 //
175 return ClassInitialize( DriverObject, RegistryPath, &InitializationData);
176
177 } // end DriverEntry()
178 \f
179
180 VOID
181 CdRomUnload(
182 IN PDRIVER_OBJECT DriverObject
183 )
184 {
185 PAGED_CODE();
186 UNREFERENCED_PARAMETER(DriverObject);
187 TraceLog((CdromDebugTrace,
188 "CDROM.SYS DriverObject %p unloading\n", DriverObject));
189 WPP_CLEANUP(DriverObject);
190 return;
191 } // end CdRomUnload()
192 \f
193
194 NTSTATUS
195 CdRomAddDevice(
196 IN PDRIVER_OBJECT DriverObject,
197 IN PDEVICE_OBJECT PhysicalDeviceObject
198 )
199
200 /*++
201
202 Routine Description:
203
204 This routine creates and initializes a new FDO for the corresponding
205 PDO. It may perform property queries on the FDO but cannot do any
206 media access operations.
207
208 Arguments:
209
210 DriverObject - CDROM class driver object.
211
212 Pdo - the physical device object we are being added to
213
214 Return Value:
215
216 status
217
218 --*/
219
220 {
221 NTSTATUS status;
222
223 PAGED_CODE();
224
225 //
226 // Get the address of the count of the number of cdroms already initialized.
227 //
228 DbgPrint("add device\n");
229
230 status = CdRomCreateDeviceObject(DriverObject,
231 PhysicalDeviceObject);
232
233 //
234 // Note: this always increments driver extension counter
235 // it will eventually wrap, and fail additions
236 // if an existing cdrom has the given number.
237 // so unlikely that we won't even bother considering
238 // this case, since the cure is quite likely worse
239 // than the symptoms.
240 //
241
242 if(NT_SUCCESS(status)) {
243
244 //
245 // keep track of the total number of active cdroms in IoGet(),
246 // as some programs use this to determine when they have found
247 // all the cdroms in the system.
248 //
249
250 TraceLog((CdromDebugTrace, "CDROM.SYS Add succeeded\n"));
251 IoGetConfigurationInformation()->CdRomCount++;
252
253 } else {
254
255 TraceLog((CdromDebugWarning,
256 "CDROM.SYS Add failed! %x\n", status));
257
258 }
259
260 return status;
261 }
262 \f
263
264 NTSTATUS
265 CdRomCreateDeviceObject(
266 IN PDRIVER_OBJECT DriverObject,
267 IN PDEVICE_OBJECT PhysicalDeviceObject
268 )
269
270 /*++
271
272 Routine Description:
273
274 This routine creates an object for the device and then calls the
275 SCSI port driver for media capacity and sector size.
276
277 Arguments:
278
279 DriverObject - Pointer to driver object created by system.
280 PortDeviceObject - to connect to SCSI port driver.
281 DeviceCount - Number of previously installed CDROMs.
282 PortCapabilities - Pointer to structure returned by SCSI port
283 driver describing adapter capabilites (and limitations).
284 LunInfo - Pointer to configuration information for this device.
285
286 Return Value:
287
288 NTSTATUS
289
290 --*/
291 {
292 UCHAR ntNameBuffer[64];
293 STRING ntNameString;
294 NTSTATUS status;
295
296 PDEVICE_OBJECT lowerDevice = NULL;
297 PDEVICE_OBJECT deviceObject = NULL;
298 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
299 PCDROM_DATA cdData = NULL;
300 PCDROM_DRIVER_EXTENSION driverExtension = NULL;
301 ULONG deviceNumber;
302
303 CCHAR dosNameBuffer[64];
304 CCHAR deviceNameBuffer[64];
305 STRING deviceNameString;
306 STRING dosString;
307 UNICODE_STRING dosUnicodeString;
308 UNICODE_STRING unicodeString;
309
310 PAGED_CODE();
311
312 //
313 // Claim the device. Note that any errors after this
314 // will goto the generic handler, where the device will
315 // be released.
316 //
317
318 lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
319
320 status = ClassClaimDevice(lowerDevice, FALSE);
321
322 if(!NT_SUCCESS(status)) {
323
324 //
325 // Someone already had this device - we're in trouble
326 //
327
328 ObDereferenceObject(lowerDevice);
329 return status;
330 }
331
332 //
333 // Create device object for this device by first getting a unique name
334 // for the device and then creating it.
335 //
336
337 driverExtension = IoGetDriverObjectExtension(DriverObject,
338 CDROM_DRIVER_EXTENSION_ID);
339 ASSERT(driverExtension != NULL);
340
341 //
342 // InterlockedCdRomCounter is biased by 1.
343 //
344
345 deviceNumber = InterlockedIncrement(&driverExtension->InterlockedCdRomCounter) - 1;
346 sprintf(ntNameBuffer, "\\Device\\CdRom%d", deviceNumber);
347
348
349 status = ClassCreateDeviceObject(DriverObject,
350 ntNameBuffer,
351 PhysicalDeviceObject,
352 TRUE,
353 &deviceObject);
354
355 if (!NT_SUCCESS(status)) {
356 TraceLog((CdromDebugWarning,
357 "CreateCdRomDeviceObjects: Can not create device %s\n",
358 ntNameBuffer));
359
360 goto CreateCdRomDeviceObjectExit;
361 }
362
363 //
364 // Indicate that IRPs should include MDLs.
365 //
366
367 SET_FLAG(deviceObject->Flags, DO_DIRECT_IO);
368
369 fdoExtension = deviceObject->DeviceExtension;
370
371 //
372 // Back pointer to device object.
373 //
374
375 fdoExtension->CommonExtension.DeviceObject = deviceObject;
376
377 //
378 // This is the physical device.
379 //
380
381 fdoExtension->CommonExtension.PartitionZeroExtension = fdoExtension;
382
383 //
384 // Initialize lock count to zero. The lock count is used to
385 // disable the ejection mechanism when media is mounted.
386 //
387
388 fdoExtension->LockCount = 0;
389
390 //
391 // Save system cdrom number
392 //
393
394 fdoExtension->DeviceNumber = deviceNumber;
395
396 //
397 // Set the alignment requirements for the device based on the
398 // host adapter requirements
399 //
400
401 if (lowerDevice->AlignmentRequirement > deviceObject->AlignmentRequirement) {
402 deviceObject->AlignmentRequirement = lowerDevice->AlignmentRequirement;
403 }
404
405 //
406 // Save the device descriptors
407 //
408
409 fdoExtension->AdapterDescriptor = NULL;
410
411 fdoExtension->DeviceDescriptor = NULL;
412
413 //
414 // Clear the SrbFlags and disable synchronous transfers
415 //
416
417 fdoExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
418
419 //
420 // Finally, attach to the PDO
421 //
422
423 fdoExtension->LowerPdo = PhysicalDeviceObject;
424
425 fdoExtension->CommonExtension.LowerDeviceObject =
426 IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
427
428 if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
429
430 //
431 // Uh - oh, we couldn't attach
432 // cleanup and return
433 //
434
435 status = STATUS_UNSUCCESSFUL;
436 goto CreateCdRomDeviceObjectExit;
437 }
438
439 //
440 // CdRom uses an extra stack location for synchronizing it's start io
441 // routine
442 //
443
444 deviceObject->StackSize++;
445
446 //
447 // cdData is used a few times below
448 //
449
450 cdData = fdoExtension->CommonExtension.DriverData;
451
452 //
453 // For NTMS to be able to easily determine drives-drv. letter matches.
454 //
455
456 status = CdRomCreateWellKnownName( deviceObject );
457
458 if (!NT_SUCCESS(status)) {
459 TraceLog((CdromDebugWarning,
460 "CdromCreateDeviceObjects: unable to create symbolic "
461 "link for device %wZ\n", &fdoExtension->CommonExtension.DeviceName));
462 TraceLog((CdromDebugWarning,
463 "CdromCreateDeviceObjects: (non-fatal error)\n"));
464 }
465
466 ClassUpdateInformationInRegistry(deviceObject, "CdRom",
467 fdoExtension->DeviceNumber, NULL, 0);
468
469 //
470 // from above IoGetAttachedDeviceReference
471 //
472
473 ObDereferenceObject(lowerDevice);
474
475 //
476 // need to init timerlist here in case a remove occurs
477 // without a start, since we check the list is empty on remove.
478 //
479
480 cdData->DelayedRetryIrp = NULL;
481 cdData->DelayedRetryInterval = 0;
482
483 //
484 // need this to be initialized for RPC Phase 1 drives (rpc0)
485 //
486
487 KeInitializeMutex(&cdData->Rpc0RegionMutex, 0);
488
489 //
490 // The device is initialized properly - mark it as such.
491 //
492
493 CLEAR_FLAG(deviceObject->Flags, DO_DEVICE_INITIALIZING);
494
495 return(STATUS_SUCCESS);
496
497 CreateCdRomDeviceObjectExit:
498
499 //
500 // Release the device since an error occured.
501 //
502
503 // ClassClaimDevice(PortDeviceObject,
504 // LunInfo,
505 // TRUE,
506 // NULL);
507
508 //
509 // from above IoGetAttachedDeviceReference
510 //
511
512 ObDereferenceObject(lowerDevice);
513
514 if (deviceObject != NULL) {
515 IoDeleteDevice(deviceObject);
516 }
517
518 return status;
519
520 } // end CreateCdRomDeviceObject()
521 \f
522
523 NTSTATUS
524 CdRomInitDevice(
525 IN PDEVICE_OBJECT Fdo
526 )
527
528 /*++
529
530 Routine Description:
531
532 This routine will complete the cd-rom initialization. This includes
533 allocating sense info buffers and srb s-lists, reading drive capacity
534 and setting up Media Change Notification (autorun).
535
536 This routine will not clean up allocate resources if it fails - that
537 is left for device stop/removal
538
539 Arguments:
540
541 Fdo - a pointer to the functional device object for this device
542
543 Return Value:
544
545 status
546
547 --*/
548
549 {
550 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
551 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
552 PCLASS_DRIVER_EXTENSION driverExtension = ClassGetDriverExtension(
553 Fdo->DriverObject);
554
555 PVOID senseData = NULL;
556
557 ULONG timeOut;
558 PCDROM_DATA cddata;
559
560 BOOLEAN changerDevice;
561 BOOLEAN isMmcDevice = FALSE;
562
563 ULONG bps;
564 ULONG lastBit;
565
566
567 NTSTATUS status;
568
569 PAGED_CODE();
570
571 //
572 // Build the lookaside list for srb's for the physical disk. Should only
573 // need a couple.
574 //
575
576 ClassInitializeSrbLookasideList(&(fdoExtension->CommonExtension),
577 CDROM_SRB_LIST_SIZE);
578
579 //
580 // Allocate request sense buffer.
581 //
582
583 senseData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
584 SENSE_BUFFER_SIZE,
585 CDROM_TAG_SENSE_INFO);
586
587 if (senseData == NULL) {
588
589 //
590 // The buffer cannot be allocated.
591 //
592
593 status = STATUS_INSUFFICIENT_RESOURCES;
594 goto CdRomInitDeviceExit;
595 }
596
597 //
598 // Set the sense data pointer in the device extension.
599 //
600
601 fdoExtension->SenseData = senseData;
602
603 //
604 // CDROMs are not partitionable so starting offset is 0.
605 //
606
607 commonExtension->StartingOffset.LowPart = 0;
608 commonExtension->StartingOffset.HighPart = 0;
609
610 //
611 // Set timeout value in seconds.
612 //
613
614 timeOut = ClassQueryTimeOutRegistryValue(Fdo);
615 if (timeOut) {
616 fdoExtension->TimeOutValue = timeOut;
617 } else {
618 fdoExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
619 }
620
621 cddata = (PCDROM_DATA)(commonExtension->DriverData);
622
623 //
624 // Set up media change support defaults.
625 //
626
627 KeInitializeSpinLock(&cddata->DelayedRetrySpinLock);
628
629 cddata->DelayedRetryIrp = NULL;
630 cddata->DelayedRetryInterval = 0;
631 cddata->Mmc.WriteAllowed = FALSE;
632
633 //
634 // Scan for controllers that require special processing.
635 //
636
637 ScanForSpecial(Fdo);
638
639 //
640 // Determine if the drive is MMC-Capable
641 //
642
643 CdRomIsDeviceMmcDevice(Fdo, &isMmcDevice);
644
645 if (!isMmcDevice) {
646
647 SET_FLAG(Fdo->Characteristics, FILE_READ_ONLY_DEVICE);
648
649 } else {
650
651 //
652 // the drive supports at least a subset of MMC commands
653 // (and therefore supports READ_CD, etc...)
654 //
655
656 cddata->Mmc.IsMmc = TRUE;
657
658 //
659 // allocate a buffer for all the capabilities and such
660 //
661
662 status = CdRomAllocateMmcResources(Fdo);
663 if (!NT_SUCCESS(status)) {
664 goto CdRomInitDeviceExit;
665 }
666
667
668 #if 0
669 //
670 // determine all the various media types from the profiles feature
671 //
672 {
673 PFEATURE_DATA_PROFILE_LIST profileHeader;
674 ULONG mediaTypes = 0;
675 ULONG i;
676
677 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
678 "Checking all profiles for media types supported.\n"
679 ));
680
681 profileHeader = CdRomFindFeaturePage(cddata->Mmc.CapabilitiesBuffer,
682 cddata->Mmc.CapabilitiesBufferSize,
683 FeatureProfileList);
684 if (profileHeader == NULL) {
685
686 //
687 // if profiles don't exist, there is something seriously
688 // wrong with this command -- it's either not a cdrom or
689 // one that hasn't implemented the spec correctly. exit
690 // now while we have the chance to do so safely.
691 //
692 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
693 "CdromDevice supports GET_CONFIGURATION, but "
694 "doesn't provide profiles for PDO %p!\n",
695 fdoExtension->LowerPdo));
696 status = STATUS_DEVICE_CONFIGURATION_ERROR;
697 goto CdRomInitDeviceExit;
698
699 }
700
701 for (i = 0; i < MAX_CDROM_MEDIA_TYPES; i++) {
702
703 BOOLEAN profileFound;
704 CdRomFindProfileInProfiles(profileHeader,
705 MediaProfileMatch[i].Profile,
706 &profileFound);
707 if (profileFound) {
708
709 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
710 "CdromInit -> Found Profile %x => Media %x "
711 "(%x total)\n",
712 MediaProfileMatch[i].Profile,
713 MediaProfileMatch[i].Media,
714 mediaTypes + 1
715 ));
716
717 cddata->Mmc.MediaProfileMatches[mediaTypes] =
718 MediaProfileMatch[i];
719 mediaTypes++;
720
721 }
722
723 }
724
725 if (mediaTypes == 0) {
726
727 //
728 // if profiles don't exist, there is something seriously
729 // wrong with this command -- it's either not a cdrom or
730 // one that hasn't implemented the spec correctly. exit
731 // now while we have the chance to do so safely.
732 //
733 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
734 "CdromDevice supports GET_CONFIGURATION, but "
735 "doesn't support any of the standard profiles "
736 "for PDO %p!\n", fdoExtension->LowerPdo));
737 status = STATUS_DEVICE_CONFIGURATION_ERROR;
738 goto CdRomInitDeviceExit;
739
740 }
741
742 cddata->Mmc.MediaTypes = mediaTypes;
743
744
745 }
746 #endif // media checks, and all failure paths due to bad firmware.
747
748 //
749 // if the drive supports target defect management and sector-addressable
750 // writes, then we should allow writes to the media.
751 //
752
753 if (CdRomFindFeaturePage(cddata->Mmc.CapabilitiesBuffer,
754 cddata->Mmc.CapabilitiesBufferSize,
755 FeatureDefectManagement) &&
756 CdRomFindFeaturePage(cddata->Mmc.CapabilitiesBuffer,
757 cddata->Mmc.CapabilitiesBufferSize,
758 FeatureRandomWritable)) {
759
760 //
761 // the drive is target defect managed, and supports random writes
762 // on sector-aligment. allow writes to occur by setting the error
763 // handler to point to a private media change detection handler.
764 //
765
766 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
767 "Found a WRITE capable device: %p\n", Fdo));
768
769 //
770 // the write specific pages have been found --
771 // set the error handler and set it to require an update!
772 //
773
774 cddata->Mmc.UpdateState = CdromMmcUpdateRequired;
775 cddata->ErrorHandler = CdRomMmcErrorHandler;
776
777 }
778
779 //
780 // ISSUE-2000/4/4-henrygab - mmc-compliant compliant drives should
781 // be initialized based upon reported
782 // capabilities, such as CSS, Analogue Audio,
783 // READ_CD capabilities, and (possibly) even
784 // drive capacity information.
785 //
786
787 TraceLog((CdromDebugWarning,
788 "Defaulting to READ_CD because device %p is MMC compliant\n",
789 Fdo));
790 SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
791 SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
792
793 }
794
795
796 //
797 // Set the default geometry for the cdrom to match what NT 4 used.
798 // Classpnp will use these values to compute the cylinder count rather
799 // than using it's NT 5.0 defaults.
800 //
801
802 fdoExtension->DiskGeometry.TracksPerCylinder = 0x40;
803 fdoExtension->DiskGeometry.SectorsPerTrack = 0x20;
804
805 //
806 // Do READ CAPACITY. This SCSI command returns the last sector address
807 // on the device and the bytes per sector. These are used to calculate
808 // the drive capacity in bytes.
809 //
810 // NOTE: This should be change to send the Srb synchronously, then
811 // call CdRomInterpretReadCapacity() to properly setup the defaults.
812 //
813
814 status = ClassReadDriveCapacity(Fdo);
815
816 bps = fdoExtension->DiskGeometry.BytesPerSector;
817
818 if (!NT_SUCCESS(status) || !bps) {
819
820 TraceLog((CdromDebugWarning,
821 "CdRomStartDevice: Can't read capacity for device %wZ\n",
822 &(fdoExtension->CommonExtension.DeviceName)));
823
824 //
825 // Set disk geometry to default values (per ISO 9660).
826 //
827
828 bps = 2048;
829 fdoExtension->SectorShift = 11;
830 commonExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
831
832 } else {
833
834 //
835 // Insure that bytes per sector is a power of 2
836 // This corrects a problem with the HP 4020i CDR where it
837 // returns an incorrect number for bytes per sector.
838 //
839
840 lastBit = (ULONG) -1;
841 while (bps) {
842 lastBit++;
843 bps = bps >> 1;
844 }
845
846 bps = 1 << lastBit;
847 }
848 fdoExtension->DiskGeometry.BytesPerSector = bps;
849 TraceLog((CdromDebugTrace, "CdRomInitDevice: Calc'd bps = %x\n", bps));
850
851
852 ClassInitializeMediaChangeDetection(fdoExtension, "CdRom");
853
854
855 //
856 // test for audio read capabilities
857 //
858
859 TraceLog((CdromDebugWarning,
860 "Detecting XA_READ capabilities\n"));
861
862 if (CdRomGetDeviceType(Fdo) == FILE_DEVICE_DVD) {
863
864 TraceLog((CdromDebugWarning,
865 "CdRomInitDevice: DVD Devices require START_UNIT\n"));
866
867
868 //
869 // all DVD devices must support the READ_CD command
870 //
871
872 TraceLog((CdromDebugWarning,
873 "CdRomDetermineRawReadCapabilities: DVD devices "
874 "support READ_CD command for FDO %p\n", Fdo));
875 SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
876 SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
877
878
879 status = STATUS_SUCCESS;
880
881 } else if ((fdoExtension->DeviceDescriptor->BusType != BusTypeScsi) &&
882 (fdoExtension->DeviceDescriptor->BusType != BusTypeAta) &&
883 (fdoExtension->DeviceDescriptor->BusType != BusTypeAtapi) &&
884 (fdoExtension->DeviceDescriptor->BusType != BusTypeUnknown)
885 ) {
886
887 //
888 // devices on the newer busses must support READ_CD command
889 //
890
891 TraceLog((CdromDebugWarning,
892 "CdRomDetermineRawReadCapabilities: Devices for newer "
893 "busses must support READ_CD command for FDO %p, Bus %x\n",
894 Fdo, fdoExtension->DeviceDescriptor->BusType));
895 SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
896 SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
897
898 }
899
900 //
901 // now clear all our READ_CD flags if the drive should have supported
902 // it, but we are not sure it actually does. we still won't query
903 // the drive more than one time if it supports the command.
904 //
905
906 if (TEST_FLAG(cddata->HackFlags, CDROM_HACK_FORCE_READ_CD_DETECTION)) {
907
908 TraceLog((CdromDebugWarning,
909 "Forcing detection of READ_CD for FDO %p because "
910 "testing showed some firmware did not properly support it\n",
911 Fdo));
912 CLEAR_FLAG(cddata->XAFlags, XA_USE_READ_CD);
913
914 }
915
916
917 //
918 // read our READ_CD support in the registry if it was seeded.
919 //
920 {
921 ULONG readCdSupported = 0;
922
923 ClassGetDeviceParameter(fdoExtension,
924 CDROM_SUBKEY_NAME,
925 CDROM_READ_CD_NAME,
926 &readCdSupported
927 );
928
929 if (readCdSupported != 0) {
930
931 TraceLog((CdromDebugWarning,
932 "Defaulting to READ_CD because previously detected "
933 "that the device supports it for Fdo %p.\n",
934 Fdo
935 ));
936 SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
937
938 }
939
940 }
941
942
943 //
944 // backwards-compatible hackish attempt to determine if the drive
945 // supports any method of reading digital audio from the disc.
946 //
947
948 if (!TEST_FLAG(cddata->XAFlags, XA_USE_READ_CD)) {
949
950 SCSI_REQUEST_BLOCK srb;
951 PCDB cdb;
952 ULONG length;
953 PUCHAR buffer = NULL;
954 ULONG count;
955
956 //
957 // ISSUE-2000/07/05-henrygab - use the mode page to determine
958 // READ_CD support, then fall back on the below
959 // (unreliable?) hack.
960 //
961
962 //
963 // Build the MODE SENSE CDB. The data returned will be kept in the
964 // device extension and used to set block size.
965 //
966
967 length = max(sizeof(ERROR_RECOVERY_DATA),sizeof(ERROR_RECOVERY_DATA10));
968
969 buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
970 length,
971 CDROM_TAG_MODE_DATA);
972
973 if (!buffer) {
974 TraceLog((CdromDebugWarning,
975 "CdRomDetermineRawReadCapabilities: cannot allocate "
976 "buffer, so leaving for FDO %p\n", Fdo));
977 status = STATUS_INSUFFICIENT_RESOURCES;
978 goto CdRomInitDeviceExit;
979 }
980
981 for (count = 0; count < 2; count++) {
982
983 if (count == 0) {
984 length = sizeof(ERROR_RECOVERY_DATA);
985 } else {
986 length = sizeof(ERROR_RECOVERY_DATA10);
987 }
988
989 RtlZeroMemory(buffer, length);
990 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
991 cdb = (PCDB)srb.Cdb;
992
993 srb.TimeOutValue = fdoExtension->TimeOutValue;
994
995 if (count == 0) {
996 srb.CdbLength = 6;
997 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
998 cdb->MODE_SENSE.PageCode = 0x1;
999 // note: not setting DBD in order to get the block descriptor!
1000 cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
1001 } else {
1002 srb.CdbLength = 10;
1003 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
1004 cdb->MODE_SENSE10.PageCode = 0x1;
1005 // note: not setting DBD in order to get the block descriptor!
1006 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(length >> 8);
1007 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(length & 0xFF);
1008 }
1009
1010 status = ClassSendSrbSynchronous(Fdo,
1011 &srb,
1012 buffer,
1013 length,
1014 FALSE);
1015
1016
1017 if (NT_SUCCESS(status) || (status == STATUS_DATA_OVERRUN)) {
1018
1019 //
1020 // STATUS_DATA_OVERRUN means it's a newer drive with more info
1021 // to tell us, so it's probably able to support READ_CD
1022 //
1023
1024 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
1025
1026 srb.CdbLength = 12;
1027 cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
1028
1029 status = ClassSendSrbSynchronous(Fdo,
1030 &srb,
1031 NULL,
1032 0,
1033 FALSE);
1034
1035 if (NT_SUCCESS(status) ||
1036 (status == STATUS_NO_MEDIA_IN_DEVICE) ||
1037 (status == STATUS_NONEXISTENT_SECTOR) ||
1038 (status == STATUS_UNRECOGNIZED_MEDIA)
1039 ) {
1040
1041 //
1042 // READ_CD works
1043 //
1044
1045 TraceLog((CdromDebugWarning,
1046 "CdRomDetermineRawReadCapabilities: Using "
1047 "READ_CD for FDO %p due to status %x\n",
1048 Fdo,
1049 status));
1050 SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
1051
1052 //
1053 // ignore errors in saving this info
1054 //
1055
1056 ClassSetDeviceParameter(fdoExtension,
1057 CDROM_SUBKEY_NAME,
1058 CDROM_READ_CD_NAME,
1059 1
1060 );
1061
1062
1063 break; // out of the for loop
1064
1065 }
1066
1067 TraceLog((CdromDebugWarning,
1068 "CdRomDetermineRawReadCapabilities: Using "
1069 "%s-byte mode switching for FDO %p due to status "
1070 "%x returned for READ_CD\n",
1071 ((count == 0) ? "6" : "10"), Fdo, status));
1072
1073 if (count == 0) {
1074 SET_FLAG(cddata->XAFlags, XA_USE_6_BYTE);
1075 RtlCopyMemory(&cddata->Header,
1076 buffer,
1077 sizeof(ERROR_RECOVERY_DATA));
1078 cddata->Header.ModeDataLength = 0;
1079 } else {
1080 SET_FLAG(cddata->XAFlags, XA_USE_10_BYTE);
1081 RtlCopyMemory(&cddata->Header10,
1082 buffer,
1083 sizeof(ERROR_RECOVERY_DATA10));
1084 cddata->Header10.ModeDataLength[0] = 0;
1085 cddata->Header10.ModeDataLength[1] = 0;
1086 }
1087 break; // out of for loop
1088
1089 }
1090 TraceLog((CdromDebugWarning,
1091 "FDO %p failed %x byte mode sense, status %x\n",
1092 Fdo,
1093 ((count == 0) ? 6 : 10),
1094 status
1095 ));
1096
1097 //
1098 // mode sense failed
1099 //
1100
1101 } // end of for loop to try 6 and 10-byte mode sense
1102
1103 if (count == 2) {
1104
1105 //
1106 // nothing worked. we probably cannot support digital
1107 // audio extraction from this drive
1108 //
1109
1110 TraceLog((CdromDebugWarning,
1111 "CdRomDetermineRawReadCapabilities: FDO %p "
1112 "cannot support READ_CD\n", Fdo));
1113 CLEAR_FLAG(cddata->XAFlags, XA_PLEXTOR_CDDA);
1114 CLEAR_FLAG(cddata->XAFlags, XA_NEC_CDDA);
1115 SET_FLAG(cddata->XAFlags, XA_NOT_SUPPORTED);
1116
1117 } // end of count == 2
1118
1119 //
1120 // free our resources
1121 //
1122
1123 ExFreePool(buffer);
1124
1125 //
1126 // set a successful status
1127 // (in case someone later checks this)
1128 //
1129
1130 status = STATUS_SUCCESS;
1131
1132 }
1133
1134 //
1135 // Register interfaces for this device.
1136 //
1137
1138 {
1139 UNICODE_STRING interfaceName;
1140
1141 RtlInitUnicodeString(&interfaceName, NULL);
1142
1143 status = IoRegisterDeviceInterface(fdoExtension->LowerPdo,
1144 (LPGUID) &CdRomClassGuid,
1145 NULL,
1146 &interfaceName);
1147
1148 if(NT_SUCCESS(status)) {
1149
1150 cddata->CdromInterfaceString = interfaceName;
1151
1152 status = IoSetDeviceInterfaceState(
1153 &interfaceName,
1154 TRUE);
1155
1156 if(!NT_SUCCESS(status)) {
1157
1158 TraceLog((CdromDebugWarning,
1159 "CdromInitDevice: Unable to register cdrom "
1160 "DCA for fdo %p [%lx]\n",
1161 Fdo, status));
1162 }
1163 }
1164 }
1165
1166 return(STATUS_SUCCESS);
1167
1168 CdRomInitDeviceExit:
1169
1170 CdRomDeAllocateMmcResources(Fdo);
1171 RtlZeroMemory(&(cddata->Mmc), sizeof(CDROM_MMC_EXTENSION));
1172
1173 return status;
1174
1175 }
1176 \f
1177
1178 NTSTATUS
1179 CdRomStartDevice(
1180 IN PDEVICE_OBJECT Fdo
1181 )
1182 /*++
1183
1184 Routine Description:
1185
1186 This routine starts the timer for the cdrom
1187
1188 Arguments:
1189
1190 Fdo - a pointer to the functional device object for this device
1191
1192 Return Value:
1193
1194 status
1195
1196 --*/
1197
1198 {
1199 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
1200 PCDROM_DATA cddata = (PCDROM_DATA)(commonExtension->DriverData);
1201 PDVD_COPY_PROTECT_KEY copyProtectKey;
1202 PDVD_RPC_KEY rpcKey;
1203 IO_STATUS_BLOCK ioStatus;
1204 ULONG bufferLen;
1205
1206 // CdRomCreateWellKnownName(Fdo);
1207
1208 //
1209 // if we have a DVD-ROM
1210 // if we have a rpc0 device
1211 // fake a rpc2 device
1212 // if device does not have a dvd region set
1213 // select a dvd region for the user
1214 //
1215
1216 cddata->DvdRpc0Device = FALSE;
1217
1218 //
1219 // since StartIo() will call IoStartNextPacket() on error, allowing
1220 // StartIo() to be non-recursive prevents stack overflow bugchecks in
1221 // severe error cases (such as fault-injection in the verifier).
1222 //
1223 // the only difference is that the thread context may be different
1224 // in StartIo() than in the caller of IoStartNextPacket().
1225 //
1226
1227 IoSetStartIoAttributes(Fdo, TRUE, TRUE);
1228
1229 //
1230 // check to see if we have a DVD device
1231 //
1232
1233 if (CdRomGetDeviceType(Fdo) != FILE_DEVICE_DVD) {
1234 return STATUS_SUCCESS;
1235 }
1236
1237 //
1238 // we got a DVD drive.
1239 // now, figure out if we have a RPC0 device
1240 //
1241
1242 bufferLen = DVD_RPC_KEY_LENGTH;
1243 copyProtectKey =
1244 (PDVD_COPY_PROTECT_KEY)ExAllocatePoolWithTag(PagedPool,
1245 bufferLen,
1246 DVD_TAG_RPC2_CHECK);
1247
1248 if (copyProtectKey == NULL) {
1249 return STATUS_INSUFFICIENT_RESOURCES;
1250 }
1251
1252 //
1253 // get the device region
1254 //
1255 RtlZeroMemory (copyProtectKey, bufferLen);
1256 copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
1257 copyProtectKey->KeyType = DvdGetRpcKey;
1258
1259 //
1260 // Build a request for READ_KEY
1261 //
1262 ClassSendDeviceIoControlSynchronous(
1263 IOCTL_DVD_READ_KEY,
1264 Fdo,
1265 copyProtectKey,
1266 DVD_RPC_KEY_LENGTH,
1267 DVD_RPC_KEY_LENGTH,
1268 FALSE,
1269 &ioStatus
1270 );
1271
1272 if (!NT_SUCCESS(ioStatus.Status)) {
1273
1274 //
1275 // we have a rpc0 device
1276 //
1277 // NOTE: THIS MODIFIES THE BEHAVIOR OF THE IOCTL
1278 //
1279
1280 cddata->DvdRpc0Device = TRUE;
1281
1282 TraceLog((CdromDebugWarning,
1283 "CdromStartDevice (%p): RPC Phase 1 drive detected\n",
1284 Fdo));
1285
1286 //
1287 // note: we could force this chosen now, but it's better to reduce
1288 // the number of code paths that could be taken. always delay to
1289 // increase the percentage code coverage.
1290 //
1291
1292 TraceLog((CdromDebugWarning,
1293 "CdromStartDevice (%p): Delay DVD Region Selection\n",
1294 Fdo));
1295
1296 cddata->Rpc0SystemRegion = 0xff;
1297 cddata->Rpc0SystemRegionResetCount = DVD_MAX_REGION_RESET_COUNT;
1298 cddata->PickDvdRegion = 1;
1299 cddata->Rpc0RetryRegistryCallback = 1;
1300 ExFreePool(copyProtectKey);
1301 return STATUS_SUCCESS;
1302
1303 } else {
1304
1305 rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
1306
1307 //
1308 // TypeCode of zero means that no region has been set.
1309 //
1310
1311 if (rpcKey->TypeCode == 0) {
1312 TraceLog((CdromDebugWarning,
1313 "CdromStartDevice (%p): must choose DVD region\n",
1314 Fdo));
1315 cddata->PickDvdRegion = 1;
1316 CdRomPickDvdRegion(Fdo);
1317 }
1318 }
1319
1320 ExFreePool (copyProtectKey);
1321
1322 return STATUS_SUCCESS;
1323 }
1324 \f
1325
1326 NTSTATUS
1327 CdRomStopDevice(
1328 IN PDEVICE_OBJECT DeviceObject,
1329 IN UCHAR Type
1330 )
1331 {
1332 return STATUS_SUCCESS;
1333 }
1334 \f
1335
1336 VOID
1337 CdRomStartIo(
1338 IN PDEVICE_OBJECT Fdo,
1339 IN PIRP Irp
1340 )
1341 {
1342
1343 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
1344 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
1345
1346 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1347 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
1348 PIO_STACK_LOCATION irpStack;
1349
1350 PIRP irp2 = NULL;
1351
1352 ULONG transferPages;
1353 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1354 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
1355 PCDROM_DATA cdData;
1356 PSCSI_REQUEST_BLOCK srb = NULL;
1357 PCDB cdb;
1358 PUCHAR senseBuffer = NULL;
1359 PVOID dataBuffer;
1360 NTSTATUS status;
1361 BOOLEAN use6Byte;
1362
1363 //
1364 // Mark IRP with status pending.
1365 //
1366
1367 IoMarkIrpPending(Irp);
1368
1369 cdData = (PCDROM_DATA)(fdoExtension->CommonExtension.DriverData);
1370 use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
1371
1372 //
1373 // if this test is true, then we will exit the routine within this
1374 // code block, queueing the irp for later completion.
1375 //
1376
1377 if ((cdData->Mmc.IsMmc) &&
1378 (cdData->Mmc.UpdateState != CdromMmcUpdateComplete)
1379 ) {
1380
1381 USHORT queueDepth;
1382 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
1383 "CdRomStartIo: [%p] Device needs to update capabilities\n",
1384 Irp));
1385 ASSERT(cdData->Mmc.IsMmc);
1386 ASSERT(cdData->Mmc.CapabilitiesIrp != NULL);
1387 ASSERT(cdData->Mmc.CapabilitiesIrp != Irp);
1388
1389 //
1390 // NOTE - REF #0002
1391 //
1392 // the state was either UpdateRequired (which means we will
1393 // have to start the work item) or UpdateStarted (which means
1394 // we have already started the work item at least once -- may
1395 // transparently change to UpdateComplete).
1396 //
1397 // if it's update required, we just queue it, change to UpdateStarted,
1398 // start the workitem, and start the next packet.
1399 //
1400 // else, we must queue the item and check the queue depth. if the
1401 // queue depth is equal to 1, that means the worker item from the
1402 // previous attempt has already de-queued the items, so we should
1403 // call this routine again (retry) as an optimization rather than
1404 // re-add it this irp to the queue. since this is tail recursion,
1405 // it won't take much/any stack to do this.
1406 //
1407 // NOTE: This presumes the following items are true:
1408 //
1409 // we only add to the list from CdRomStartIo(), which is serialized.
1410 // we only set to UpdateStarted from CdRomStartIo(), and only if
1411 // the state was UpdateRequired.
1412 // we only set to UpdateRequired from CdRomMmcErrorHandler(), and
1413 // only if the state was UpdateComplete.
1414 // we only set to UpdateComplete from the workitem, and assert the
1415 // state was UpdateStarted.
1416 // we flush the entire queue in one atomic operation in the workitem,
1417 // except in the special case described above when we dequeue
1418 // the request immediately.
1419 //
1420 // order of operations is vitally important: queue, then test the depth
1421 // this will prevent lost irps.
1422 //
1423
1424 ExInterlockedPushEntrySList(&(cdData->Mmc.DelayedIrps),
1425 (PSINGLE_LIST_ENTRY)&(Irp->Tail.Overlay.DriverContext[0]),
1426 &(cdData->Mmc.DelayedLock));
1427
1428 queueDepth = ExQueryDepthSList(&(cdData->Mmc.DelayedIrps));
1429 if (queueDepth == 1) {
1430
1431 if (cdData->Mmc.UpdateState == CdromMmcUpdateRequired) {
1432 LONG oldState;
1433
1434 //
1435 // should free any old partition list info that
1436 // we've previously saved away and then start the WorkItem
1437 //
1438
1439 oldState = InterlockedExchange(&cdData->Mmc.UpdateState,
1440 CdromMmcUpdateStarted);
1441 ASSERT(oldState == CdromMmcUpdateRequired);
1442
1443 IoQueueWorkItem(cdData->Mmc.CapabilitiesWorkItem,
1444 CdRomUpdateMmcDriveCapabilities,
1445 DelayedWorkQueue,
1446 NULL);
1447
1448 } else {
1449
1450 //
1451 // they *just* finished updating, so we should flush the list
1452 // back onto the StartIo queue and start the next packet.
1453 //
1454
1455 CdRompFlushDelayedList(Fdo, &(cdData->Mmc), STATUS_SUCCESS, FALSE);
1456
1457 }
1458
1459 }
1460
1461 //
1462 // start the next packet so we don't deadlock....
1463 //
1464
1465 IoStartNextPacket(Fdo, FALSE);
1466 return;
1467
1468 }
1469
1470 //
1471 // If the flag is set in the device object
1472 // force a verify for READ, WRITE and RAW_READ requests
1473 // Note that ioctls are passed through....
1474 //
1475
1476 if (TEST_FLAG(Fdo->Flags, DO_VERIFY_VOLUME) &&
1477 IS_READ_WRITE_REQUEST(currentIrpStack)) {
1478
1479 TraceLog((CdromDebugTrace,
1480 "CdRomStartIo: [%p] Volume needs verified\n", Irp));
1481
1482 if (!(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
1483
1484 if (Irp->Tail.Overlay.Thread) {
1485 IoSetHardErrorOrVerifyDevice(Irp, Fdo);
1486 }
1487
1488 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1489
1490 TraceLog((CdromDebugTrace,
1491 "CdRomStartIo: [%p] Calling UpdateCapcity - "
1492 "ioctl event = %p\n",
1493 Irp,
1494 nextIrpStack->Parameters.Others.Argument1
1495 ));
1496
1497 //
1498 // our device control dispatch routine stores an event in the next
1499 // stack location to signal when startio has completed. We need to
1500 // pass this in so that the update capacity completion routine can
1501 // set it rather than completing the Irp.
1502 //
1503
1504 status = CdRomUpdateCapacity(fdoExtension,
1505 Irp,
1506 nextIrpStack->Parameters.Others.Argument1
1507 );
1508
1509 TraceLog((CdromDebugTrace,
1510 "CdRomStartIo: [%p] UpdateCapacity returned %lx\n",
1511 Irp, status));
1512 return;
1513 }
1514 }
1515
1516 //
1517 // fail writes if they are not allowed...
1518 //
1519
1520 if ((currentIrpStack->MajorFunction == IRP_MJ_WRITE) &&
1521 !(cdData->Mmc.WriteAllowed)) {
1522
1523 TraceLog((CdromDebugError,
1524 "CdRomStartIo: [%p] Device %p failing write request\n",
1525 Irp, Fdo));
1526
1527 Irp->IoStatus.Information = 0;
1528 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1529 BAIL_OUT(Irp);
1530 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1531 return;
1532 }
1533
1534 if (currentIrpStack->MajorFunction == IRP_MJ_READ ||
1535 currentIrpStack->MajorFunction == IRP_MJ_WRITE ) {
1536
1537 ULONG maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;
1538
1539 //
1540 // Add partition byte offset to make starting byte relative to
1541 // beginning of disk.
1542 //
1543
1544 currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
1545 (fdoExtension->CommonExtension.StartingOffset.QuadPart);
1546
1547 //
1548 // Calculate number of pages in this transfer.
1549 //
1550
1551 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
1552 currentIrpStack->Parameters.Read.Length);
1553
1554 //
1555 // Check if request length is greater than the maximum number of
1556 // bytes that the hardware can transfer.
1557 //
1558
1559 if (cdData->RawAccess) {
1560
1561 //
1562 // a writable device must be MMC compliant, which supports
1563 // READ_CD commands.
1564 //
1565
1566 ASSERT(currentIrpStack->MajorFunction != IRP_MJ_WRITE);
1567
1568 ASSERT(!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD));
1569
1570 //
1571 // Fire off a mode select to switch back to cooked sectors.
1572 //
1573
1574 irp2 = IoAllocateIrp((CCHAR)(Fdo->StackSize+1), FALSE);
1575
1576 if (!irp2) {
1577 Irp->IoStatus.Information = 0;
1578 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1579
1580 BAIL_OUT(Irp);
1581 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1582 return;
1583 }
1584
1585 srb = ExAllocatePoolWithTag(NonPagedPool,
1586 sizeof(SCSI_REQUEST_BLOCK),
1587 CDROM_TAG_SRB);
1588 if (!srb) {
1589 IoFreeIrp(irp2);
1590 Irp->IoStatus.Information = 0;
1591 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1592
1593 BAIL_OUT(Irp);
1594 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1595 return;
1596 }
1597
1598 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1599
1600 cdb = (PCDB)srb->Cdb;
1601
1602 //
1603 // Allocate sense buffer.
1604 //
1605
1606 senseBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
1607 SENSE_BUFFER_SIZE,
1608 CDROM_TAG_SENSE_INFO);
1609
1610 if (!senseBuffer) {
1611 ExFreePool(srb);
1612 IoFreeIrp(irp2);
1613 Irp->IoStatus.Information = 0;
1614 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1615
1616 BAIL_OUT(Irp);
1617 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1618 return;
1619 }
1620
1621 //
1622 // Set up the irp.
1623 //
1624
1625 IoSetNextIrpStackLocation(irp2);
1626 irp2->IoStatus.Status = STATUS_SUCCESS;
1627 irp2->IoStatus.Information = 0;
1628 irp2->Flags = 0;
1629 irp2->UserBuffer = NULL;
1630
1631 //
1632 // Save the device object and irp in a private stack location.
1633 //
1634
1635 irpStack = IoGetCurrentIrpStackLocation(irp2);
1636 irpStack->DeviceObject = Fdo;
1637 irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
1638
1639 //
1640 // The retry count will be in the real Irp, as the retry logic will
1641 // recreate our private irp.
1642 //
1643
1644 if (!(nextIrpStack->Parameters.Others.Argument1)) {
1645
1646 //
1647 // Only jam this in if it doesn't exist. The completion routines can
1648 // call StartIo directly in the case of retries and resetting it will
1649 // cause infinite loops.
1650 //
1651
1652 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
1653 }
1654
1655 //
1656 // Construct the IRP stack for the lower level driver.
1657 //
1658
1659 irpStack = IoGetNextIrpStackLocation(irp2);
1660 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1661 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1662 irpStack->Parameters.Scsi.Srb = srb;
1663
1664 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1665 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1666 srb->SrbStatus = srb->ScsiStatus = 0;
1667 srb->NextSrb = 0;
1668 srb->OriginalRequest = irp2;
1669 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1670 srb->SenseInfoBuffer = senseBuffer;
1671
1672 transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
1673
1674 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
1675 transferByteCount,
1676 CDROM_TAG_RAW);
1677
1678 if (!dataBuffer) {
1679 ExFreePool(senseBuffer);
1680 ExFreePool(srb);
1681 IoFreeIrp(irp2);
1682 Irp->IoStatus.Information = 0;
1683 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1684
1685 BAIL_OUT(Irp);
1686 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1687 return;
1688
1689 }
1690
1691 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
1692 transferByteCount,
1693 FALSE,
1694 FALSE,
1695 (PIRP) NULL);
1696
1697 if (!irp2->MdlAddress) {
1698 ExFreePool(senseBuffer);
1699 ExFreePool(srb);
1700 ExFreePool(dataBuffer);
1701 IoFreeIrp(irp2);
1702 Irp->IoStatus.Information = 0;
1703 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1704
1705 BAIL_OUT(Irp);
1706 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1707 return;
1708 }
1709
1710 //
1711 // Prepare the MDL
1712 //
1713
1714 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
1715
1716 srb->DataBuffer = dataBuffer;
1717
1718 //
1719 // Set the new block size in the descriptor.
1720 //
1721
1722 if (use6Byte) {
1723 cdData->BlockDescriptor.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
1724 cdData->BlockDescriptor.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >> 8) & 0xFF;
1725 cdData->BlockDescriptor.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
1726 } else {
1727 cdData->BlockDescriptor10.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
1728 cdData->BlockDescriptor10.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >> 8) & 0xFF;
1729 cdData->BlockDescriptor10.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
1730 }
1731
1732 //
1733 // Move error page into dataBuffer.
1734 //
1735
1736 RtlCopyMemory(srb->DataBuffer, &cdData->Header, transferByteCount);
1737
1738 //
1739 // Build and send a mode select to switch into raw mode.
1740 //
1741
1742 srb->SrbFlags = fdoExtension->SrbFlags;
1743 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
1744 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
1745 srb->DataTransferLength = transferByteCount;
1746 srb->TimeOutValue = fdoExtension->TimeOutValue * 2;
1747
1748 if (use6Byte) {
1749 srb->CdbLength = 6;
1750 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
1751 cdb->MODE_SELECT.PFBit = 1;
1752 cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
1753 } else {
1754 srb->CdbLength = 10;
1755 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
1756 cdb->MODE_SELECT10.PFBit = 1;
1757 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
1758 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
1759 }
1760
1761 //
1762 // Update completion routine.
1763 //
1764
1765 IoSetCompletionRoutine(irp2,
1766 CdRomSwitchModeCompletion,
1767 srb,
1768 TRUE,
1769 TRUE,
1770 TRUE);
1771
1772 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
1773 return;
1774 }
1775
1776
1777 //
1778 // Request needs to be split. Completion of each portion of the
1779 // request will fire off the next portion. The final request will
1780 // signal Io to send a new request.
1781 //
1782
1783 transferPages =
1784 fdoExtension->AdapterDescriptor->MaximumPhysicalPages - 1;
1785
1786 if(maximumTransferLength > (transferPages << PAGE_SHIFT)) {
1787 maximumTransferLength = transferPages << PAGE_SHIFT;
1788 }
1789
1790 //
1791 // Check that the maximum transfer size is not zero
1792 //
1793
1794 if(maximumTransferLength == 0) {
1795 maximumTransferLength = PAGE_SIZE;
1796 }
1797
1798 ClassSplitRequest(Fdo, Irp, maximumTransferLength);
1799 return;
1800
1801 } else if (currentIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
1802
1803 //
1804 // Allocate an irp, srb and associated structures.
1805 //
1806
1807 irp2 = IoAllocateIrp((CCHAR)(Fdo->StackSize+1),
1808 FALSE);
1809
1810 if (!irp2) {
1811 Irp->IoStatus.Information = 0;
1812 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1813
1814 BAIL_OUT(Irp);
1815 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1816 return;
1817 }
1818
1819 srb = ExAllocatePoolWithTag(NonPagedPool,
1820 sizeof(SCSI_REQUEST_BLOCK),
1821 CDROM_TAG_SRB);
1822 if (!srb) {
1823 IoFreeIrp(irp2);
1824 Irp->IoStatus.Information = 0;
1825 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1826
1827 BAIL_OUT(Irp);
1828 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1829 return;
1830 }
1831
1832 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1833
1834 cdb = (PCDB)srb->Cdb;
1835
1836 //
1837 // Allocate sense buffer.
1838 //
1839
1840 senseBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
1841 SENSE_BUFFER_SIZE,
1842 CDROM_TAG_SENSE_INFO);
1843
1844 if (!senseBuffer) {
1845 ExFreePool(srb);
1846 IoFreeIrp(irp2);
1847 Irp->IoStatus.Information = 0;
1848 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1849
1850 BAIL_OUT(Irp);
1851 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1852 return;
1853 }
1854
1855 RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);
1856
1857 //
1858 // Set up the irp.
1859 //
1860
1861 IoSetNextIrpStackLocation(irp2);
1862 irp2->IoStatus.Status = STATUS_SUCCESS;
1863 irp2->IoStatus.Information = 0;
1864 irp2->Flags = 0;
1865 irp2->UserBuffer = NULL;
1866
1867 //
1868 // Save the device object and irp in a private stack location.
1869 //
1870
1871 irpStack = IoGetCurrentIrpStackLocation(irp2);
1872 irpStack->DeviceObject = Fdo;
1873 irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
1874
1875 //
1876 // The retry count will be in the real Irp, as the retry logic will
1877 // recreate our private irp.
1878 //
1879
1880 if (!(nextIrpStack->Parameters.Others.Argument1)) {
1881
1882 //
1883 // Only jam this in if it doesn't exist. The completion routines can
1884 // call StartIo directly in the case of retries and resetting it will
1885 // cause infinite loops.
1886 //
1887
1888 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
1889 }
1890
1891 //
1892 // keep track of the new irp as Argument3
1893 //
1894
1895 nextIrpStack->Parameters.Others.Argument3 = irp2;
1896
1897
1898 //
1899 // Construct the IRP stack for the lower level driver.
1900 //
1901
1902 irpStack = IoGetNextIrpStackLocation(irp2);
1903 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1904 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1905 irpStack->Parameters.Scsi.Srb = srb;
1906
1907 IoSetCompletionRoutine(irp2,
1908 CdRomDeviceControlCompletion,
1909 srb,
1910 TRUE,
1911 TRUE,
1912 TRUE);
1913 //
1914 // Setup those fields that are generic to all requests.
1915 //
1916
1917 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1918 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1919 srb->SrbStatus = srb->ScsiStatus = 0;
1920 srb->NextSrb = 0;
1921 srb->OriginalRequest = irp2;
1922 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1923 srb->SenseInfoBuffer = senseBuffer;
1924
1925 switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
1926
1927
1928 case IOCTL_CDROM_RAW_READ: {
1929
1930 //
1931 // Determine whether the drive is currently in raw or cooked mode,
1932 // and which command to use to read the data.
1933 //
1934
1935 if (!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD)) {
1936
1937 PRAW_READ_INFO rawReadInfo =
1938 (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
1939 ULONG maximumTransferLength;
1940 ULONG transferPages;
1941
1942 if (cdData->RawAccess) {
1943
1944 ULONG startingSector;
1945 UCHAR min, sec, frame;
1946
1947 //
1948 // Free the recently allocated irp, as we don't need it.
1949 //
1950
1951 IoFreeIrp(irp2);
1952
1953 cdb = (PCDB)srb->Cdb;
1954 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
1955
1956 //
1957 // Calculate starting offset.
1958 //
1959
1960 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> fdoExtension->SectorShift);
1961 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
1962 maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;
1963 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
1964 transferByteCount);
1965
1966 //
1967 // Determine if request is within limits imposed by miniport.
1968 //
1969 if (transferByteCount > maximumTransferLength ||
1970 transferPages > fdoExtension->AdapterDescriptor->MaximumPhysicalPages) {
1971
1972 //
1973 // The claim is that this won't happen, and is backed up by
1974 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
1975 // we get only 4 sector requests.
1976 //
1977
1978 ExFreePool(senseBuffer);
1979 ExFreePool(srb);
1980
1981 Irp->IoStatus.Information = 0;
1982 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1983
1984 BAIL_OUT(Irp);
1985 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
1986 return;
1987
1988 }
1989
1990 srb->OriginalRequest = Irp;
1991 srb->SrbFlags = fdoExtension->SrbFlags;
1992 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
1993 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
1994 srb->DataTransferLength = transferByteCount;
1995 srb->TimeOutValue = fdoExtension->TimeOutValue;
1996 srb->CdbLength = 10;
1997 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
1998
1999 if (rawReadInfo->TrackMode == CDDA) {
2000 if (TEST_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA)) {
2001
2002 srb->CdbLength = 12;
2003
2004 cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
2005 cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
2006 cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
2007 cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
2008
2009 cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
2010 cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
2011 cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
2012 cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
2013
2014 cdb->PLXTR_READ_CDDA.SubCode = 0;
2015 cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
2016
2017 } else if (TEST_FLAG(cdData->XAFlags, XA_NEC_CDDA)) {
2018
2019 cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
2020 cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
2021 cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
2022 cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
2023
2024 cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
2025 cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
2026
2027 cdb->NEC_READ_CDDA.OperationCode = 0xD4;
2028 }
2029 } else {
2030
2031 cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8);
2032 cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
2033
2034 cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
2035 cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
2036 cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
2037 cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
2038
2039 cdb->CDB10.OperationCode = SCSIOP_READ;
2040 }
2041
2042 srb->SrbStatus = srb->ScsiStatus = 0;
2043
2044 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
2045 nextIrpStack->Parameters.Scsi.Srb = srb;
2046
2047 // HACKHACK - REF #0001
2048
2049 //
2050 // Set up IoCompletion routine address.
2051 //
2052
2053 IoSetCompletionRoutine(Irp,
2054 CdRomXACompletion,
2055 srb,
2056 TRUE,
2057 TRUE,
2058 TRUE);
2059
2060 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, Irp);
2061 return;
2062
2063 } else {
2064
2065 transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
2066 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2067 transferByteCount,
2068 CDROM_TAG_RAW );
2069 if (!dataBuffer) {
2070 ExFreePool(senseBuffer);
2071 ExFreePool(srb);
2072 IoFreeIrp(irp2);
2073 Irp->IoStatus.Information = 0;
2074 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2075
2076 BAIL_OUT(Irp);
2077 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2078 return;
2079
2080 }
2081
2082 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2083 transferByteCount,
2084 FALSE,
2085 FALSE,
2086 (PIRP) NULL);
2087
2088 if (!irp2->MdlAddress) {
2089 ExFreePool(senseBuffer);
2090 ExFreePool(srb);
2091 ExFreePool(dataBuffer);
2092 IoFreeIrp(irp2);
2093 Irp->IoStatus.Information = 0;
2094 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2095
2096 BAIL_OUT(Irp);
2097 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2098 return;
2099 }
2100
2101 //
2102 // Prepare the MDL
2103 //
2104
2105 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2106
2107 srb->DataBuffer = dataBuffer;
2108
2109 //
2110 // Set the new block size in the descriptor.
2111 // This will set the block read size to RAW_SECTOR_SIZE
2112 // TODO: Set density code, based on operation
2113 //
2114
2115 if (use6Byte) {
2116 cdData->BlockDescriptor.BlockLength[0] = (UCHAR)(RAW_SECTOR_SIZE >> 16) & 0xFF;
2117 cdData->BlockDescriptor.BlockLength[1] = (UCHAR)(RAW_SECTOR_SIZE >> 8) & 0xFF;
2118 cdData->BlockDescriptor.BlockLength[2] = (UCHAR)(RAW_SECTOR_SIZE & 0xFF);
2119 cdData->BlockDescriptor.DensityCode = 0;
2120 } else {
2121 cdData->BlockDescriptor10.BlockLength[0] = (UCHAR)(RAW_SECTOR_SIZE >> 16) & 0xFF;
2122 cdData->BlockDescriptor10.BlockLength[1] = (UCHAR)(RAW_SECTOR_SIZE >> 8) & 0xFF;
2123 cdData->BlockDescriptor10.BlockLength[2] = (UCHAR)(RAW_SECTOR_SIZE & 0xFF);
2124 cdData->BlockDescriptor10.DensityCode = 0;
2125 }
2126
2127 //
2128 // Move error page into dataBuffer.
2129 //
2130
2131 RtlCopyMemory(srb->DataBuffer, &cdData->Header, transferByteCount);
2132
2133
2134 //
2135 // Build and send a mode select to switch into raw mode.
2136 //
2137
2138 srb->SrbFlags = fdoExtension->SrbFlags;
2139 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2140 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
2141 srb->DataTransferLength = transferByteCount;
2142 srb->TimeOutValue = fdoExtension->TimeOutValue * 2;
2143
2144 if (use6Byte) {
2145 srb->CdbLength = 6;
2146 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
2147 cdb->MODE_SELECT.PFBit = 1;
2148 cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
2149 } else {
2150
2151 srb->CdbLength = 10;
2152 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
2153 cdb->MODE_SELECT10.PFBit = 1;
2154 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
2155 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
2156 }
2157
2158 //
2159 // Update completion routine.
2160 //
2161
2162 IoSetCompletionRoutine(irp2,
2163 CdRomSwitchModeCompletion,
2164 srb,
2165 TRUE,
2166 TRUE,
2167 TRUE);
2168
2169 }
2170
2171 } else {
2172
2173 PRAW_READ_INFO rawReadInfo =
2174 (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
2175 ULONG startingSector;
2176
2177 //
2178 // Free the recently allocated irp, as we don't need it.
2179 //
2180
2181 IoFreeIrp(irp2);
2182
2183 cdb = (PCDB)srb->Cdb;
2184 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
2185
2186
2187 //
2188 // Calculate starting offset.
2189 //
2190
2191 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> fdoExtension->SectorShift);
2192 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
2193
2194 srb->OriginalRequest = Irp;
2195 srb->SrbFlags = fdoExtension->SrbFlags;
2196 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2197 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
2198 srb->DataTransferLength = transferByteCount;
2199 srb->TimeOutValue = fdoExtension->TimeOutValue;
2200 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
2201 srb->CdbLength = 12;
2202 srb->SrbStatus = srb->ScsiStatus = 0;
2203
2204 //
2205 // Fill in CDB fields.
2206 //
2207
2208 cdb = (PCDB)srb->Cdb;
2209
2210
2211 cdb->READ_CD.TransferBlocks[2] = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
2212 cdb->READ_CD.TransferBlocks[1] = (UCHAR) (rawReadInfo->SectorCount >> 8 );
2213 cdb->READ_CD.TransferBlocks[0] = (UCHAR) (rawReadInfo->SectorCount >> 16);
2214
2215
2216 cdb->READ_CD.StartingLBA[3] = (UCHAR) (startingSector & 0xFF);
2217 cdb->READ_CD.StartingLBA[2] = (UCHAR) ((startingSector >> 8));
2218 cdb->READ_CD.StartingLBA[1] = (UCHAR) ((startingSector >> 16));
2219 cdb->READ_CD.StartingLBA[0] = (UCHAR) ((startingSector >> 24));
2220
2221 //
2222 // Setup cdb depending upon the sector type we want.
2223 //
2224
2225 switch (rawReadInfo->TrackMode) {
2226 case CDDA:
2227
2228 cdb->READ_CD.ExpectedSectorType = CD_DA_SECTOR;
2229 cdb->READ_CD.IncludeUserData = 1;
2230 cdb->READ_CD.HeaderCode = 3;
2231 cdb->READ_CD.IncludeSyncData = 1;
2232 break;
2233
2234 case YellowMode2:
2235
2236 cdb->READ_CD.ExpectedSectorType = YELLOW_MODE2_SECTOR;
2237 cdb->READ_CD.IncludeUserData = 1;
2238 cdb->READ_CD.HeaderCode = 1;
2239 cdb->READ_CD.IncludeSyncData = 1;
2240 break;
2241
2242 case XAForm2:
2243
2244 cdb->READ_CD.ExpectedSectorType = FORM2_MODE2_SECTOR;
2245 cdb->READ_CD.IncludeUserData = 1;
2246 cdb->READ_CD.HeaderCode = 3;
2247 cdb->READ_CD.IncludeSyncData = 1;
2248 break;
2249
2250 default:
2251 ExFreePool(senseBuffer);
2252 ExFreePool(srb);
2253 Irp->IoStatus.Information = 0;
2254 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2255
2256 BAIL_OUT(Irp);
2257 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2258 return;
2259 }
2260
2261 cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
2262
2263 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
2264 nextIrpStack->Parameters.Scsi.Srb = srb;
2265
2266 // HACKHACK - REF #0001
2267
2268 //
2269 // Set up IoCompletion routine address.
2270 //
2271
2272 IoSetCompletionRoutine(Irp,
2273 CdRomXACompletion,
2274 srb,
2275 TRUE,
2276 TRUE,
2277 TRUE);
2278
2279 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, Irp);
2280 return;
2281
2282 }
2283
2284 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2285 return;
2286 }
2287
2288 //
2289 // the _EX version does the same thing on the front end
2290 //
2291
2292 case IOCTL_DISK_GET_LENGTH_INFO:
2293 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
2294 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
2295 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX:
2296 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
2297
2298 //
2299 // Issue ReadCapacity to update device extension
2300 // with information for current media.
2301 //
2302
2303 TraceLog((CdromDebugError,
2304 "CdRomStartIo: Get drive geometry/length "
2305 "info (%p)\n", Irp));
2306
2307 //
2308 // setup remaining srb and cdb parameters.
2309 //
2310
2311 srb->SrbFlags = fdoExtension->SrbFlags;
2312 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2313 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
2314 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
2315 srb->CdbLength = 10;
2316 srb->TimeOutValue = fdoExtension->TimeOutValue;
2317
2318 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2319 sizeof(READ_CAPACITY_DATA),
2320 CDROM_TAG_READ_CAP);
2321 if (!dataBuffer) {
2322 ExFreePool(senseBuffer);
2323 ExFreePool(srb);
2324 IoFreeIrp(irp2);
2325 Irp->IoStatus.Information = 0;
2326 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2327
2328 BAIL_OUT(Irp);
2329 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2330 return;
2331
2332 }
2333
2334 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2335 sizeof(READ_CAPACITY_DATA),
2336 FALSE,
2337 FALSE,
2338 (PIRP) NULL);
2339
2340 if (!irp2->MdlAddress) {
2341 ExFreePool(senseBuffer);
2342 ExFreePool(srb);
2343 ExFreePool(dataBuffer);
2344 IoFreeIrp(irp2);
2345 Irp->IoStatus.Information = 0;
2346 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2347
2348 BAIL_OUT(Irp);
2349 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2350 return;
2351 }
2352
2353 //
2354 // Prepare the MDL
2355 //
2356
2357 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2358
2359 srb->DataBuffer = dataBuffer;
2360 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
2361
2362 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2363 return;
2364 }
2365
2366 case IOCTL_CDROM_GET_CONFIGURATION: {
2367
2368 PGET_CONFIGURATION_IOCTL_INPUT inputBuffer;
2369
2370 TraceLog((CdromDebugError,
2371 "CdRomStartIo: Get configuration (%p)\n", Irp));
2372
2373 if (!cdData->Mmc.IsMmc) {
2374 ExFreePool(senseBuffer);
2375 ExFreePool(srb);
2376 IoFreeIrp(irp2);
2377 Irp->IoStatus.Information = 0;
2378 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
2379 BAIL_OUT(Irp);
2380 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2381 return;
2382 }
2383
2384 transferByteCount = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
2385
2386 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2387 transferByteCount,
2388 CDROM_TAG_GET_CONFIG);
2389 if (!dataBuffer) {
2390 ExFreePool(senseBuffer);
2391 ExFreePool(srb);
2392 IoFreeIrp(irp2);
2393 Irp->IoStatus.Information = 0;
2394 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2395 BAIL_OUT(Irp);
2396 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2397 return;
2398 }
2399
2400 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2401 transferByteCount,
2402 FALSE,
2403 FALSE,
2404 (PIRP) NULL);
2405 if (!irp2->MdlAddress) {
2406 ExFreePool(dataBuffer);
2407 ExFreePool(senseBuffer);
2408 ExFreePool(srb);
2409 IoFreeIrp(irp2);
2410 Irp->IoStatus.Information = 0;
2411 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2412 BAIL_OUT(Irp);
2413 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2414 return;
2415 }
2416
2417 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2418
2419 //
2420 // setup remaining srb and cdb parameters
2421 //
2422
2423 srb->SrbFlags = fdoExtension->SrbFlags;
2424 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
2425 srb->DataTransferLength = transferByteCount;
2426 srb->CdbLength = 10;
2427 srb->TimeOutValue = fdoExtension->TimeOutValue;
2428 srb->DataBuffer = dataBuffer;
2429
2430 cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION;
2431 cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(transferByteCount >> 8);
2432 cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(transferByteCount & 0xff);
2433
2434 inputBuffer = (PGET_CONFIGURATION_IOCTL_INPUT)Irp->AssociatedIrp.SystemBuffer;
2435 cdb->GET_CONFIGURATION.StartingFeature[0] = (UCHAR)(inputBuffer->Feature >> 8);
2436 cdb->GET_CONFIGURATION.StartingFeature[1] = (UCHAR)(inputBuffer->Feature & 0xff);
2437 cdb->GET_CONFIGURATION.RequestType = (UCHAR)(inputBuffer->RequestType);
2438
2439 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2440 return;
2441 }
2442
2443 case IOCTL_DISK_VERIFY: {
2444
2445 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
2446 LARGE_INTEGER byteOffset;
2447 ULONG sectorOffset;
2448 USHORT sectorCount;
2449
2450 if (!cdData->Mmc.WriteAllowed) {
2451 ExFreePool(senseBuffer);
2452 ExFreePool(srb);
2453 IoFreeIrp(irp2);
2454 Irp->IoStatus.Information = 0;
2455 Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;
2456 BAIL_OUT(Irp);
2457 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2458 return;
2459 }
2460 //
2461 // Verify sectors
2462 //
2463
2464 srb->CdbLength = 10;
2465
2466 cdb->CDB10.OperationCode = SCSIOP_VERIFY;
2467
2468 //
2469 // Add disk offset to starting sector.
2470 //
2471
2472 byteOffset.QuadPart = commonExtension->StartingOffset.QuadPart +
2473 verifyInfo->StartingOffset.QuadPart;
2474
2475 //
2476 // Convert byte offset to sector offset.
2477 //
2478
2479 sectorOffset = (ULONG)(byteOffset.QuadPart >> fdoExtension->SectorShift);
2480
2481 //
2482 // Convert ULONG byte count to USHORT sector count.
2483 //
2484
2485 sectorCount = (USHORT)(verifyInfo->Length >> fdoExtension->SectorShift);
2486
2487 //
2488 // Move little endian values into CDB in big endian format.
2489 //
2490
2491 cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
2492 cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
2493 cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
2494 cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
2495
2496 cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&sectorCount)->Byte1;
2497 cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&sectorCount)->Byte0;
2498
2499 //
2500 // The verify command is used by the NT FORMAT utility and
2501 // requests are sent down for 5% of the volume size. The
2502 // request timeout value is calculated based on the number of
2503 // sectors verified.
2504 //
2505
2506 srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
2507 fdoExtension->TimeOutValue;
2508
2509 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2510 return;
2511 }
2512
2513 case IOCTL_STORAGE_CHECK_VERIFY:
2514 case IOCTL_DISK_CHECK_VERIFY:
2515 case IOCTL_CDROM_CHECK_VERIFY: {
2516
2517 //
2518 // Since a test unit ready is about to be performed, reset the
2519 // timer value to decrease the opportunities for it to race with
2520 // this code.
2521 //
2522
2523 ClassResetMediaChangeTimer(fdoExtension);
2524
2525 //
2526 // Set up the SRB/CDB
2527 //
2528
2529 srb->CdbLength = 6;
2530 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
2531 srb->TimeOutValue = fdoExtension->TimeOutValue * 2;
2532 srb->SrbFlags = fdoExtension->SrbFlags;
2533 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2534 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
2535
2536
2537 TraceLog((CdromDebugTrace,
2538 "CdRomStartIo: [%p] Sending CHECK_VERIFY irp %p\n",
2539 Irp, irp2));
2540 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2541 return;
2542 }
2543
2544 case IOCTL_DVD_READ_STRUCTURE: {
2545
2546 CdRomDeviceControlDvdReadStructure(Fdo, Irp, irp2, srb);
2547 return;
2548
2549 }
2550
2551 case IOCTL_DVD_END_SESSION: {
2552 CdRomDeviceControlDvdEndSession(Fdo, Irp, irp2, srb);
2553 return;
2554 }
2555
2556 case IOCTL_DVD_START_SESSION:
2557 case IOCTL_DVD_READ_KEY: {
2558
2559 CdRomDeviceControlDvdStartSessionReadKey(Fdo, Irp, irp2, srb);
2560 return;
2561
2562 }
2563
2564
2565 case IOCTL_DVD_SEND_KEY:
2566 case IOCTL_DVD_SEND_KEY2: {
2567
2568 CdRomDeviceControlDvdSendKey (Fdo, Irp, irp2, srb);
2569 return;
2570
2571
2572 }
2573
2574 case IOCTL_CDROM_READ_TOC_EX: {
2575
2576 PCDROM_READ_TOC_EX inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2577
2578 transferByteCount = currentIrpStack->Parameters.Read.Length;
2579
2580 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2581 transferByteCount,
2582 CDROM_TAG_TOC);
2583 if (!dataBuffer) {
2584 ExFreePool(senseBuffer);
2585 ExFreePool(srb);
2586 IoFreeIrp(irp2);
2587 Irp->IoStatus.Information = 0;
2588 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2589
2590 BAIL_OUT(Irp);
2591 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2592 return;
2593
2594 }
2595
2596 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2597 transferByteCount,
2598 FALSE,
2599 FALSE,
2600 (PIRP) NULL);
2601
2602 if (!irp2->MdlAddress) {
2603 ExFreePool(senseBuffer);
2604 ExFreePool(srb);
2605 ExFreePool(dataBuffer);
2606 IoFreeIrp(irp2);
2607 Irp->IoStatus.Information = 0;
2608 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2609
2610 BAIL_OUT(Irp);
2611 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2612 return;
2613 }
2614
2615 //
2616 // setup the request per user request
2617 // do validity checking in devctl dispatch, not here
2618 //
2619
2620 cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
2621 cdb->READ_TOC.Msf = inputBuffer->Msf;
2622 cdb->READ_TOC.Format2 = inputBuffer->Format;
2623 cdb->READ_TOC.StartingTrack = inputBuffer->SessionTrack;
2624 cdb->READ_TOC.AllocationLength[0] = (UCHAR)(transferByteCount >> 8);
2625 cdb->READ_TOC.AllocationLength[1] = (UCHAR)(transferByteCount & 0xff);
2626
2627 //
2628 // Prepare the MDL
2629 //
2630
2631 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2632
2633 //
2634 // do the standard stuff....
2635 //
2636
2637 srb->SrbFlags = fdoExtension->SrbFlags;
2638 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2639 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
2640 srb->DataTransferLength = transferByteCount;
2641 srb->CdbLength = 10;
2642 srb->TimeOutValue = fdoExtension->TimeOutValue;
2643 srb->DataBuffer = dataBuffer;
2644
2645 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2646 return;
2647 }
2648
2649 case IOCTL_CDROM_GET_LAST_SESSION:
2650 case IOCTL_CDROM_READ_TOC: {
2651
2652 if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
2653 IOCTL_CDROM_GET_LAST_SESSION) {
2654
2655 //
2656 // Set format to return first and last session numbers.
2657 //
2658
2659 cdb->READ_TOC.Format = CDROM_READ_TOC_EX_FORMAT_SESSION;
2660
2661 } else {
2662
2663 //
2664 // Use MSF addressing
2665 //
2666
2667 cdb->READ_TOC.Msf = 1;
2668
2669 }
2670
2671
2672 transferByteCount =
2673 currentIrpStack->Parameters.Read.Length >
2674 sizeof(CDROM_TOC) ? sizeof(CDROM_TOC):
2675 currentIrpStack->Parameters.Read.Length;
2676
2677 //
2678 // Set size of TOC structure.
2679 //
2680
2681 cdb->READ_TOC.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
2682 cdb->READ_TOC.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
2683
2684 //
2685 // setup remaining srb and cdb parameters.
2686 //
2687
2688 srb->SrbFlags = fdoExtension->SrbFlags;
2689 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2690 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
2691 srb->DataTransferLength = transferByteCount;
2692 srb->CdbLength = 10;
2693 srb->TimeOutValue = fdoExtension->TimeOutValue;
2694
2695 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2696 transferByteCount,
2697 CDROM_TAG_TOC);
2698 if (!dataBuffer) {
2699 ExFreePool(senseBuffer);
2700 ExFreePool(srb);
2701 IoFreeIrp(irp2);
2702 Irp->IoStatus.Information = 0;
2703 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2704
2705 BAIL_OUT(Irp);
2706 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2707 return;
2708
2709 }
2710
2711 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2712 transferByteCount,
2713 FALSE,
2714 FALSE,
2715 (PIRP) NULL);
2716
2717 if (!irp2->MdlAddress) {
2718 ExFreePool(senseBuffer);
2719 ExFreePool(srb);
2720 ExFreePool(dataBuffer);
2721 IoFreeIrp(irp2);
2722 Irp->IoStatus.Information = 0;
2723 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2724
2725 BAIL_OUT(Irp);
2726 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2727 return;
2728 }
2729
2730 //
2731 // Prepare the MDL
2732 //
2733
2734 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2735
2736 srb->DataBuffer = dataBuffer;
2737 cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
2738
2739 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2740 return;
2741
2742 }
2743
2744 case IOCTL_CDROM_PLAY_AUDIO_MSF: {
2745
2746 PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2747
2748 //
2749 // Set up the SRB/CDB
2750 //
2751
2752 srb->CdbLength = 10;
2753 cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
2754
2755 cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
2756 cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
2757 cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
2758
2759 cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
2760 cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
2761 cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
2762
2763 srb->TimeOutValue = fdoExtension->TimeOutValue;
2764 srb->SrbFlags = fdoExtension->SrbFlags;
2765 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2766 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
2767
2768 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2769 return;
2770
2771 }
2772
2773 case IOCTL_CDROM_READ_Q_CHANNEL: {
2774
2775 PSUB_Q_CHANNEL_DATA userChannelData =
2776 Irp->AssociatedIrp.SystemBuffer;
2777 PCDROM_SUB_Q_DATA_FORMAT inputBuffer =
2778 Irp->AssociatedIrp.SystemBuffer;
2779
2780 //
2781 // Allocate buffer for subq channel information.
2782 //
2783
2784 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2785 sizeof(SUB_Q_CHANNEL_DATA),
2786 CDROM_TAG_SUB_Q);
2787
2788 if (!dataBuffer) {
2789 ExFreePool(senseBuffer);
2790 ExFreePool(srb);
2791 IoFreeIrp(irp2);
2792 Irp->IoStatus.Information = 0;
2793 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2794
2795 BAIL_OUT(Irp);
2796 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2797 return;
2798
2799 }
2800
2801 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2802 sizeof(SUB_Q_CHANNEL_DATA),
2803 FALSE,
2804 FALSE,
2805 (PIRP) NULL);
2806
2807 if (!irp2->MdlAddress) {
2808 ExFreePool(senseBuffer);
2809 ExFreePool(srb);
2810 ExFreePool(dataBuffer);
2811 IoFreeIrp(irp2);
2812 Irp->IoStatus.Information = 0;
2813 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2814
2815 BAIL_OUT(Irp);
2816 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2817 return;
2818 }
2819
2820 //
2821 // Prepare the MDL
2822 //
2823
2824 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2825
2826 srb->DataBuffer = dataBuffer;
2827
2828 //
2829 // Always logical unit 0, but only use MSF addressing
2830 // for IOCTL_CDROM_CURRENT_POSITION
2831 //
2832
2833 if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION)
2834 cdb->SUBCHANNEL.Msf = CDB_USE_MSF;
2835
2836 //
2837 // Return subchannel data
2838 //
2839
2840 cdb->SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK;
2841
2842 //
2843 // Specify format of informatin to return
2844 //
2845
2846 cdb->SUBCHANNEL.Format = inputBuffer->Format;
2847
2848 //
2849 // Specify which track to access (only used by Track ISRC reads)
2850 //
2851
2852 if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC) {
2853 cdb->SUBCHANNEL.TrackNumber = inputBuffer->Track;
2854 }
2855
2856 //
2857 // Set size of channel data -- however, this is dependent on
2858 // what information we are requesting (which Format)
2859 //
2860
2861 switch( inputBuffer->Format ) {
2862
2863 case IOCTL_CDROM_CURRENT_POSITION:
2864 transferByteCount = sizeof(SUB_Q_CURRENT_POSITION);
2865 break;
2866
2867 case IOCTL_CDROM_MEDIA_CATALOG:
2868 transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
2869 break;
2870
2871 case IOCTL_CDROM_TRACK_ISRC:
2872 transferByteCount = sizeof(SUB_Q_TRACK_ISRC);
2873 break;
2874 }
2875
2876 cdb->SUBCHANNEL.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
2877 cdb->SUBCHANNEL.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
2878 cdb->SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL;
2879 srb->SrbFlags = fdoExtension->SrbFlags;
2880 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2881 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
2882 srb->DataTransferLength = transferByteCount;
2883 srb->CdbLength = 10;
2884 srb->TimeOutValue = fdoExtension->TimeOutValue;
2885
2886 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2887 return;
2888
2889 }
2890
2891 case IOCTL_CDROM_PAUSE_AUDIO: {
2892
2893 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
2894 cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE;
2895
2896 srb->CdbLength = 10;
2897 srb->TimeOutValue = fdoExtension->TimeOutValue;
2898 srb->SrbFlags = fdoExtension->SrbFlags;
2899 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2900 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
2901
2902 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2903 return;
2904 }
2905
2906 case IOCTL_CDROM_RESUME_AUDIO: {
2907
2908 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
2909 cdb->PAUSE_RESUME.Action = CDB_AUDIO_RESUME;
2910
2911 srb->CdbLength = 10;
2912 srb->TimeOutValue = fdoExtension->TimeOutValue;
2913 srb->SrbFlags = fdoExtension->SrbFlags;
2914 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2915 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
2916
2917 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2918 return;
2919 }
2920
2921 case IOCTL_CDROM_SEEK_AUDIO_MSF: {
2922
2923 PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2924 ULONG logicalBlockAddress;
2925
2926 logicalBlockAddress = MSF_TO_LBA(inputBuffer->M, inputBuffer->S, inputBuffer->F);
2927
2928 cdb->SEEK.OperationCode = SCSIOP_SEEK;
2929 cdb->SEEK.LogicalBlockAddress[0] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
2930 cdb->SEEK.LogicalBlockAddress[1] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
2931 cdb->SEEK.LogicalBlockAddress[2] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
2932 cdb->SEEK.LogicalBlockAddress[3] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
2933
2934 srb->CdbLength = 10;
2935 srb->TimeOutValue = fdoExtension->TimeOutValue;
2936 srb->SrbFlags = fdoExtension->SrbFlags;
2937 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2938 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
2939
2940 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2941 return;
2942
2943 }
2944
2945 case IOCTL_CDROM_STOP_AUDIO: {
2946
2947 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
2948 cdb->START_STOP.Immediate = 1;
2949 cdb->START_STOP.Start = 0;
2950 cdb->START_STOP.LoadEject = 0;
2951
2952 srb->CdbLength = 6;
2953 srb->TimeOutValue = fdoExtension->TimeOutValue;
2954
2955 srb->SrbFlags = fdoExtension->SrbFlags;
2956 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2957 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
2958
2959 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
2960 return;
2961 }
2962
2963 case IOCTL_CDROM_GET_CONTROL: {
2964
2965 PAUDIO_OUTPUT audioOutput;
2966 PCDROM_AUDIO_CONTROL audioControl = Irp->AssociatedIrp.SystemBuffer;
2967
2968 //
2969 // Allocate buffer for volume control information.
2970 //
2971
2972 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2973 MODE_DATA_SIZE,
2974 CDROM_TAG_VOLUME);
2975
2976 if (!dataBuffer) {
2977 ExFreePool(senseBuffer);
2978 ExFreePool(srb);
2979 IoFreeIrp(irp2);
2980 Irp->IoStatus.Information = 0;
2981 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2982
2983 BAIL_OUT(Irp);
2984 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
2985 return;
2986
2987 }
2988
2989 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2990 MODE_DATA_SIZE,
2991 FALSE,
2992 FALSE,
2993 (PIRP) NULL);
2994
2995 if (!irp2->MdlAddress) {
2996 ExFreePool(senseBuffer);
2997 ExFreePool(srb);
2998 ExFreePool(dataBuffer);
2999 IoFreeIrp(irp2);
3000 Irp->IoStatus.Information = 0;
3001 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3002
3003 BAIL_OUT(Irp);
3004 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
3005 return;
3006 }
3007
3008 //
3009 // Prepare the MDL
3010 //
3011
3012 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
3013 srb->DataBuffer = dataBuffer;
3014
3015 RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
3016
3017 //
3018 // Setup for either 6 or 10 byte CDBs.
3019 //
3020
3021 if (use6Byte) {
3022
3023 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
3024 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
3025 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
3026
3027 //
3028 // Disable block descriptors.
3029 //
3030
3031 cdb->MODE_SENSE.Dbd = TRUE;
3032
3033 srb->CdbLength = 6;
3034 } else {
3035
3036 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
3037 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
3038 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
3039 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
3040
3041 //
3042 // Disable block descriptors.
3043 //
3044
3045 cdb->MODE_SENSE10.Dbd = TRUE;
3046
3047 srb->CdbLength = 10;
3048 }
3049
3050 srb->TimeOutValue = fdoExtension->TimeOutValue;
3051 srb->DataTransferLength = MODE_DATA_SIZE;
3052 srb->SrbFlags = fdoExtension->SrbFlags;
3053 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
3054 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
3055
3056 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
3057 return;
3058
3059 }
3060
3061 case IOCTL_CDROM_GET_VOLUME:
3062 case IOCTL_CDROM_SET_VOLUME: {
3063
3064 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
3065 MODE_DATA_SIZE,
3066 CDROM_TAG_VOLUME);
3067
3068 if (!dataBuffer) {
3069 ExFreePool(senseBuffer);
3070 ExFreePool(srb);
3071 IoFreeIrp(irp2);
3072 Irp->IoStatus.Information = 0;
3073 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3074
3075 BAIL_OUT(Irp);
3076 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
3077 return;
3078 }
3079
3080 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
3081 MODE_DATA_SIZE,
3082 FALSE,
3083 FALSE,
3084 (PIRP) NULL);
3085
3086 if (!irp2->MdlAddress) {
3087 ExFreePool(senseBuffer);
3088 ExFreePool(srb);
3089 ExFreePool(dataBuffer);
3090 IoFreeIrp(irp2);
3091 Irp->IoStatus.Information = 0;
3092 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3093
3094 BAIL_OUT(Irp);
3095 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
3096 return;
3097 }
3098
3099 //
3100 // Prepare the MDL
3101 //
3102
3103 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
3104 srb->DataBuffer = dataBuffer;
3105
3106 RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
3107
3108
3109 if (use6Byte) {
3110
3111 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
3112 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
3113 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
3114
3115 srb->CdbLength = 6;
3116
3117 } else {
3118
3119 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
3120 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
3121 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
3122 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
3123
3124 srb->CdbLength = 10;
3125 }
3126
3127 srb->TimeOutValue = fdoExtension->TimeOutValue;
3128 srb->DataTransferLength = MODE_DATA_SIZE;
3129 srb->SrbFlags = fdoExtension->SrbFlags;
3130 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
3131 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
3132
3133 if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_SET_VOLUME) {
3134
3135 //
3136 // Setup a different completion routine as the mode sense data is needed in order
3137 // to send the mode select.
3138 //
3139
3140 IoSetCompletionRoutine(irp2,
3141 CdRomSetVolumeIntermediateCompletion,
3142 srb,
3143 TRUE,
3144 TRUE,
3145 TRUE);
3146
3147 }
3148
3149 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
3150 return;
3151
3152 }
3153
3154 case IOCTL_STORAGE_SET_READ_AHEAD: {
3155
3156 PSTORAGE_SET_READ_AHEAD readAhead = Irp->AssociatedIrp.SystemBuffer;
3157
3158 ULONG blockAddress;
3159 PFOUR_BYTE fourByte = (PFOUR_BYTE) &blockAddress;
3160
3161 //
3162 // setup the SRB for a set readahead command
3163 //
3164
3165 cdb->SET_READ_AHEAD.OperationCode = SCSIOP_SET_READ_AHEAD;
3166
3167 blockAddress = (ULONG) (readAhead->TriggerAddress.QuadPart >>
3168 fdoExtension->SectorShift);
3169
3170 cdb->SET_READ_AHEAD.TriggerLBA[0] = fourByte->Byte3;
3171 cdb->SET_READ_AHEAD.TriggerLBA[1] = fourByte->Byte2;
3172 cdb->SET_READ_AHEAD.TriggerLBA[2] = fourByte->Byte1;
3173 cdb->SET_READ_AHEAD.TriggerLBA[3] = fourByte->Byte0;
3174
3175 blockAddress = (ULONG) (readAhead->TargetAddress.QuadPart >>
3176 fdoExtension->SectorShift);
3177
3178 cdb->SET_READ_AHEAD.ReadAheadLBA[0] = fourByte->Byte3;
3179 cdb->SET_READ_AHEAD.ReadAheadLBA[1] = fourByte->Byte2;
3180 cdb->SET_READ_AHEAD.ReadAheadLBA[2] = fourByte->Byte1;
3181 cdb->SET_READ_AHEAD.ReadAheadLBA[3] = fourByte->Byte0;
3182
3183 srb->CdbLength = 12;
3184 srb->TimeOutValue = fdoExtension->TimeOutValue;
3185
3186 srb->SrbFlags = fdoExtension->SrbFlags;
3187 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
3188 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
3189
3190 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
3191 return;
3192 }
3193
3194 case IOCTL_DISK_GET_DRIVE_LAYOUT:
3195 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
3196 case IOCTL_DISK_GET_PARTITION_INFO:
3197 case IOCTL_DISK_GET_PARTITION_INFO_EX: {
3198
3199 ASSERT(irp2);
3200 ASSERT(senseBuffer);
3201 ASSERT(srb);
3202
3203 ExFreePool(srb);
3204 ExFreePool(senseBuffer);
3205 IoFreeIrp(irp2);
3206
3207 //
3208 // NOTE: should probably update the media's capacity first...
3209 //
3210
3211 CdromFakePartitionInfo(commonExtension, Irp);
3212 return;
3213 }
3214
3215 case IOCTL_DISK_IS_WRITABLE: {
3216
3217 TraceLog((CdromDebugWarning,
3218 "CdRomStartIo: DiskIsWritable (%p) - returning %s\n",
3219 Irp, (cdData->Mmc.WriteAllowed ? "TRUE" : "false")));
3220
3221 ASSERT(irp2);
3222 ASSERT(senseBuffer);
3223 ASSERT(srb);
3224
3225 ExFreePool(srb);
3226 ExFreePool(senseBuffer);
3227 IoFreeIrp(irp2);
3228
3229 Irp->IoStatus.Information = 0;
3230 if (cdData->Mmc.WriteAllowed) {
3231 Irp->IoStatus.Status = STATUS_SUCCESS;
3232 } else {
3233 Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;
3234 }
3235 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
3236 return;
3237 }
3238
3239 default: {
3240
3241 UCHAR uniqueAddress;
3242
3243 //
3244 // Just complete the request - CdRomClassIoctlCompletion will take
3245 // care of it for us
3246 //
3247 // NOTE: THIS IS A SYNCHRONIZATION METHOD!!!
3248 //
3249
3250 //
3251 // Acquire a new copy of the lock so that ClassCompleteRequest
3252 // doesn't get confused when we complete the other request while
3253 // holding the lock.
3254 //
3255
3256 //
3257 // NOTE: CdRomDeviceControlDispatch/CdRomDeviceControlCompletion
3258 // wait for the event and eventually calls
3259 // IoStartNextPacket()
3260 //
3261
3262 ASSERT(irp2);
3263 ASSERT(senseBuffer);
3264 ASSERT(srb);
3265
3266 ExFreePool(srb);
3267 ExFreePool(senseBuffer);
3268 IoFreeIrp(irp2);
3269
3270
3271
3272 ClassAcquireRemoveLock(Fdo, (PIRP)&uniqueAddress);
3273 ClassReleaseRemoveLock(Fdo, Irp);
3274 ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT);
3275 ClassReleaseRemoveLock(Fdo, (PIRP)&uniqueAddress);
3276 return;
3277 }
3278
3279 } // end switch()
3280 } else if (currentIrpStack->MajorFunction == IRP_MJ_SHUTDOWN ||
3281 currentIrpStack->MajorFunction == IRP_MJ_FLUSH_BUFFERS) {
3282
3283 currentIrpStack->Parameters.Others.Argument1 = 0;
3284 Irp->IoStatus.Status = STATUS_SUCCESS;
3285 CdRomShutdownFlushCompletion(Fdo, NULL, Irp);
3286 return;
3287
3288 }
3289
3290 //
3291 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
3292 // are expected and composed of AutoRun Irps, at present.
3293 //
3294
3295 IoCallDriver(commonExtension->LowerDeviceObject, Irp);
3296 return;
3297 }
3298 \f
3299
3300 NTSTATUS
3301 CdRomReadWriteVerification(
3302 IN PDEVICE_OBJECT DeviceObject,
3303 IN PIRP Irp
3304 )
3305
3306 /*++
3307
3308 Routine Description:
3309
3310 This is the entry called by the I/O system for read requests.
3311 It builds the SRB and sends it to the port driver.
3312
3313 Arguments:
3314
3315 DeviceObject - the system object for the device.
3316 Irp - IRP involved.
3317
3318 Return Value:
3319
3320 NT Status
3321
3322 --*/
3323
3324 {
3325 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3326 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
3327
3328 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
3329 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
3330 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
3331
3332 PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
3333
3334 SCSI_REQUEST_BLOCK srb;
3335 PCDB cdb = (PCDB)srb.Cdb;
3336 NTSTATUS status;
3337
3338 PAGED_CODE();
3339
3340 //
3341 // note: we are no longer failing write commands immediately
3342 // they are now failed in StartIo based upon media ability
3343 //
3344
3345 //
3346 // If the cd is playing music then reject this request.
3347 //
3348
3349 if (PLAY_ACTIVE(fdoExtension)) {
3350 Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
3351 return STATUS_DEVICE_BUSY;
3352 }
3353
3354 //
3355 // Verify parameters of this request.
3356 // Check that ending sector is on disc and
3357 // that number of bytes to transfer is a multiple of
3358 // the sector size.
3359 //
3360
3361 startingOffset.QuadPart = currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
3362 transferByteCount;
3363
3364 if (!fdoExtension->DiskGeometry.BytesPerSector) {
3365 fdoExtension->DiskGeometry.BytesPerSector = 2048;
3366 }
3367
3368 if ((startingOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
3369 (transferByteCount & fdoExtension->DiskGeometry.BytesPerSector - 1)) {
3370
3371 //
3372 // Fail request with status of invalid parameters.
3373 //
3374
3375 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
3376
3377 return STATUS_INVALID_PARAMETER;
3378 }
3379
3380
3381 return STATUS_SUCCESS;
3382
3383 } // end CdRomReadWriteVerification()
3384 \f
3385
3386 NTSTATUS
3387 CdRomSwitchModeCompletion(
3388 IN PDEVICE_OBJECT DeviceObject,
3389 IN PIRP Irp,
3390 IN PVOID Context
3391 )
3392 {
3393 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3394 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
3395
3396 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
3397 PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
3398 BOOLEAN use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
3399 PIO_STACK_LOCATION realIrpStack;
3400 PIO_STACK_LOCATION realIrpNextStack;
3401 PSCSI_REQUEST_BLOCK srb = Context;
3402 PIRP realIrp = NULL;
3403 NTSTATUS status;
3404 BOOLEAN retry;
3405
3406 //
3407 // Extract the 'real' irp from the irpstack.
3408 //
3409
3410 realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
3411 realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
3412 realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
3413
3414 //
3415 // Check SRB status for success of completing request.
3416 //
3417
3418 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
3419
3420 ULONG retryInterval;
3421
3422 TraceLog((CdromDebugTrace,
3423 "CdRomSetVolumeIntermediateCompletion: Irp %p, Srb %p, Real Irp %p\n",
3424 Irp,
3425 srb,
3426 realIrp));
3427
3428 //
3429 // Release the queue if it is frozen.
3430 //
3431
3432 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
3433 ClassReleaseQueue(DeviceObject);
3434 }
3435
3436
3437 retry = ClassInterpretSenseInfo(DeviceObject,
3438 srb,
3439 irpStack->MajorFunction,
3440 irpStack->Parameters.DeviceIoControl.IoControlCode,
3441 MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
3442 &status,
3443 &retryInterval);
3444
3445 //
3446 // If the status is verified required and the this request
3447 // should bypass verify required then retry the request.
3448 //
3449
3450 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
3451 status == STATUS_VERIFY_REQUIRED) {
3452
3453 status = STATUS_IO_DEVICE_ERROR;
3454 retry = TRUE;
3455 }
3456
3457 if (retry && realIrpNextStack->Parameters.Others.Argument1--) {
3458
3459 if (((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
3460
3461 //
3462 // Retry request.
3463 //
3464
3465 TraceLog((CdromDebugWarning,
3466 "Retry request %p - Calling StartIo\n", Irp));
3467
3468
3469 ExFreePool(srb->SenseInfoBuffer);
3470 ExFreePool(srb->DataBuffer);
3471 ExFreePool(srb);
3472 if (Irp->MdlAddress) {
3473 IoFreeMdl(Irp->MdlAddress);
3474 }
3475
3476 IoFreeIrp(Irp);
3477
3478 //
3479 // Call StartIo directly since IoStartNextPacket hasn't been called,
3480 // the serialisation is still intact.
3481 //
3482
3483 CdRomRetryRequest(fdoExtension,
3484 realIrp,
3485 retryInterval,
3486 FALSE);
3487
3488 return STATUS_MORE_PROCESSING_REQUIRED;
3489
3490 }
3491
3492 //
3493 // Exhausted retries. Fall through and complete the request with the appropriate status.
3494 //
3495 }
3496 } else {
3497
3498 //
3499 // Set status for successful request.
3500 //
3501
3502 status = STATUS_SUCCESS;
3503
3504 }
3505
3506 if (NT_SUCCESS(status)) {
3507
3508 ULONG sectorSize, startingSector, transferByteCount;
3509 PCDB cdb;
3510
3511 //
3512 // Update device ext. to show which mode we are currently using.
3513 //
3514
3515 sectorSize = cdData->BlockDescriptor.BlockLength[0] << 16;
3516 sectorSize |= (cdData->BlockDescriptor.BlockLength[1] << 8);
3517 sectorSize |= (cdData->BlockDescriptor.BlockLength[2]);
3518
3519 cdData->RawAccess = (sectorSize == RAW_SECTOR_SIZE) ? TRUE : FALSE;
3520
3521 //
3522 // Free the old data buffer, mdl.
3523 // reuse the SenseInfoBuffer and Srb
3524 //
3525
3526 ExFreePool(srb->DataBuffer);
3527 IoFreeMdl(Irp->MdlAddress);
3528 IoFreeIrp(Irp);
3529
3530 //
3531 // rebuild the srb.
3532 //
3533
3534 cdb = (PCDB)srb->Cdb;
3535 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
3536
3537
3538 if (cdData->RawAccess) {
3539
3540 PRAW_READ_INFO rawReadInfo =
3541 (PRAW_READ_INFO)realIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
3542
3543 ULONG maximumTransferLength;
3544 ULONG transferPages;
3545 UCHAR min, sec, frame;
3546
3547 //
3548 // Calculate starting offset.
3549 //
3550
3551 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> fdoExtension->SectorShift);
3552 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
3553 maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;
3554 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp->MdlAddress),
3555 transferByteCount);
3556
3557 //
3558 // Determine if request is within limits imposed by miniport.
3559 // If the request is larger than the miniport's capabilities, split it.
3560 //
3561
3562 if (transferByteCount > maximumTransferLength ||
3563 transferPages > fdoExtension->AdapterDescriptor->MaximumPhysicalPages) {
3564
3565
3566 ExFreePool(srb->SenseInfoBuffer);
3567 ExFreePool(srb);
3568 realIrp->IoStatus.Information = 0;
3569 realIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
3570
3571 BAIL_OUT(realIrp);
3572 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, realIrp);
3573 return STATUS_MORE_PROCESSING_REQUIRED;
3574 }
3575
3576 srb->OriginalRequest = realIrp;
3577 srb->SrbFlags = fdoExtension->SrbFlags;
3578 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
3579 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
3580
3581 srb->DataTransferLength = transferByteCount;
3582 srb->TimeOutValue = fdoExtension->TimeOutValue;
3583 srb->CdbLength = 10;
3584 srb->DataBuffer = MmGetMdlVirtualAddress(realIrp->MdlAddress);
3585
3586 if (rawReadInfo->TrackMode == CDDA) {
3587 if (TEST_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA)) {
3588
3589 srb->CdbLength = 12;
3590
3591 cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
3592 cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
3593 cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
3594 cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
3595
3596 cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
3597 cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
3598 cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
3599 cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
3600
3601 cdb->PLXTR_READ_CDDA.SubCode = 0;
3602 cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
3603
3604 } else if (TEST_FLAG(cdData->XAFlags, XA_NEC_CDDA)) {
3605
3606 cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
3607 cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
3608 cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
3609 cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
3610
3611 cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
3612 cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
3613
3614 cdb->NEC_READ_CDDA.OperationCode = 0xD4;
3615 }
3616 } else {
3617 cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8);
3618 cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
3619
3620 cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
3621 cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
3622 cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
3623 cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
3624
3625 cdb->CDB10.OperationCode = SCSIOP_READ;
3626 }
3627
3628 srb->SrbStatus = srb->ScsiStatus = 0;
3629
3630
3631 irpStack = IoGetNextIrpStackLocation(realIrp);
3632 irpStack->MajorFunction = IRP_MJ_SCSI;
3633 irpStack->Parameters.Scsi.Srb = srb;
3634
3635 if (!(irpStack->Parameters.Others.Argument1)) {
3636
3637 //
3638 // Only jam this in if it doesn't exist. The completion routines can
3639 // call StartIo directly in the case of retries and resetting it will
3640 // cause infinite loops.
3641 //
3642
3643 irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
3644 }
3645
3646 //
3647 // Set up IoCompletion routine address.
3648 //
3649
3650 IoSetCompletionRoutine(realIrp,
3651 CdRomXACompletion,
3652 srb,
3653 TRUE,
3654 TRUE,
3655 TRUE);
3656 } else {
3657
3658 PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor;
3659 ULONG maximumTransferLength;
3660 ULONG transferPages;
3661
3662 //
3663 // a writable device must be MMC compliant, which supports
3664 // READ_CD commands, so writes and mode switching should
3665 // never occur on the same device.
3666 //
3667
3668 ASSERT(realIrpStack->MajorFunction != IRP_MJ_WRITE);
3669
3670 //
3671 // free the SRB and SenseInfoBuffer since they aren't used
3672 // by either ClassBuildRequest() nor ClassSplitRequest().
3673 //
3674
3675 ExFreePool(srb->SenseInfoBuffer);
3676 ExFreePool(srb);
3677
3678 //
3679 // Back to cooked sectors. Build and send a normal read.
3680 // The real work for setting offsets was done in startio.
3681 //
3682
3683 adapterDescriptor =
3684 commonExtension->PartitionZeroExtension->AdapterDescriptor;
3685 maximumTransferLength = adapterDescriptor->MaximumTransferLength;
3686 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
3687 MmGetMdlVirtualAddress(realIrp->MdlAddress),
3688 realIrpStack->Parameters.Read.Length);
3689
3690 if ((realIrpStack->Parameters.Read.Length > maximumTransferLength) ||
3691 (transferPages > adapterDescriptor->MaximumPhysicalPages)) {
3692
3693 ULONG maxPages = adapterDescriptor->MaximumPhysicalPages;
3694
3695 if (maxPages != 0) {
3696 maxPages --; // to account for page boundaries
3697 }
3698
3699 TraceLog((CdromDebugTrace,
3700 "CdromSwitchModeCompletion: Request greater than "
3701 " maximum\n"));
3702 TraceLog((CdromDebugTrace,
3703 "CdromSwitchModeCompletion: Maximum is %lx\n",
3704 maximumTransferLength));
3705 TraceLog((CdromDebugTrace,
3706 "CdromSwitchModeCompletion: Byte count is %lx\n",
3707 realIrpStack->Parameters.Read.Length));
3708
3709 //
3710 // Check that the maximum transfer length fits within
3711 // the maximum number of pages the device can handle.
3712 //
3713
3714 if (maximumTransferLength > maxPages << PAGE_SHIFT) {
3715 maximumTransferLength = maxPages << PAGE_SHIFT;
3716 }
3717
3718 //
3719 // Check that maximum transfer size is not zero
3720 //
3721
3722 if (maximumTransferLength == 0) {
3723 maximumTransferLength = PAGE_SIZE;
3724 }
3725
3726 //
3727 // Request needs to be split. Completion of each portion
3728 // of the request will fire off the next portion. The final
3729 // request will signal Io to send a new request.
3730 //
3731
3732 ClassSplitRequest(DeviceObject, realIrp, maximumTransferLength);
3733 return STATUS_MORE_PROCESSING_REQUIRED;
3734
3735 } else {
3736
3737 //
3738 // Build SRB and CDB for this IRP.
3739 //
3740
3741 ClassBuildRequest(DeviceObject, realIrp);
3742
3743 }
3744 }
3745
3746 //
3747 // Call the port driver.
3748 //
3749
3750 IoCallDriver(commonExtension->LowerDeviceObject, realIrp);
3751
3752 return STATUS_MORE_PROCESSING_REQUIRED;
3753 }
3754
3755 //
3756 // Update device Extension flags to indicate that XA isn't supported.
3757 //
3758
3759 TraceLog((CdromDebugWarning,
3760 "Device Cannot Support CDDA (but tested positive) "
3761 "Now Clearing CDDA flags for FDO %p\n", DeviceObject));
3762 SET_FLAG(cdData->XAFlags, XA_NOT_SUPPORTED);
3763 CLEAR_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA);
3764 CLEAR_FLAG(cdData->XAFlags, XA_NEC_CDDA);
3765
3766 //
3767 // Deallocate srb and sense buffer.
3768 //
3769
3770 if (srb) {
3771 if (srb->DataBuffer) {
3772 ExFreePool(srb->DataBuffer);
3773 }
3774 if (srb->SenseInfoBuffer) {
3775 ExFreePool(srb->SenseInfoBuffer);
3776 }
3777 ExFreePool(srb);
3778 }
3779
3780 if (Irp->PendingReturned) {
3781 IoMarkIrpPending(Irp);
3782 }
3783
3784 if (realIrp->PendingReturned) {
3785 IoMarkIrpPending(realIrp);
3786 }
3787
3788 if (Irp->MdlAddress) {
3789 IoFreeMdl(Irp->MdlAddress);
3790 }
3791
3792 IoFreeIrp(Irp);
3793
3794 //
3795 // Set status in completing IRP.
3796 //
3797
3798 realIrp->IoStatus.Status = status;
3799
3800 //
3801 // Set the hard error if necessary.
3802 //
3803
3804 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
3805
3806 //
3807 // Store DeviceObject for filesystem, and clear
3808 // in IoStatus.Information field.
3809 //
3810
3811 if (realIrp->Tail.Overlay.Thread) {
3812 IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
3813 }
3814 realIrp->IoStatus.Information = 0;
3815 }
3816
3817 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, realIrp);
3818
3819 return STATUS_MORE_PROCESSING_REQUIRED;
3820 }
3821 \f
3822
3823 VOID
3824 ScanForSpecialHandler(
3825 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
3826 ULONG_PTR HackFlags
3827 )
3828 {
3829 PCOMMON_DEVICE_EXTENSION commonExtension;
3830 PCDROM_DATA cdData;
3831
3832 PAGED_CODE();
3833
3834 CLEAR_FLAG(HackFlags, CDROM_HACK_INVALID_FLAGS);
3835
3836 commonExtension = &(FdoExtension->CommonExtension);
3837 cdData = (PCDROM_DATA)(commonExtension->DriverData);
3838 cdData->HackFlags = HackFlags;
3839
3840 return;
3841 }
3842
3843 VOID
3844 ScanForSpecial(
3845 PDEVICE_OBJECT DeviceObject
3846 )
3847
3848 /*++
3849
3850 Routine Description:
3851
3852 This function checks to see if an SCSI logical unit requires an special
3853 initialization or error processing.
3854
3855 Arguments:
3856
3857 DeviceObject - Supplies the device object to be tested.
3858
3859 InquiryData - Supplies the inquiry data returned by the device of interest.
3860
3861 PortCapabilities - Supplies the capabilities of the device object.
3862
3863 Return Value:
3864
3865 None.
3866
3867 --*/
3868
3869 {
3870 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
3871 PCOMMON_DEVICE_EXTENSION commonExtension;
3872 PCDROM_DATA cdData;
3873
3874 PAGED_CODE();
3875
3876 fdoExtension = DeviceObject->DeviceExtension;
3877 commonExtension = DeviceObject->DeviceExtension;
3878 cdData = (PCDROM_DATA)(commonExtension->DriverData);
3879
3880
3881 //
3882 // set our hack flags
3883 //
3884
3885 ClassScanForSpecial(fdoExtension, CdromHackItems, ScanForSpecialHandler);
3886
3887 //
3888 // All CDRom's can ignore the queue lock failure for power operations
3889 // and do not require handling the SpinUp case (unknown result of sending
3890 // a cdrom a START_UNIT command -- may eject disks?)
3891 //
3892 // We send the stop command mostly to stop outstanding asynch operations
3893 // (like audio playback) from running when the system is powered off.
3894 // Because of this and the unlikely chance that a PLAY command will be
3895 // sent in the window between the STOP and the time the machine powers down
3896 // we don't require queue locks. This is important because without them
3897 // classpnp's power routines will send the START_STOP_UNIT command to the
3898 // device whether or not it supports locking (atapi does not support locking
3899 // and if we requested them we would end up not stopping audio on atapi
3900 // devices).
3901 //
3902
3903 SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_DISABLE_SPIN_UP);
3904 SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_NO_QUEUE_LOCK);
3905
3906 if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_1750)
3907 && ( fdoExtension->AdapterDescriptor->AdapterUsesPio )
3908 ) {
3909
3910 //
3911 // Read-ahead must be disabled in order to get this cdrom drive
3912 // to work on scsi adapters that use PIO.
3913 //
3914
3915
3916 TraceLog((CdromDebugWarning,
3917 "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
3918
3919 //
3920 // Setup an error handler to reinitialize the cd rom after it is reset.
3921 //
3922
3923 cdData->ErrorHandler = HitachiProcessError;
3924
3925 //
3926 // Lock down the hitachi error processing code.
3927 //
3928
3929 MmLockPagableCodeSection(HitachiProcessError);
3930 SET_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES);
3931
3932
3933 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_TOSHIBA_SD_W1101)) {
3934
3935 TraceLog((CdromDebugError,
3936 "CdRom ScanForSpecial: Found Toshiba SD-W1101 DVD-RAM "
3937 "-- This drive will *NOT* support DVD-ROM playback.\n"));
3938
3939 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_GD_2000)) {
3940
3941 TraceLog((CdromDebugWarning,
3942 "CdRom ScanForSpecial: Found Hitachi GD-2000\n"));
3943
3944 //
3945 // Setup an error handler to spin up the drive when it idles out
3946 // since it seems to like to fail to spin itself back up on its
3947 // own for a REPORT_KEY command. It may also lose the AGIDs that
3948 // it has given, which will result in DVD playback failures.
3949 // This routine will just do what it can...
3950 //
3951
3952 cdData->ErrorHandler = HitachiProcessErrorGD2000;
3953
3954 //
3955 // this drive may require START_UNIT commands to spin
3956 // the drive up when it's spun itself down.
3957 //
3958
3959 SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
3960
3961 //
3962 // Lock down the hitachi error processing code.
3963 //
3964
3965 MmLockPagableCodeSection(HitachiProcessErrorGD2000);
3966 SET_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES);
3967
3968 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_FUJITSU_FMCD_10x)) {
3969
3970 //
3971 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
3972 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
3973 // error status.
3974 //
3975
3976 fdoExtension->TimeOutValue = 20;
3977
3978 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_DEC_RRD)) {
3979
3980 PMODE_PARM_READ_WRITE_DATA modeParameters;
3981 SCSI_REQUEST_BLOCK srb;
3982 PCDB cdb;
3983 NTSTATUS status;
3984
3985
3986 TraceLog((CdromDebugWarning,
3987 "CdRom ScanForSpecial: Found DEC RRD.\n"));
3988
3989 cdData->IsDecRrd = TRUE;
3990
3991 //
3992 // Setup an error handler to reinitialize the cd rom after it is reset?
3993 //
3994 //commonExtension->DevInfo->ClassError = DecRrdProcessError;
3995
3996 //
3997 // Found a DEC RRD cd-rom. These devices do not pass MS HCT
3998 // multi-media tests because the DEC firmware modifieds the block
3999 // from the PC-standard 2K to 512. Change the block transfer size
4000 // back to the PC-standard 2K by using a mode select command.
4001 //
4002
4003 modeParameters = ExAllocatePoolWithTag(NonPagedPool,
4004 sizeof(MODE_PARM_READ_WRITE_DATA),
4005 CDROM_TAG_MODE_DATA
4006 );
4007 if (modeParameters == NULL) {
4008 return;
4009 }
4010
4011 RtlZeroMemory(modeParameters, sizeof(MODE_PARM_READ_WRITE_DATA));
4012 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
4013
4014 //
4015 // Set the block length to 2K.
4016 //
4017
4018 modeParameters->ParameterListHeader.BlockDescriptorLength =
4019 sizeof(MODE_PARAMETER_BLOCK);
4020
4021 //
4022 // Set block length to 2K (0x0800) in Parameter Block.
4023 //
4024
4025 modeParameters->ParameterListBlock.BlockLength[0] = 0x00; //MSB
4026 modeParameters->ParameterListBlock.BlockLength[1] = 0x08;
4027 modeParameters->ParameterListBlock.BlockLength[2] = 0x00; //LSB
4028
4029 //
4030 // Build the mode select CDB.
4031 //
4032
4033 srb.CdbLength = 6;
4034 srb.TimeOutValue = fdoExtension->TimeOutValue;
4035
4036 cdb = (PCDB)srb.Cdb;
4037 cdb->MODE_SELECT.PFBit = 1;
4038 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
4039 cdb->MODE_SELECT.ParameterListLength = HITACHI_MODE_DATA_SIZE;
4040
4041 //
4042 // Send the request to the device.
4043 //
4044
4045 status = ClassSendSrbSynchronous(DeviceObject,
4046 &srb,
4047 modeParameters,
4048 sizeof(MODE_PARM_READ_WRITE_DATA),
4049 TRUE);
4050
4051 if (!NT_SUCCESS(status)) {
4052 TraceLog((CdromDebugWarning,
4053 "CdRom ScanForSpecial: Setting DEC RRD to 2K block"
4054 "size failed [%x]\n", status));
4055 }
4056 ExFreePool(modeParameters);
4057
4058 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_TOSHIBA_XM_3xx)) {
4059
4060 SCSI_REQUEST_BLOCK srb;
4061 PCDB cdb;
4062 ULONG length;
4063 PUCHAR buffer;
4064 NTSTATUS status;
4065
4066 //
4067 // Set the density code and the error handler.
4068 //
4069
4070 length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH);
4071
4072 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
4073
4074 //
4075 // Build the MODE SENSE CDB.
4076 //
4077
4078 srb.CdbLength = 6;
4079 cdb = (PCDB)srb.Cdb;
4080
4081 //
4082 // Set timeout value from device extension.
4083 //
4084
4085 srb.TimeOutValue = fdoExtension->TimeOutValue;
4086
4087 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
4088 cdb->MODE_SENSE.PageCode = 0x1;
4089 // NOTE: purposely not setting DBD because it is what is needed.
4090 cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
4091
4092 buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
4093 (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH),
4094 CDROM_TAG_MODE_DATA);
4095 if (!buffer) {
4096 return;
4097 }
4098
4099 status = ClassSendSrbSynchronous(DeviceObject,
4100 &srb,
4101 buffer,
4102 length,
4103 FALSE);
4104
4105 ((PERROR_RECOVERY_DATA)buffer)->BlockDescriptor.DensityCode = 0x83;
4106 ((PERROR_RECOVERY_DATA)buffer)->Header.ModeDataLength = 0x0;
4107
4108 RtlCopyMemory(&cdData->Header, buffer, sizeof(ERROR_RECOVERY_DATA));
4109
4110 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
4111
4112 //
4113 // Build the MODE SENSE CDB.
4114 //
4115
4116 srb.CdbLength = 6;
4117 cdb = (PCDB)srb.Cdb;
4118
4119 //
4120 // Set timeout value from device extension.
4121 //
4122
4123 srb.TimeOutValue = fdoExtension->TimeOutValue;
4124
4125 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
4126 cdb->MODE_SELECT.PFBit = 1;
4127 cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
4128
4129 status = ClassSendSrbSynchronous(DeviceObject,
4130 &srb,
4131 buffer,
4132 length,
4133 TRUE);
4134
4135 if (!NT_SUCCESS(status)) {
4136 TraceLog((CdromDebugWarning,
4137 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
4138 status));
4139 }
4140
4141 cdData->ErrorHandler = ToshibaProcessError;
4142
4143 //
4144 // Lock down the toshiba error section.
4145 //
4146
4147 MmLockPagableCodeSection(ToshibaProcessError);
4148 SET_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES);
4149
4150 ExFreePool(buffer);
4151
4152 }
4153
4154 //
4155 // Determine special CD-DA requirements.
4156 //
4157
4158 if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_READ_CD_SUPPORTED)) {
4159
4160 SET_FLAG(cdData->XAFlags, XA_USE_READ_CD);
4161
4162 } else if (!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD)) {
4163
4164 if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_PLEXTOR_CDDA)) {
4165 SET_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA);
4166 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_NEC_CDDA)) {
4167 SET_FLAG(cdData->XAFlags, XA_NEC_CDDA);
4168 }
4169
4170 }
4171
4172 if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES)) {
4173 KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_ERROR_LEVEL,
4174 "Locking pages for error handler\n"));
4175 }
4176
4177
4178 return;
4179 }
4180 \f
4181
4182 VOID
4183 HitachiProcessErrorGD2000(
4184 PDEVICE_OBJECT Fdo,
4185 PSCSI_REQUEST_BLOCK OriginalSrb,
4186 NTSTATUS *Status,
4187 BOOLEAN *Retry
4188 )
4189 /*++
4190
4191 Routine Description:
4192
4193 This routine checks the type of error. If the error suggests that the
4194 drive has spun down and cannot reinitialize itself, send a
4195 START_UNIT or READ to the device. This will force the drive to spin
4196 up. This drive also loses the AGIDs it has granted when it spins down,
4197 which may result in playback failure the first time around.
4198
4199 Arguments:
4200
4201 DeviceObject - Supplies a pointer to the device object.
4202
4203 Srb - Supplies a pointer to the failing Srb.
4204
4205 Status - return the final status for this command?
4206
4207 Retry - return if the command should be retried.
4208
4209 Return Value:
4210
4211 None.
4212
4213 --*/
4214 {
4215 PSENSE_DATA senseBuffer = OriginalSrb->SenseInfoBuffer;
4216
4217 UNREFERENCED_PARAMETER(Status);
4218 UNREFERENCED_PARAMETER(Retry);
4219
4220 if (!TEST_FLAG(OriginalSrb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
4221 return;
4222 }
4223
4224 if (((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_HARDWARE_ERROR) &&
4225 (senseBuffer->AdditionalSenseCode == 0x44)) {
4226
4227 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
4228 PIRP irp;
4229 PIO_STACK_LOCATION irpStack;
4230 PCOMPLETION_CONTEXT context;
4231 PSCSI_REQUEST_BLOCK newSrb;
4232 PCDB cdb;
4233
4234 TraceLog((CdromDebugWarning,
4235 "HitachiProcessErrorGD2000 (%p) => Internal Target "
4236 "Failure Detected -- spinning up drive\n", Fdo));
4237
4238 //
4239 // the request should be retried because the device isn't ready
4240 //
4241
4242 *Retry = TRUE;
4243 *Status = STATUS_DEVICE_NOT_READY;
4244
4245 //
4246 // send a START_STOP unit to spin up the drive
4247 // NOTE: this temporarily violates the StartIo serialization
4248 // mechanism, but the completion routine on this will NOT
4249 // call StartNextPacket(), so it's a temporary disruption
4250 // of the serialization only.
4251 //
4252
4253 ClassSendStartUnit(Fdo);
4254
4255 }
4256
4257 return;
4258 }
4259 \f
4260
4261 VOID
4262 HitachiProcessError(
4263 PDEVICE_OBJECT DeviceObject,
4264 PSCSI_REQUEST_BLOCK Srb,
4265 NTSTATUS *Status,
4266 BOOLEAN *Retry
4267 )
4268 /*++
4269
4270 Routine Description:
4271
4272 This routine checks the type of error. If the error indicates CD-ROM the
4273 CD-ROM needs to be reinitialized then a Mode sense command is sent to the
4274 device. This command disables read-ahead for the device.
4275
4276 Arguments:
4277
4278 DeviceObject - Supplies a pointer to the device object.
4279
4280 Srb - Supplies a pointer to the failing Srb.
4281
4282 Status - Not used.
4283
4284 Retry - Not used.
4285
4286 Return Value:
4287
4288 None.
4289
4290 --*/
4291
4292 {
4293 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4294 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
4295 LARGE_INTEGER largeInt;
4296 PUCHAR modePage;
4297 PIO_STACK_LOCATION irpStack;
4298 PIRP irp;
4299 PSCSI_REQUEST_BLOCK srb;
4300 PCOMPLETION_CONTEXT context;
4301 PCDB cdb;
4302 ULONG_PTR alignment;
4303
4304 UNREFERENCED_PARAMETER(Status);
4305 UNREFERENCED_PARAMETER(Retry);
4306
4307 largeInt.QuadPart = (LONGLONG) 1;
4308
4309 //
4310 // Check the status. The initialization command only needs to be sent
4311 // if UNIT ATTENTION is returned.
4312 //
4313
4314 if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
4315
4316 //
4317 // The drive does not require reinitialization.
4318 //
4319
4320 return;
4321 }
4322
4323 //
4324 // Found an HITACHI cd-rom that does not work with PIO
4325 // adapters when read-ahead is enabled. Read-ahead is disabled by
4326 // a mode select command. The mode select page code is zero and the
4327 // length is 6 bytes. All of the other bytes should be zero.
4328 //
4329
4330 if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
4331
4332 TraceLog((CdromDebugWarning,
4333 "HitachiProcessError: Reinitializing the CD-ROM.\n"));
4334
4335 //
4336 // Send the special mode select command to disable read-ahead
4337 // on the CD-ROM reader.
4338 //
4339
4340 alignment = DeviceObject->AlignmentRequirement ?
4341 DeviceObject->AlignmentRequirement : 1;
4342
4343 context = ExAllocatePoolWithTag(
4344 NonPagedPool,
4345 sizeof(COMPLETION_CONTEXT) + HITACHI_MODE_DATA_SIZE + (ULONG)alignment,
4346 CDROM_TAG_HITACHI_ERROR
4347 );
4348
4349 if (context == NULL) {
4350
4351 //
4352 // If there is not enough memory to fulfill this request,
4353 // simply return. A subsequent retry will fail and another
4354 // chance to start the unit.
4355 //
4356
4357 return;
4358 }
4359
4360 context->DeviceObject = DeviceObject;
4361 srb = &context->Srb;
4362
4363 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
4364
4365 //
4366 // Write length to SRB.
4367 //
4368
4369 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
4370
4371 //
4372 // Set up SCSI bus address.
4373 //
4374
4375 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
4376 srb->TimeOutValue = fdoExtension->TimeOutValue;
4377
4378 //
4379 // Set the transfer length.
4380 //
4381
4382 srb->DataTransferLength = HITACHI_MODE_DATA_SIZE;
4383 srb->SrbFlags = fdoExtension->SrbFlags;
4384 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
4385 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
4386 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
4387
4388 //
4389 // The data buffer must be aligned.
4390 //
4391
4392 srb->DataBuffer = (PVOID) (((ULONG_PTR) (context + 1) + (alignment - 1)) &
4393 ~(alignment - 1));
4394
4395
4396 //
4397 // Build the HITACHI read-ahead mode select CDB.
4398 //
4399
4400 srb->CdbLength = 6;
4401 cdb = (PCDB)srb->Cdb;
4402 cdb->MODE_SENSE.LogicalUnitNumber = srb->Lun;
4403 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SELECT;
4404 cdb->MODE_SENSE.AllocationLength = HITACHI_MODE_DATA_SIZE;
4405
4406 //
4407 // Initialize the mode sense data.
4408 //
4409
4410 modePage = srb->DataBuffer;
4411
4412 RtlZeroMemory(modePage, HITACHI_MODE_DATA_SIZE);
4413
4414 //
4415 // Set the page length field to 6.
4416 //
4417
4418 modePage[5] = 6;
4419
4420 //
4421 // Build the asynchronous request to be sent to the port driver.
4422 //
4423
4424 irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE,
4425 DeviceObject,
4426 srb->DataBuffer,
4427 srb->DataTransferLength,
4428 &largeInt,
4429 NULL);
4430
4431 if (irp == NULL) {
4432
4433 //
4434 // If there is not enough memory to fulfill this request,
4435 // simply return. A subsequent retry will fail and another
4436 // chance to start the unit.
4437 //
4438
4439 ExFreePool(context);
4440 return;
4441 }
4442
4443 ClassAcquireRemoveLock(DeviceObject, irp);
4444
4445 IoSetCompletionRoutine(irp,
4446 (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion,
4447 context,
4448 TRUE,
4449 TRUE,
4450 TRUE);
4451
4452 irpStack = IoGetNextIrpStackLocation(irp);
4453
4454 irpStack->MajorFunction = IRP_MJ_SCSI;
4455
4456 srb->OriginalRequest = irp;
4457
4458 //
4459 // Save SRB address in next stack for port driver.
4460 //
4461
4462 irpStack->Parameters.Scsi.Srb = (PVOID)srb;
4463
4464 //
4465 // Set up IRP Address.
4466 //
4467
4468 (VOID)IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
4469
4470 }
4471 }
4472 \f
4473
4474 NTSTATUS
4475 ToshibaProcessErrorCompletion(
4476 PDEVICE_OBJECT DeviceObject,
4477 PIRP Irp,
4478 PVOID Context
4479 )
4480
4481 /*++
4482
4483 Routine Description:
4484
4485 Completion routine for the ClassError routine to handle older Toshiba units
4486 that require setting the density code.
4487
4488 Arguments:
4489
4490 DeviceObject - Supplies a pointer to the device object.
4491
4492 Irp - Pointer to irp created to set the density code.
4493
4494 Context - Supplies a pointer to the Mode Select Srb.
4495
4496
4497 Return Value:
4498
4499 STATUS_MORE_PROCESSING_REQUIRED
4500
4501 --*/
4502
4503 {
4504
4505 PSCSI_REQUEST_BLOCK srb = Context;
4506
4507 //
4508 // Free all of the allocations.
4509 //
4510
4511 ClassReleaseRemoveLock(DeviceObject, Irp);
4512
4513 ExFreePool(srb->DataBuffer);
4514 ExFreePool(srb);
4515 IoFreeMdl(Irp->MdlAddress);
4516 IoFreeIrp(Irp);
4517
4518 //
4519 // Indicate the I/O system should stop processing the Irp completion.
4520 //
4521
4522 return STATUS_MORE_PROCESSING_REQUIRED;
4523 }
4524 \f
4525
4526 VOID
4527 ToshibaProcessError(
4528 PDEVICE_OBJECT DeviceObject,
4529 PSCSI_REQUEST_BLOCK Srb,
4530 NTSTATUS *Status,
4531 BOOLEAN *Retry
4532 )
4533
4534 /*++
4535
4536 Routine Description:
4537
4538 This routine checks the type of error. If the error indicates a unit attention,
4539 the density code needs to be set via a Mode select command.
4540
4541 Arguments:
4542
4543 DeviceObject - Supplies a pointer to the device object.
4544
4545 Srb - Supplies a pointer to the failing Srb.
4546
4547 Status - Not used.
4548
4549 Retry - Not used.
4550
4551 Return Value:
4552
4553 None.
4554
4555 --*/
4556
4557 {
4558 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4559 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4560
4561 PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
4562 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
4563 PIO_STACK_LOCATION irpStack;
4564 PIRP irp;
4565 PSCSI_REQUEST_BLOCK srb;
4566 ULONG length;
4567 PCDB cdb;
4568 PUCHAR dataBuffer;
4569
4570
4571 if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
4572 return;
4573 }
4574
4575 //
4576 // The Toshiba's require the density code to be set on power up and media changes.
4577 //
4578
4579 if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
4580
4581
4582 irp = IoAllocateIrp((CCHAR)(DeviceObject->StackSize+1),
4583 FALSE);
4584
4585 if (!irp) {
4586 return;
4587 }
4588
4589 srb = ExAllocatePoolWithTag(NonPagedPool,
4590 sizeof(SCSI_REQUEST_BLOCK),
4591 CDROM_TAG_TOSHIBA_ERROR);
4592 if (!srb) {
4593 IoFreeIrp(irp);
4594 return;
4595 }
4596
4597
4598 length = sizeof(ERROR_RECOVERY_DATA);
4599 dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
4600 length,
4601 CDROM_TAG_TOSHIBA_ERROR);
4602 if (!dataBuffer) {
4603 ExFreePool(srb);
4604 IoFreeIrp(irp);
4605 return;
4606 }
4607
4608 irp->MdlAddress = IoAllocateMdl(dataBuffer,
4609 length,
4610 FALSE,
4611 FALSE,
4612 (PIRP) NULL);
4613
4614 if (!irp->MdlAddress) {
4615 ExFreePool(srb);
4616 ExFreePool(dataBuffer);
4617 IoFreeIrp(irp);
4618 return;
4619 }
4620
4621 //
4622 // Prepare the MDL
4623 //
4624
4625 MmBuildMdlForNonPagedPool(irp->MdlAddress);
4626
4627 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
4628
4629 srb->DataBuffer = dataBuffer;
4630 cdb = (PCDB)srb->Cdb;
4631
4632 //
4633 // Set up the irp.
4634 //
4635
4636 IoSetNextIrpStackLocation(irp);
4637 irp->IoStatus.Status = STATUS_SUCCESS;
4638 irp->IoStatus.Information = 0;
4639 irp->Flags = 0;
4640 irp->UserBuffer = NULL;
4641
4642 //
4643 // Save the device object and irp in a private stack location.
4644 //
4645
4646 irpStack = IoGetCurrentIrpStackLocation(irp);
4647 irpStack->DeviceObject = DeviceObject;
4648
4649 //
4650 // Construct the IRP stack for the lower level driver.
4651 //
4652
4653 irpStack = IoGetNextIrpStackLocation(irp);
4654 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
4655 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_OUT;
4656 irpStack->Parameters.Scsi.Srb = srb;
4657
4658 IoSetCompletionRoutine(irp,
4659 ToshibaProcessErrorCompletion,
4660 srb,
4661 TRUE,
4662 TRUE,
4663 TRUE);
4664
4665 ClassAcquireRemoveLock(DeviceObject, irp);
4666
4667 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
4668 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
4669 srb->SrbStatus = srb->ScsiStatus = 0;
4670 srb->NextSrb = 0;
4671 srb->OriginalRequest = irp;
4672 srb->SenseInfoBufferLength = 0;
4673
4674 //
4675 // Set the transfer length.
4676 //
4677
4678 srb->DataTransferLength = length;
4679 srb->SrbFlags = fdoExtension->SrbFlags;
4680 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
4681 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
4682 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
4683 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
4684
4685
4686 srb->CdbLength = 6;
4687 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
4688 cdb->MODE_SELECT.PFBit = 1;
4689 cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
4690
4691 //
4692 // Copy the Mode page into the databuffer.
4693 //
4694
4695 RtlCopyMemory(srb->DataBuffer, &cdData->Header, length);
4696
4697 //
4698 // Set the density code.
4699 //
4700
4701 ((PERROR_RECOVERY_DATA)srb->DataBuffer)->BlockDescriptor.DensityCode = 0x83;
4702
4703 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
4704 }
4705 }
4706 \f
4707
4708 BOOLEAN
4709 CdRomIsPlayActive(
4710 IN PDEVICE_OBJECT DeviceObject
4711 )
4712
4713 /*++
4714
4715 Routine Description:
4716
4717 This routine determines if the cd is currently playing music.
4718
4719 Arguments:
4720
4721 DeviceObject - Device object to test.
4722
4723 Return Value:
4724
4725 TRUE if the device is playing music.
4726
4727 --*/
4728 {
4729 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4730 IO_STATUS_BLOCK ioStatus;
4731 PSUB_Q_CURRENT_POSITION currentBuffer;
4732
4733 PAGED_CODE();
4734
4735 //
4736 // if we don't think it is playing audio, don't bother checking.
4737 //
4738
4739 if (!PLAY_ACTIVE(fdoExtension)) {
4740 return(FALSE);
4741 }
4742
4743 currentBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
4744 sizeof(SUB_Q_CURRENT_POSITION),
4745 CDROM_TAG_PLAY_ACTIVE);
4746
4747 if (currentBuffer == NULL) {
4748 return(FALSE);
4749 }
4750
4751 ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION;
4752 ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0;
4753
4754 //
4755 // Build the synchronous request to be sent to ourself
4756 // to perform the request.
4757 //
4758
4759 ClassSendDeviceIoControlSynchronous(
4760 IOCTL_CDROM_READ_Q_CHANNEL,
4761 DeviceObject,
4762 currentBuffer,
4763 sizeof(CDROM_SUB_Q_DATA_FORMAT),
4764 sizeof(SUB_Q_CURRENT_POSITION),
4765 FALSE,
4766 &ioStatus);
4767
4768 if (!NT_SUCCESS(ioStatus.Status)) {
4769 ExFreePool(currentBuffer);
4770 return FALSE;
4771 }
4772
4773 //
4774 // should update the playactive flag here.
4775 //
4776
4777 if (currentBuffer->Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
4778 PLAY_ACTIVE(fdoExtension) = TRUE;
4779 } else {
4780 PLAY_ACTIVE(fdoExtension) = FALSE;
4781 }
4782
4783 ExFreePool(currentBuffer);
4784
4785 return(PLAY_ACTIVE(fdoExtension));
4786
4787 }
4788 \f
4789
4790 VOID
4791 CdRomTickHandler(
4792 IN PDEVICE_OBJECT DeviceObject
4793 )
4794
4795 /*++
4796
4797 Routine Description:
4798
4799 This routine handles the once per second timer provided by the
4800 Io subsystem. It is used to do delayed retries for cdroms.
4801
4802 Arguments:
4803
4804 DeviceObject - what to check.
4805
4806 Return Value:
4807
4808 None.
4809
4810 --*/
4811
4812 {
4813 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4814 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4815
4816 ULONG isRemoved;
4817
4818 KIRQL oldIrql;
4819
4820 PIRP irp;
4821 PIRP heldIrpList;
4822 PIRP nextIrp;
4823 PLIST_ENTRY listEntry;
4824 PCDROM_DATA cddata;
4825 PIO_STACK_LOCATION irpStack;
4826 UCHAR uniqueAddress;
4827
4828 isRemoved = ClassAcquireRemoveLock(DeviceObject, (PIRP) &uniqueAddress);
4829
4830 //
4831 // We stop the timer before deleting the device. It's safe to keep going
4832 // if the flag value is REMOVE_PENDING because the removal thread will be
4833 // blocked trying to stop the timer.
4834 //
4835
4836 ASSERT(isRemoved != REMOVE_COMPLETE);
4837
4838 //
4839 // This routine is reasonably safe even if the device object has a pending
4840 // remove
4841
4842 cddata = commonExtension->DriverData;
4843
4844 //
4845 // Since cdrom is completely synchronized there can never be more than one
4846 // irp delayed for retry at any time.
4847 //
4848
4849 KeAcquireSpinLock(&(cddata->DelayedRetrySpinLock), &oldIrql);
4850
4851 if(cddata->DelayedRetryIrp != NULL) {
4852
4853 PIRP irp = cddata->DelayedRetryIrp;
4854
4855 //
4856 // If we've got a delayed retry at this point then there had beter
4857 // be an interval for it.
4858 //
4859
4860 ASSERT(cddata->DelayedRetryInterval != 0);
4861 cddata->DelayedRetryInterval--;
4862
4863 if(isRemoved) {
4864
4865 //
4866 // This device is removed - flush the timer queue
4867 //
4868
4869 cddata->DelayedRetryIrp = NULL;
4870 cddata->DelayedRetryInterval = 0;
4871
4872 KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
4873
4874 ClassReleaseRemoveLock(DeviceObject, irp);
4875 ClassCompleteRequest(DeviceObject, irp, IO_CD_ROM_INCREMENT);
4876
4877 } else if (cddata->DelayedRetryInterval == 0) {
4878
4879 //
4880 // Submit this IRP to the lower driver. This IRP does not
4881 // need to be remembered here. It will be handled again when
4882 // it completes.
4883 //
4884
4885 cddata->DelayedRetryIrp = NULL;
4886
4887 KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
4888
4889 TraceLog((CdromDebugWarning,
4890 "CdRomTickHandler: Reissuing request %p (thread = %p)\n",
4891 irp,
4892 irp->Tail.Overlay.Thread));
4893
4894 //
4895 // feed this to the appropriate port driver
4896 //
4897
4898 CdRomRerunRequest(fdoExtension, irp, cddata->DelayedRetryResend);
4899 } else {
4900 KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
4901 }
4902 } else {
4903 KeReleaseSpinLock(&(cddata->DelayedRetrySpinLock), oldIrql);
4904 }
4905
4906 ClassReleaseRemoveLock(DeviceObject, (PIRP) &uniqueAddress);
4907 }
4908 \f
4909
4910 NTSTATUS
4911 CdRomUpdateGeometryCompletion(
4912 PDEVICE_OBJECT DeviceObject,
4913 PIRP Irp,
4914 PVOID Context
4915 )
4916
4917 /*++
4918
4919 Routine Description:
4920
4921 This routine andles the completion of the test unit ready irps
4922 used to determine if the media has changed. If the media has
4923 changed, this code signals the named event to wake up other
4924 system services that react to media change (aka AutoPlay).
4925
4926 Arguments:
4927
4928 DeviceObject - the object for the completion
4929 Irp - the IRP being completed
4930 Context - the SRB from the IRP
4931
4932 Return Value:
4933
4934 NTSTATUS
4935
4936 --*/
4937
4938 {
4939 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
4940 PCOMMON_DEVICE_EXTENSION commonExtension;
4941
4942 PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK) Context;
4943 PREAD_CAPACITY_DATA readCapacityBuffer;
4944 PIO_STACK_LOCATION irpStack;
4945 NTSTATUS status;
4946 BOOLEAN retry;
4947 ULONG retryCount;
4948 ULONG lastSector;
4949 PIRP originalIrp;
4950 PCDROM_DATA cddata;
4951 UCHAR uniqueAddress;
4952
4953 //
4954 // Get items saved in the private IRP stack location.
4955 //
4956
4957 irpStack = IoGetCurrentIrpStackLocation(Irp);
4958 retryCount = (ULONG)(ULONG_PTR) irpStack->Parameters.Others.Argument1;
4959 originalIrp = (PIRP) irpStack->Parameters.Others.Argument2;
4960
4961 if (!DeviceObject) {
4962 DeviceObject = irpStack->DeviceObject;
4963 }
4964 ASSERT(DeviceObject);
4965
4966 fdoExtension = DeviceObject->DeviceExtension;
4967 commonExtension = DeviceObject->DeviceExtension;
4968 cddata = commonExtension->DriverData;
4969 readCapacityBuffer = srb->DataBuffer;
4970
4971 if ((NT_SUCCESS(Irp->IoStatus.Status)) && (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)) {
4972
4973 CdRomInterpretReadCapacity(DeviceObject, readCapacityBuffer);
4974
4975 } else {
4976
4977 ULONG retryInterval;
4978
4979 TraceLog((CdromDebugWarning,
4980 "CdRomUpdateGeometryCompletion: [%p] unsuccessful "
4981 "completion of buddy-irp %p (status - %lx)\n",
4982 originalIrp, Irp, Irp->IoStatus.Status));
4983
4984 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
4985 ClassReleaseQueue(DeviceObject);
4986 }
4987
4988 retry = ClassInterpretSenseInfo(DeviceObject,
4989 srb,
4990 IRP_MJ_SCSI,
4991 0,
4992 retryCount,
4993 &status,
4994 &retryInterval);
4995 if (retry) {
4996 retryCount--;
4997 if ((retryCount) && (commonExtension->IsRemoved == NO_REMOVE)) {
4998 PCDB cdb;
4999
5000 TraceLog((CdromDebugWarning,
5001 "CdRomUpdateGeometryCompletion: [%p] Retrying "
5002 "request %p .. thread is %p\n",
5003 originalIrp, Irp, Irp->Tail.Overlay.Thread));
5004
5005 //
5006 // set up a one shot timer to get this process started over
5007 //
5008
5009 irpStack->Parameters.Others.Argument1 = ULongToPtr( retryCount );
5010 irpStack->Parameters.Others.Argument2 = (PVOID) originalIrp;
5011 irpStack->Parameters.Others.Argument3 = (PVOID) 2;
5012
5013 //
5014 // Setup the IRP to be submitted again in the timer routine.
5015 //
5016
5017 irpStack = IoGetNextIrpStackLocation(Irp);
5018 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
5019 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
5020 irpStack->Parameters.Scsi.Srb = srb;
5021 IoSetCompletionRoutine(Irp,
5022 CdRomUpdateGeometryCompletion,
5023 srb,
5024 TRUE,
5025 TRUE,
5026 TRUE);
5027
5028 //
5029 // Set up the SRB for read capacity.
5030 //
5031
5032 srb->CdbLength = 10;
5033 srb->TimeOutValue = fdoExtension->TimeOutValue;
5034 srb->SrbStatus = srb->ScsiStatus = 0;
5035 srb->NextSrb = 0;
5036 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
5037 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
5038 srb->SrbFlags = fdoExtension->SrbFlags;
5039 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
5040 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
5041 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
5042
5043 //
5044 // Set up the CDB
5045 //
5046
5047 cdb = (PCDB) &srb->Cdb[0];
5048 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
5049
5050 //
5051 // Requests queued onto this list will be sent to the
5052 // lower level driver during CdRomTickHandler
5053 //
5054
5055 CdRomRetryRequest(fdoExtension, Irp, retryInterval, TRUE);
5056
5057 return STATUS_MORE_PROCESSING_REQUIRED;
5058 }
5059
5060 if (commonExtension->IsRemoved != NO_REMOVE) {
5061
5062 //
5063 // We cannot retry the request. Fail it.
5064 //
5065
5066 originalIrp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
5067
5068 } else {
5069
5070 //
5071 // This has been bounced for a number of times. Error the
5072 // original request.
5073 //
5074
5075 originalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
5076 RtlZeroMemory(&(fdoExtension->DiskGeometry),
5077 sizeof(DISK_GEOMETRY));
5078 fdoExtension->DiskGeometry.BytesPerSector = 2048;
5079 fdoExtension->SectorShift = 11;
5080 commonExtension->PartitionLength.QuadPart =
5081 (LONGLONG)(0x7fffffff);
5082 fdoExtension->DiskGeometry.MediaType = RemovableMedia;
5083 }
5084 } else {
5085
5086 //
5087 // Set up reasonable defaults
5088 //
5089
5090 RtlZeroMemory(&(fdoExtension->DiskGeometry),
5091 sizeof(DISK_GEOMETRY));
5092 fdoExtension->DiskGeometry.BytesPerSector = 2048;
5093 fdoExtension->SectorShift = 11;
5094 commonExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
5095 fdoExtension->DiskGeometry.MediaType = RemovableMedia;
5096 }
5097 }
5098
5099 //
5100 // Free resources held.
5101 //
5102
5103 ExFreePool(srb->SenseInfoBuffer);
5104 ExFreePool(srb->DataBuffer);
5105 ExFreePool(srb);
5106 if (Irp->MdlAddress) {
5107 IoFreeMdl(Irp->MdlAddress);
5108 }
5109 IoFreeIrp(Irp);
5110 Irp = NULL;
5111
5112 if (originalIrp->Tail.Overlay.Thread) {
5113
5114 TraceLog((CdromDebugTrace,
5115 "CdRomUpdateGeometryCompletion: [%p] completing "
5116 "original IRP\n", originalIrp));
5117
5118 } else {
5119
5120 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
5121 "CdRomUpdateGeometryCompletion: completing irp %p which has "
5122 "no thread\n", originalIrp));
5123
5124 }
5125
5126 {
5127 // NOTE: should the original irp be sent down to the device object?
5128 // it probably should if the SL_OVERRIDER_VERIFY_VOLUME flag
5129 // is set!
5130 KIRQL oldIrql;
5131 PIO_STACK_LOCATION realIrpStack;
5132
5133 realIrpStack = IoGetCurrentIrpStackLocation(originalIrp);
5134 oldIrql = KeRaiseIrqlToDpcLevel();
5135
5136 if (TEST_FLAG(realIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)) {
5137 CdRomStartIo(DeviceObject, originalIrp);
5138 } else {
5139 originalIrp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
5140 originalIrp->IoStatus.Information = 0;
5141 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, originalIrp);
5142 }
5143 KeLowerIrql(oldIrql);
5144 }
5145
5146 return STATUS_MORE_PROCESSING_REQUIRED;
5147 }
5148 \f
5149
5150 NTSTATUS
5151 CdRomUpdateCapacity(
5152 IN PFUNCTIONAL_DEVICE_EXTENSION DeviceExtension,
5153 IN PIRP IrpToComplete,
5154 IN OPTIONAL PKEVENT IoctlEvent
5155 )
5156
5157 /*++
5158
5159 Routine Description:
5160
5161 This routine updates the capacity of the disk as recorded in the device extension.
5162 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
5163 when a media change has occurred and it is necessary to determine the capacity of the
5164 new media prior to the next access.
5165
5166 Arguments:
5167
5168 DeviceExtension - the device to update
5169 IrpToComplete - the request that needs to be completed when done.
5170
5171 Return Value:
5172
5173 NTSTATUS
5174
5175 --*/
5176
5177 {
5178 PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION) DeviceExtension;
5179 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION) DeviceExtension;
5180
5181 PCDB cdb;
5182 PIRP irp;
5183 PSCSI_REQUEST_BLOCK srb;
5184 PREAD_CAPACITY_DATA capacityBuffer;
5185 PIO_STACK_LOCATION irpStack;
5186 PUCHAR senseBuffer;
5187 NTSTATUS status;
5188
5189 irp = IoAllocateIrp((CCHAR)(commonExtension->DeviceObject->StackSize+1),
5190 FALSE);
5191
5192 if (irp) {
5193
5194 srb = ExAllocatePoolWithTag(NonPagedPool,
5195 sizeof(SCSI_REQUEST_BLOCK),
5196 CDROM_TAG_UPDATE_CAP);
5197 if (srb) {
5198 capacityBuffer = ExAllocatePoolWithTag(
5199 NonPagedPoolCacheAligned,
5200 sizeof(READ_CAPACITY_DATA),
5201 CDROM_TAG_UPDATE_CAP);
5202
5203 if (capacityBuffer) {
5204
5205
5206 senseBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
5207 SENSE_BUFFER_SIZE,
5208 CDROM_TAG_UPDATE_CAP);
5209
5210 if (senseBuffer) {
5211
5212 irp->MdlAddress = IoAllocateMdl(capacityBuffer,
5213 sizeof(READ_CAPACITY_DATA),
5214 FALSE,
5215 FALSE,
5216 (PIRP) NULL);
5217
5218 if (irp->MdlAddress) {
5219
5220 //
5221 // Have all resources. Set up the IRP to send for the capacity.
5222 //
5223
5224 IoSetNextIrpStackLocation(irp);
5225 irp->IoStatus.Status = STATUS_SUCCESS;
5226 irp->IoStatus.Information = 0;
5227 irp->Flags = 0;
5228 irp->UserBuffer = NULL;
5229
5230 //
5231 // Save the device object and retry count in a private stack location.
5232 //
5233
5234 irpStack = IoGetCurrentIrpStackLocation(irp);
5235 irpStack->DeviceObject = commonExtension->DeviceObject;
5236 irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
5237 irpStack->Parameters.Others.Argument2 = (PVOID) IrpToComplete;
5238
5239 //
5240 // Construct the IRP stack for the lower level driver.
5241 //
5242
5243 irpStack = IoGetNextIrpStackLocation(irp);
5244 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
5245 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
5246 irpStack->Parameters.Scsi.Srb = srb;
5247 IoSetCompletionRoutine(irp,
5248 CdRomUpdateGeometryCompletion,
5249 srb,
5250 TRUE,
5251 TRUE,
5252 TRUE);
5253 //
5254 // Prepare the MDL
5255 //
5256
5257 MmBuildMdlForNonPagedPool(irp->MdlAddress);
5258
5259
5260 //
5261 // Set up the SRB for read capacity.
5262 //
5263
5264 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
5265 RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);
5266 srb->CdbLength = 10;
5267 srb->TimeOutValue = DeviceExtension->TimeOutValue;
5268 srb->SrbStatus = srb->ScsiStatus = 0;
5269 srb->NextSrb = 0;
5270 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
5271 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
5272 srb->SrbFlags = DeviceExtension->SrbFlags;
5273 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
5274 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
5275 srb->DataBuffer = capacityBuffer;
5276 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
5277 srb->OriginalRequest = irp;
5278 srb->SenseInfoBuffer = senseBuffer;
5279 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
5280
5281 //
5282 // Set up the CDB
5283 //
5284
5285 cdb = (PCDB) &srb->Cdb[0];
5286 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
5287
5288 //
5289 // Set the return value in the IRP that will be completed
5290 // upon completion of the read capacity.
5291 //
5292
5293 IrpToComplete->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
5294 IoMarkIrpPending(IrpToComplete);
5295
5296 IoCallDriver(commonExtension->LowerDeviceObject, irp);
5297
5298 //
5299 // status is not checked because the completion routine for this
5300 // IRP will always get called and it will free the resources.
5301 //
5302
5303 return STATUS_PENDING;
5304
5305 } else {
5306 ExFreePool(senseBuffer);
5307 ExFreePool(capacityBuffer);
5308 ExFreePool(srb);
5309 IoFreeIrp(irp);
5310 }
5311 } else {
5312 ExFreePool(capacityBuffer);
5313 ExFreePool(srb);
5314 IoFreeIrp(irp);
5315 }
5316 } else {
5317 ExFreePool(srb);
5318 IoFreeIrp(irp);
5319 }
5320 } else {
5321 IoFreeIrp(irp);
5322 }
5323 }
5324
5325 //
5326 // complete the original irp with a failure.
5327 // ISSUE-2000/07/05-henrygab - find a way to avoid failure.
5328 //
5329
5330 RtlZeroMemory(&(fdoExtension->DiskGeometry),
5331 sizeof(DISK_GEOMETRY));
5332 fdoExtension->DiskGeometry.BytesPerSector = 2048;
5333 fdoExtension->SectorShift = 11;
5334 commonExtension->PartitionLength.QuadPart =
5335 (LONGLONG)(0x7fffffff);
5336 fdoExtension->DiskGeometry.MediaType = RemovableMedia;
5337
5338 IrpToComplete->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
5339 IrpToComplete->IoStatus.Information = 0;
5340
5341 BAIL_OUT(IrpToComplete);
5342 CdRomCompleteIrpAndStartNextPacketSafely(commonExtension->DeviceObject,
5343 IrpToComplete);
5344 return STATUS_INSUFFICIENT_RESOURCES;
5345 }
5346 \f
5347
5348 NTSTATUS
5349 CdRomRemoveDevice(
5350 IN PDEVICE_OBJECT DeviceObject,
5351 IN UCHAR Type
5352 )
5353
5354 /*++
5355
5356 Routine Description:
5357
5358 This routine is responsible for releasing any resources in use by the
5359 cdrom driver and shutting down it's timer routine. This routine is called
5360 when all outstanding requests have been completed and the device has
5361 disappeared - no requests may be issued to the lower drivers.
5362
5363 Arguments:
5364
5365 DeviceObject - the device object being removed
5366
5367 Return Value:
5368
5369 none - this routine may not fail
5370
5371 --*/
5372
5373 {
5374 PFUNCTIONAL_DEVICE_EXTENSION deviceExtension =
5375 DeviceObject->DeviceExtension;
5376
5377 PCDROM_DATA cdData = deviceExtension->CommonExtension.DriverData;
5378
5379 PAGED_CODE();
5380
5381 if((Type == IRP_MN_QUERY_REMOVE_DEVICE) ||
5382 (Type == IRP_MN_CANCEL_REMOVE_DEVICE)) {
5383 return STATUS_SUCCESS;
5384 }
5385
5386 if(cdData->DelayedRetryIrp != NULL) {
5387 cdData->DelayedRetryInterval = 1;
5388 CdRomTickHandler(DeviceObject);
5389 }
5390
5391 CdRomDeAllocateMmcResources(DeviceObject);
5392
5393 if (deviceExtension->DeviceDescriptor) {
5394 ExFreePool(deviceExtension->DeviceDescriptor);
5395 deviceExtension->DeviceDescriptor = NULL;
5396 }
5397
5398 if (deviceExtension->AdapterDescriptor) {
5399 ExFreePool(deviceExtension->AdapterDescriptor);
5400 deviceExtension->AdapterDescriptor = NULL;
5401 }
5402
5403 if (deviceExtension->SenseData) {
5404 ExFreePool(deviceExtension->SenseData);
5405 deviceExtension->SenseData = NULL;
5406 }
5407
5408 ClassDeleteSrbLookasideList(&deviceExtension->CommonExtension);
5409
5410 if(cdData->CdromInterfaceString.Buffer != NULL) {
5411 IoSetDeviceInterfaceState(
5412 &(cdData->CdromInterfaceString),
5413 FALSE);
5414 RtlFreeUnicodeString(&(cdData->CdromInterfaceString));
5415 RtlInitUnicodeString(&(cdData->CdromInterfaceString), NULL);
5416 }
5417
5418 if(cdData->VolumeInterfaceString.Buffer != NULL) {
5419 IoSetDeviceInterfaceState(
5420 &(cdData->VolumeInterfaceString),
5421 FALSE);
5422 RtlFreeUnicodeString(&(cdData->VolumeInterfaceString));
5423 RtlInitUnicodeString(&(cdData->VolumeInterfaceString), NULL);
5424 }
5425
5426 CdRomDeleteWellKnownName(DeviceObject);
5427
5428 ASSERT(cdData->DelayedRetryIrp == NULL);
5429
5430 if(Type == IRP_MN_REMOVE_DEVICE) {
5431
5432 if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_LOCKED_PAGES)) {
5433
5434 //
5435 // unlock locked pages by locking (to get Mm pointer)
5436 // and then unlocking twice.
5437 //
5438
5439 PVOID locked;
5440
5441 if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_1750)) {
5442
5443 locked = MmLockPagableCodeSection(HitachiProcessError);
5444
5445 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_HITACHI_GD_2000)) {
5446
5447 locked = MmLockPagableCodeSection(HitachiProcessErrorGD2000);
5448
5449 } else if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_TOSHIBA_XM_3xx )) {
5450
5451 locked = MmLockPagableCodeSection(ToshibaProcessError);
5452
5453 } else {
5454
5455 // this is a problem!
5456 // workaround by locking this twice, once for us and
5457 // once for the non-existant locker from ScanForSpecial
5458 ASSERT(!"hack flags show locked section, but none exists?");
5459 locked = MmLockPagableCodeSection(CdRomRemoveDevice);
5460 locked = MmLockPagableCodeSection(CdRomRemoveDevice);
5461
5462
5463 }
5464
5465 MmUnlockPagableImageSection(locked);
5466 MmUnlockPagableImageSection(locked);
5467
5468 }
5469
5470 //
5471 // keep the system-wide count accurate, as
5472 // programs use this info to know when they
5473 // have found all the cdroms in a system.
5474 //
5475
5476 TraceLog((CdromDebugTrace,
5477 "CDROM.SYS Remove device\n"));
5478 IoGetConfigurationInformation()->CdRomCount--;
5479 }
5480
5481 //
5482 // so long, and thanks for all the fish!
5483 //
5484
5485 return STATUS_SUCCESS;
5486 }
5487 \f
5488
5489 DEVICE_TYPE
5490 CdRomGetDeviceType(
5491 IN PDEVICE_OBJECT DeviceObject
5492 )
5493 /*++
5494
5495 Routine Description:
5496
5497 This routine figures out the real device type
5498 by checking CDVD_CAPABILITIES_PAGE
5499
5500 Arguments:
5501
5502 DeviceObject -
5503
5504 Return Value:
5505
5506 FILE_DEVICE_CD_ROM or FILE_DEVICE_DVD
5507
5508
5509 --*/
5510 {
5511 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
5512 PCDROM_DATA cdromExtension;
5513 ULONG bufLength;
5514 SCSI_REQUEST_BLOCK srb;
5515 PCDB cdb;
5516 PMODE_PARAMETER_HEADER10 modePageHeader;
5517 PCDVD_CAPABILITIES_PAGE capPage;
5518 ULONG capPageOffset;
5519 DEVICE_TYPE deviceType;
5520 NTSTATUS status;
5521 BOOLEAN use6Byte;
5522
5523 PAGED_CODE();
5524
5525 //
5526 // NOTE: don't cache this until understand how it affects GetMediaTypes()
5527 //
5528
5529 //
5530 // default device type
5531 //
5532
5533 deviceType = FILE_DEVICE_CD_ROM;
5534
5535 fdoExtension = DeviceObject->DeviceExtension;
5536
5537 cdromExtension = fdoExtension->CommonExtension.DriverData;
5538
5539 use6Byte = TEST_FLAG(cdromExtension->XAFlags, XA_USE_6_BYTE);
5540
5541 RtlZeroMemory(&srb, sizeof(srb));
5542 cdb = (PCDB)srb.Cdb;
5543
5544 //
5545 // Build the MODE SENSE CDB. The data returned will be kept in the
5546 // device extension and used to set block size.
5547 //
5548 if (use6Byte) {
5549
5550 bufLength = sizeof(CDVD_CAPABILITIES_PAGE) +
5551 sizeof(MODE_PARAMETER_HEADER);
5552
5553 capPageOffset = sizeof(MODE_PARAMETER_HEADER);
5554
5555 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
5556 cdb->MODE_SENSE.Dbd = 1;
5557 cdb->MODE_SENSE.PageCode = MODE_PAGE_CAPABILITIES;
5558 cdb->MODE_SENSE.AllocationLength = (UCHAR)bufLength;
5559 srb.CdbLength = 6;
5560 } else {
5561
5562 bufLength = sizeof(CDVD_CAPABILITIES_PAGE) +
5563 sizeof(MODE_PARAMETER_HEADER10);
5564
5565 capPageOffset = sizeof(MODE_PARAMETER_HEADER10);
5566
5567 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
5568 cdb->MODE_SENSE10.Dbd = 1;
5569 cdb->MODE_SENSE10.PageCode = MODE_PAGE_CAPABILITIES;
5570 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufLength >> 8);
5571 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufLength >> 0);
5572 srb.CdbLength = 10;
5573 }
5574
5575 //
5576 // Set timeout value from device extension.
5577 //
5578 srb.TimeOutValue = fdoExtension->TimeOutValue;
5579
5580 modePageHeader = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
5581 bufLength,
5582 CDROM_TAG_MODE_DATA);
5583 if (modePageHeader) {
5584
5585 RtlZeroMemory(modePageHeader, bufLength);
5586
5587 status = ClassSendSrbSynchronous(
5588 DeviceObject,
5589 &srb,
5590 modePageHeader,
5591 bufLength,
5592 FALSE);
5593
5594 if (NT_SUCCESS(status) ||
5595 (status == STATUS_DATA_OVERRUN) ||
5596 (status == STATUS_BUFFER_OVERFLOW)
5597 ) {
5598
5599 capPage = (PCDVD_CAPABILITIES_PAGE) (((PUCHAR) modePageHeader) + capPageOffset);
5600
5601 if ((capPage->PageCode == MODE_PAGE_CAPABILITIES) &&
5602 (capPage->DVDROMRead || capPage->DVDRRead ||
5603 capPage->DVDRAMRead || capPage->DVDRWrite ||
5604 capPage->DVDRAMWrite)) {
5605
5606 deviceType = FILE_DEVICE_DVD;
5607 }
5608 }
5609 ExFreePool (modePageHeader);
5610 }
5611
5612 return deviceType;
5613 }
5614 \f
5615
5616 NTSTATUS
5617 CdRomCreateWellKnownName(
5618 IN PDEVICE_OBJECT DeviceObject
5619 )
5620 /*++
5621
5622 Routine Description:
5623
5624 This routine creates a symbolic link to the cdrom device object
5625 under \dosdevices. The number of the cdrom device does not neccessarily
5626 match between \dosdevices and \device, but usually will be the same.
5627
5628 Saves the buffer
5629
5630 Arguments:
5631
5632 DeviceObject -
5633
5634 Return Value:
5635
5636 NTSTATUS
5637
5638 --*/
5639 {
5640 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
5641 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5642 PCDROM_DATA cdromData = commonExtension->DriverData;
5643
5644 UNICODE_STRING unicodeLinkName;
5645 WCHAR wideLinkName[64];
5646 PWCHAR savedName;
5647
5648 LONG cdromNumber = fdoExtension->DeviceNumber;
5649
5650 NTSTATUS status;
5651
5652 //
5653 // if already linked, assert then return
5654 //
5655
5656 if (cdromData->WellKnownName.Buffer != NULL) {
5657
5658 TraceLog((CdromDebugError,
5659 "CdRomCreateWellKnownName: link already exists %p\n",
5660 cdromData->WellKnownName.Buffer));
5661 ASSERT(FALSE);
5662 return STATUS_UNSUCCESSFUL;
5663
5664 }
5665
5666 //
5667 // find an unused CdRomNN to link to
5668 //
5669
5670 do {
5671
5672 swprintf(wideLinkName, L"\\DosDevices\\CdRom%d", cdromNumber);
5673 RtlInitUnicodeString(&unicodeLinkName, wideLinkName);
5674 status = IoCreateSymbolicLink(&unicodeLinkName,
5675 &(commonExtension->DeviceName));
5676
5677 cdromNumber++;
5678
5679 } while((status == STATUS_OBJECT_NAME_COLLISION) ||
5680 (status == STATUS_OBJECT_NAME_EXISTS));
5681
5682 if (!NT_SUCCESS(status)) {
5683
5684 TraceLog((CdromDebugWarning,
5685 "CdRomCreateWellKnownName: Error %lx linking %wZ to "
5686 "device %wZ\n",
5687 status,
5688 &unicodeLinkName,
5689 &(commonExtension->DeviceName)));
5690 return status;
5691
5692 }
5693
5694 TraceLog((CdromDebugWarning,
5695 "CdRomCreateWellKnownName: successfully linked %wZ "
5696 "to device %wZ\n",
5697 &unicodeLinkName,
5698 &(commonExtension->DeviceName)));
5699
5700 //
5701 // Save away the symbolic link name in the driver data block. We need
5702 // it so we can delete the link when the device is removed.
5703 //
5704
5705 savedName = ExAllocatePoolWithTag(PagedPool,
5706 unicodeLinkName.MaximumLength,
5707 CDROM_TAG_STRINGS);
5708
5709 if (savedName == NULL) {
5710 IoDeleteSymbolicLink(&unicodeLinkName);
5711 return STATUS_INSUFFICIENT_RESOURCES;
5712 }
5713
5714 RtlCopyMemory(savedName,
5715 unicodeLinkName.Buffer,
5716 unicodeLinkName.MaximumLength);
5717
5718 RtlInitUnicodeString(&(cdromData->WellKnownName), savedName);
5719
5720 //
5721 // the name was saved and the link created
5722 //
5723
5724 return STATUS_SUCCESS;
5725 }
5726 \f
5727
5728 VOID
5729 CdRomDeleteWellKnownName(
5730 IN PDEVICE_OBJECT DeviceObject
5731 )
5732 {
5733 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5734 PCDROM_DATA cdromData = commonExtension->DriverData;
5735
5736 if(cdromData->WellKnownName.Buffer != NULL) {
5737
5738 IoDeleteSymbolicLink(&(cdromData->WellKnownName));
5739 ExFreePool(cdromData->WellKnownName.Buffer);
5740 cdromData->WellKnownName.Buffer = NULL;
5741 cdromData->WellKnownName.Length = 0;
5742 cdromData->WellKnownName.MaximumLength = 0;
5743
5744 }
5745 return;
5746 }
5747 \f
5748
5749 NTSTATUS
5750 CdRomGetDeviceParameter (
5751 IN PDEVICE_OBJECT Fdo,
5752 IN PWSTR ParameterName,
5753 IN OUT PULONG ParameterValue
5754 )
5755 /*++
5756
5757 Routine Description:
5758
5759 retrieve a devnode registry parameter
5760
5761 Arguments:
5762
5763 DeviceObject - Cdrom Device Object
5764
5765 ParameterName - parameter name to look up
5766
5767 ParameterValuse - default parameter value
5768
5769 Return Value:
5770
5771 NT Status
5772
5773 --*/
5774 {
5775 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
5776 NTSTATUS status;
5777 HANDLE deviceParameterHandle;
5778 RTL_QUERY_REGISTRY_TABLE queryTable[2];
5779 ULONG defaultParameterValue;
5780
5781 PAGED_CODE();
5782
5783 //
5784 // open the given parameter
5785 //
5786 status = IoOpenDeviceRegistryKey(fdoExtension->LowerPdo,
5787 PLUGPLAY_REGKEY_DRIVER,
5788 KEY_READ,
5789 &deviceParameterHandle);
5790
5791 if(NT_SUCCESS(status)) {
5792
5793 RtlZeroMemory(queryTable, sizeof(queryTable));
5794
5795 defaultParameterValue = *ParameterValue;
5796
5797 queryTable->Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
5798 queryTable->Name = ParameterName;
5799 queryTable->EntryContext = ParameterValue;
5800 queryTable->DefaultType = REG_NONE;
5801 queryTable->DefaultData = NULL;
5802 queryTable->DefaultLength = 0;
5803
5804 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
5805 (PWSTR) deviceParameterHandle,
5806 queryTable,
5807 NULL,
5808 NULL);
5809 if (!NT_SUCCESS(status)) {
5810
5811 *ParameterValue = defaultParameterValue;
5812 }
5813
5814 //
5815 // close what we open
5816 //
5817 ZwClose(deviceParameterHandle);
5818 }
5819
5820 return status;
5821
5822 } // CdRomGetDeviceParameter
5823 \f
5824
5825 NTSTATUS
5826 CdRomSetDeviceParameter (
5827 IN PDEVICE_OBJECT Fdo,
5828 IN PWSTR ParameterName,
5829 IN ULONG ParameterValue
5830 )
5831 /*++
5832
5833 Routine Description:
5834
5835 save a devnode registry parameter
5836
5837 Arguments:
5838
5839 DeviceObject - Cdrom Device Object
5840
5841 ParameterName - parameter name
5842
5843 ParameterValuse - parameter value
5844
5845 Return Value:
5846
5847 NT Status
5848
5849 --*/
5850 {
5851 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
5852 NTSTATUS status;
5853 HANDLE deviceParameterHandle;
5854
5855 PAGED_CODE();
5856
5857 //
5858 // open the given parameter
5859 //
5860 status = IoOpenDeviceRegistryKey(fdoExtension->LowerPdo,
5861 PLUGPLAY_REGKEY_DRIVER,
5862 KEY_READ | KEY_WRITE,
5863 &deviceParameterHandle);
5864
5865 if(NT_SUCCESS(status)) {
5866
5867 status = RtlWriteRegistryValue(
5868 RTL_REGISTRY_HANDLE,
5869 (PWSTR) deviceParameterHandle,
5870 ParameterName,
5871 REG_DWORD,
5872 &ParameterValue,
5873 sizeof (ParameterValue));
5874
5875 //
5876 // close what we open
5877 //
5878 ZwClose(deviceParameterHandle);
5879 }
5880
5881 return status;
5882
5883 } // CdromSetDeviceParameter
5884 \f
5885
5886 VOID
5887 CdRomPickDvdRegion(
5888 IN PDEVICE_OBJECT Fdo
5889 )
5890 /*++
5891
5892 Routine Description:
5893
5894 pick a default dvd region
5895
5896 Arguments:
5897
5898 DeviceObject - Cdrom Device Object
5899
5900 Return Value:
5901
5902 NT Status
5903
5904 --*/
5905 {
5906 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
5907 PCDROM_DATA cddata = (PCDROM_DATA)(commonExtension->DriverData);
5908
5909 //
5910 // these five pointers all point to dvdReadStructure or part of
5911 // its data, so don't deallocate them more than once!
5912 //
5913
5914 PDVD_READ_STRUCTURE dvdReadStructure;
5915 PDVD_COPY_PROTECT_KEY copyProtectKey;
5916 PDVD_COPYRIGHT_DESCRIPTOR dvdCopyRight;
5917 PDVD_RPC_KEY rpcKey;
5918 PDVD_SET_RPC_KEY dvdRpcKey;
5919
5920 IO_STATUS_BLOCK ioStatus;
5921 ULONG bufferLen;
5922 UCHAR mediaRegion;
5923 ULONG pickDvdRegion;
5924 ULONG defaultDvdRegion;
5925 ULONG dvdRegion;
5926
5927 PAGED_CODE();
5928
5929 if ((pickDvdRegion = InterlockedExchange(&cddata->PickDvdRegion, 0)) == 0) {
5930
5931 //
5932 // it was non-zero, so either another thread will do this, or
5933 // we no longer need to pick a region
5934 //
5935
5936 return;
5937 }
5938
5939 //
5940 // short-circuit if license agreement violated
5941 //
5942
5943 if (cddata->DvdRpc0LicenseFailure) {
5944 TraceLog((CdromDebugWarning,
5945 "DVD License failure. Refusing to pick a region\n"));
5946 InterlockedExchange(&cddata->PickDvdRegion, 0);
5947 return;
5948 }
5949
5950
5951 ULONG a, b;
5952
5953 a = max(sizeof(DVD_DESCRIPTOR_HEADER) +
5954 sizeof(DVD_COPYRIGHT_DESCRIPTOR),
5955 sizeof(DVD_READ_STRUCTURE)
5956 );
5957 b = max(DVD_RPC_KEY_LENGTH,
5958 DVD_SET_RPC_KEY_LENGTH
5959 );
5960 bufferLen = max(a, b);
5961
5962 dvdReadStructure = (PDVD_READ_STRUCTURE)
5963 ExAllocatePoolWithTag(PagedPool, bufferLen, DVD_TAG_DVD_REGION);
5964
5965 if (dvdReadStructure == NULL) {
5966 InterlockedExchange(&cddata->PickDvdRegion, pickDvdRegion);
5967 return;
5968 }
5969
5970 if (cddata->DvdRpc0Device && cddata->Rpc0RetryRegistryCallback) {
5971
5972 TraceLog((CdromDebugWarning,
5973 "CdRomPickDvdRegion (%p): now retrying RPC0 callback\n",
5974 Fdo));
5975
5976 //
5977 // get the registry settings again
5978 //
5979
5980 ioStatus.Status = CdRomGetRpc0Settings(Fdo);
5981
5982 if (ioStatus.Status == STATUS_LICENSE_VIOLATION) {
5983
5984 //
5985 // if this is the returned error, then
5986 // the routine should have set this!
5987 //
5988
5989 ASSERT(cddata->DvdRpc0LicenseFailure);
5990 cddata->DvdRpc0LicenseFailure = 1;
5991 TraceLog((CdromDebugWarning,
5992 "CdRomPickDvdRegion (%p): "
5993 "setting to fail all dvd ioctls due to CSS licensing "
5994 "failure.\n", Fdo));
5995
5996 pickDvdRegion = 0;
5997 goto getout;
5998
5999 }
6000
6001 //
6002 // get the device region, again
6003 //
6004
6005 copyProtectKey = (PDVD_COPY_PROTECT_KEY)dvdReadStructure;
6006 RtlZeroMemory(copyProtectKey, bufferLen);
6007 copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
6008 copyProtectKey->KeyType = DvdGetRpcKey;
6009
6010 //
6011 // Build a request for READ_KEY
6012 //
6013
6014 ClassSendDeviceIoControlSynchronous(
6015 IOCTL_DVD_READ_KEY,
6016 Fdo,
6017 copyProtectKey,
6018 DVD_RPC_KEY_LENGTH,
6019 DVD_RPC_KEY_LENGTH,
6020 FALSE,
6021 &ioStatus);
6022
6023 if (!NT_SUCCESS(ioStatus.Status)) {
6024 TraceLog((CdromDebugWarning,
6025 "CdRomPickDvdRegion: Unable to get "
6026 "device RPC data (%x)\n", ioStatus.Status));
6027 pickDvdRegion = 0;
6028 goto getout;
6029 }
6030
6031 //
6032 // now that we have gotten the device's RPC data,
6033 // we have set the device extension to usable data.
6034 // no need to call back into this section of code again
6035 //
6036
6037 cddata->Rpc0RetryRegistryCallback = 0;
6038
6039
6040 rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
6041
6042 //
6043 // TypeCode of zero means that no region has been set.
6044 //
6045
6046 if (rpcKey->TypeCode != 0) {
6047 TraceLog((CdromDebugWarning,
6048 "CdRomPickDvdRegion (%p): DVD Region already "
6049 "chosen\n", Fdo));
6050 pickDvdRegion = 0;
6051 goto getout;
6052 }
6053
6054 TraceLog((CdromDebugWarning,
6055 "CdRomPickDvdRegion (%p): must choose initial DVD "
6056 " Region\n", Fdo));
6057 }
6058
6059
6060
6061 copyProtectKey = (PDVD_COPY_PROTECT_KEY) dvdReadStructure;
6062
6063 dvdCopyRight = (PDVD_COPYRIGHT_DESCRIPTOR)
6064 ((PDVD_DESCRIPTOR_HEADER) dvdReadStructure)->Data;
6065
6066 //
6067 // get the media region
6068 //
6069
6070 RtlZeroMemory (dvdReadStructure, bufferLen);
6071 dvdReadStructure->Format = DvdCopyrightDescriptor;
6072
6073 //
6074 // Build and send a request for READ_KEY
6075 //
6076
6077 TraceLog((CdromDebugTrace,
6078 "CdRomPickDvdRegion (%p): Getting Copyright Descriptor\n",
6079 Fdo));
6080
6081 ClassSendDeviceIoControlSynchronous(
6082 IOCTL_DVD_READ_STRUCTURE,
6083 Fdo,
6084 dvdReadStructure,
6085 sizeof(DVD_READ_STRUCTURE),
6086 sizeof (DVD_DESCRIPTOR_HEADER) +
6087 sizeof(DVD_COPYRIGHT_DESCRIPTOR),
6088 FALSE,
6089 &ioStatus
6090 );
6091 TraceLog((CdromDebugTrace,
6092 "CdRomPickDvdRegion (%p): Got Copyright Descriptor %x\n",
6093 Fdo, ioStatus.Status));
6094
6095 if ((NT_SUCCESS(ioStatus.Status)) &&
6096 (dvdCopyRight->CopyrightProtectionType == 0x01)
6097 ) {
6098
6099 //
6100 // keep the media region bitmap around
6101 // a 1 means ok to play
6102 //
6103
6104 if (dvdCopyRight->RegionManagementInformation == 0xff) {
6105 TraceLog((CdromDebugError,
6106 "CdRomPickDvdRegion (%p): RegionManagementInformation "
6107 "is set to dis-allow playback for all regions. This is "
6108 "most likely a poorly authored disc. defaulting to all "
6109 "region disc for purpose of choosing initial region\n",
6110 Fdo));
6111 dvdCopyRight->RegionManagementInformation = 0;
6112 }
6113
6114
6115 mediaRegion = ~dvdCopyRight->RegionManagementInformation;
6116
6117 } else {
6118
6119 //
6120 // could be media, can't set the device region
6121 //
6122
6123 if (!cddata->DvdRpc0Device) {
6124
6125 //
6126 // can't automatically pick a default region on a rpc2 drive
6127 // without media, so just exit
6128 //
6129 TraceLog((CdromDebugWarning,
6130 "CdRomPickDvdRegion (%p): failed to auto-choose "
6131 "a region due to status %x getting copyright "
6132 "descriptor\n", Fdo, ioStatus.Status));
6133 goto getout;
6134
6135 } else {
6136
6137 //
6138 // for an RPC0 drive, we can try to pick a region for
6139 // the drive
6140 //
6141
6142 mediaRegion = 0x0;
6143 }
6144
6145 }
6146
6147 //
6148 // get the device region
6149 //
6150
6151 RtlZeroMemory (copyProtectKey, bufferLen);
6152 copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
6153 copyProtectKey->KeyType = DvdGetRpcKey;
6154
6155 //
6156 // Build and send a request for READ_KEY for RPC key
6157 //
6158
6159 TraceLog((CdromDebugTrace,
6160 "CdRomPickDvdRegion (%p): Getting RpcKey\n",
6161 Fdo));
6162 ClassSendDeviceIoControlSynchronous(
6163 IOCTL_DVD_READ_KEY,
6164 Fdo,
6165 copyProtectKey,
6166 DVD_RPC_KEY_LENGTH,
6167 DVD_RPC_KEY_LENGTH,
6168 FALSE,
6169 &ioStatus
6170 );
6171 TraceLog((CdromDebugTrace,
6172 "CdRomPickDvdRegion (%p): Got RpcKey %x\n",
6173 Fdo, ioStatus.Status));
6174
6175 if (!NT_SUCCESS(ioStatus.Status)) {
6176
6177 TraceLog((CdromDebugWarning,
6178 "CdRomPickDvdRegion (%p): failed to get RpcKey from "
6179 "a DVD Device\n", Fdo));
6180 goto getout;
6181
6182 }
6183
6184 //
6185 // so we now have what we can get for the media region and the
6186 // drive region. we will not set a region if the drive has one
6187 // set already (mask is not all 1's), nor will we set a region
6188 // if there are no more user resets available.
6189 //
6190
6191 rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
6192
6193
6194 if (rpcKey->RegionMask != 0xff) {
6195 TraceLog((CdromDebugWarning,
6196 "CdRomPickDvdRegion (%p): not picking a region since "
6197 "it is already chosen\n", Fdo));
6198 goto getout;
6199 }
6200
6201 if (rpcKey->UserResetsAvailable <= 1) {
6202 TraceLog((CdromDebugWarning,
6203 "CdRomPickDvdRegion (%p): not picking a region since "
6204 "only one change remains\n", Fdo));
6205 goto getout;
6206 }
6207
6208 defaultDvdRegion = 0;
6209
6210 //
6211 // the proppage dvd class installer sets
6212 // this key based upon the system locale
6213 //
6214
6215 CdRomGetDeviceParameter (
6216 Fdo,
6217 DVD_DEFAULT_REGION,
6218 &defaultDvdRegion
6219 );
6220
6221 if (defaultDvdRegion > DVD_MAX_REGION) {
6222
6223 //
6224 // the registry has a bogus default
6225 //
6226
6227 TraceLog((CdromDebugWarning,
6228 "CdRomPickDvdRegion (%p): registry has a bogus default "
6229 "region value of %x\n", Fdo, defaultDvdRegion));
6230 defaultDvdRegion = 0;
6231
6232 }
6233
6234 //
6235 // if defaultDvdRegion == 0, it means no default.
6236 //
6237
6238 //
6239 // we will select the initial dvd region for the user
6240 //
6241
6242 if ((defaultDvdRegion != 0) &&
6243 (mediaRegion &
6244 (1 << (defaultDvdRegion - 1))
6245 )
6246 ) {
6247
6248 //
6249 // first choice:
6250 // the media has region that matches
6251 // the default dvd region.
6252 //
6253
6254 dvdRegion = (1 << (defaultDvdRegion - 1));
6255
6256 TraceLog((CdromDebugWarning,
6257 "CdRomPickDvdRegion (%p): Choice #1: media matches "
6258 "drive's default, chose region %x\n", Fdo, dvdRegion));
6259
6260
6261 } else if (mediaRegion) {
6262
6263 //
6264 // second choice:
6265 // pick the lowest region number
6266 // from the media
6267 //
6268
6269 UCHAR mask;
6270
6271 mask = 1;
6272 dvdRegion = 0;
6273 while (mediaRegion && !dvdRegion) {
6274
6275 //
6276 // pick the lowest bit
6277 //
6278 dvdRegion = mediaRegion & mask;
6279 mask <<= 1;
6280 }
6281
6282 TraceLog((CdromDebugWarning,
6283 "CdRomPickDvdRegion (%p): Choice #2: choosing lowest "
6284 "media region %x\n", Fdo, dvdRegion));
6285
6286 } else if (defaultDvdRegion) {
6287
6288 //
6289 // third choice:
6290 // default dvd region from the dvd class installer
6291 //
6292
6293 dvdRegion = (1 << (defaultDvdRegion - 1));
6294 TraceLog((CdromDebugWarning,
6295 "CdRomPickDvdRegion (%p): Choice #3: using default "
6296 "region for this install %x\n", Fdo, dvdRegion));
6297
6298 } else {
6299
6300 //
6301 // unable to pick one for the user -- this should rarely
6302 // happen, since the proppage dvd class installer sets
6303 // the key based upon the system locale
6304 //
6305 TraceLog((CdromDebugWarning,
6306 "CdRomPickDvdRegion (%p): Choice #4: failed to choose "
6307 "a media region\n", Fdo));
6308 goto getout;
6309
6310 }
6311
6312 //
6313 // now that we've chosen a region, set the region by sending the
6314 // appropriate request to the drive
6315 //
6316
6317 RtlZeroMemory (copyProtectKey, bufferLen);
6318 copyProtectKey->KeyLength = DVD_SET_RPC_KEY_LENGTH;
6319 copyProtectKey->KeyType = DvdSetRpcKey;
6320 dvdRpcKey = (PDVD_SET_RPC_KEY) copyProtectKey->KeyData;
6321 dvdRpcKey->PreferredDriveRegionCode = (UCHAR) ~dvdRegion;
6322
6323 //
6324 // Build and send request for SEND_KEY
6325 //
6326 TraceLog((CdromDebugTrace,
6327 "CdRomPickDvdRegion (%p): Sending new Rpc Key to region %x\n",
6328 Fdo, dvdRegion));
6329
6330 ClassSendDeviceIoControlSynchronous(
6331 IOCTL_DVD_SEND_KEY2,
6332 Fdo,
6333 copyProtectKey,
6334 DVD_SET_RPC_KEY_LENGTH,
6335 0,
6336 FALSE,
6337 &ioStatus);
6338 TraceLog((CdromDebugTrace,
6339 "CdRomPickDvdRegion (%p): Sent new Rpc Key %x\n",
6340 Fdo, ioStatus.Status));
6341
6342 if (!NT_SUCCESS(ioStatus.Status)) {
6343 DebugPrint ((1, "CdRomPickDvdRegion (%p): unable to set dvd initial "
6344 " region code (%p)\n", Fdo, ioStatus.Status));
6345 } else {
6346 DebugPrint ((1, "CdRomPickDvdRegion (%p): Successfully set dvd "
6347 "initial region\n", Fdo));
6348 pickDvdRegion = 0;
6349 }
6350
6351 getout:
6352 if (dvdReadStructure) {
6353 ExFreePool (dvdReadStructure);
6354 }
6355
6356 //
6357 // update the new PickDvdRegion value
6358 //
6359
6360 InterlockedExchange(&cddata->PickDvdRegion, pickDvdRegion);
6361
6362 return;
6363 }
6364 \f
6365
6366 NTSTATUS
6367 CdRomRetryRequest(
6368 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
6369 IN PIRP Irp,
6370 IN ULONG Delay,
6371 IN BOOLEAN ResendIrp
6372 )
6373 {
6374 PCDROM_DATA cdData;
6375 KIRQL oldIrql;
6376
6377 if(Delay == 0) {
6378 return CdRomRerunRequest(FdoExtension, Irp, ResendIrp);
6379 }
6380
6381 cdData = FdoExtension->CommonExtension.DriverData;
6382
6383 KeAcquireSpinLock(&(cdData->DelayedRetrySpinLock), &oldIrql);
6384
6385 ASSERT(cdData->DelayedRetryIrp == NULL);
6386 ASSERT(cdData->DelayedRetryInterval == 0);
6387
6388 cdData->DelayedRetryIrp = Irp;
6389 cdData->DelayedRetryInterval = Delay;
6390 cdData->DelayedRetryResend = ResendIrp;
6391
6392 KeReleaseSpinLock(&(cdData->DelayedRetrySpinLock), oldIrql);
6393
6394 return STATUS_PENDING;
6395 }
6396 \f
6397
6398 NTSTATUS
6399 CdRomRerunRequest(
6400 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
6401 IN OPTIONAL PIRP Irp,
6402 IN BOOLEAN ResendIrp
6403 )
6404 {
6405 if(ResendIrp) {
6406 return IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject,
6407 Irp);
6408 } else {
6409 KIRQL oldIrql;
6410
6411 oldIrql = KeRaiseIrqlToDpcLevel();
6412 CdRomStartIo(FdoExtension->DeviceObject, Irp);
6413 KeLowerIrql(oldIrql);
6414 return STATUS_MORE_PROCESSING_REQUIRED;
6415 }
6416 }
6417 \f
6418
6419 /*++
6420
6421 Routine Description:
6422
6423 This routine just checks for media change sense/asc/ascq and
6424 also for other events, such as bus resets. this is used to
6425 determine if the device behaviour has changed, to allow for
6426 read and write operations to be allowed and/or disallowed.
6427
6428 Arguments:
6429
6430 ISSUE-2000/3/30-henrygab - not fully doc'd
6431
6432 Return Value:
6433
6434 NTSTATUS
6435
6436 --*/
6437 NTSTATUS
6438 CdRomMmcErrorHandler(
6439 IN PDEVICE_OBJECT Fdo,
6440 IN PSCSI_REQUEST_BLOCK Srb,
6441 OUT PNTSTATUS Status,
6442 OUT PBOOLEAN Retry
6443 )
6444 {
6445 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
6446 BOOLEAN queryCapabilities = FALSE;
6447
6448 if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
6449
6450 PCDROM_DATA cddata = (PCDROM_DATA)commonExtension->DriverData;
6451 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
6452
6453 //
6454 // the following sense keys could indicate a change in
6455 // capabilities.
6456 //
6457
6458 //
6459 // we used to expect this to be serialized, and only hit from our
6460 // own routine. we now allow some requests to continue during our
6461 // processing of the capabilities update in order to allow
6462 // IoReadPartitionTable() to succeed.
6463 //
6464
6465 switch (senseBuffer->SenseKey & 0xf) {
6466
6467 case SCSI_SENSE_NOT_READY: {
6468 if (senseBuffer->AdditionalSenseCode ==
6469 SCSI_ADSENSE_NO_MEDIA_IN_DEVICE) {
6470
6471 if (cddata->Mmc.WriteAllowed) {
6472 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6473 "CdromErrorHandler: media removed, writes will be "
6474 "failed until new media detected\n"));
6475 }
6476
6477 // NOTE - REF #0002
6478 cddata->Mmc.WriteAllowed = FALSE;
6479 } else
6480 if ((senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
6481 (senseBuffer->AdditionalSenseCodeQualifier ==
6482 SCSI_SENSEQ_BECOMING_READY)) {
6483 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6484 "CdromErrorHandler: media becoming ready, "
6485 "SHOULD notify shell of change time by sending "
6486 "GESN request immediately!\n"));
6487 }
6488 break;
6489 } // end SCSI_SENSE_NOT_READY
6490
6491 case SCSI_SENSE_UNIT_ATTENTION: {
6492 switch (senseBuffer->AdditionalSenseCode) {
6493 case SCSI_ADSENSE_MEDIUM_CHANGED: {
6494
6495 //
6496 // always update if the medium may have changed
6497 //
6498
6499 // NOTE - REF #0002
6500 cddata->Mmc.WriteAllowed = FALSE;
6501 InterlockedCompareExchange(&(cddata->Mmc.UpdateState),
6502 CdromMmcUpdateRequired,
6503 CdromMmcUpdateComplete);
6504
6505 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6506 "CdromErrorHandler: media change detected, need to "
6507 "update drive capabilities\n"));
6508 break;
6509
6510 } // end SCSI_ADSENSE_MEDIUM_CHANGED
6511
6512 case SCSI_ADSENSE_BUS_RESET: {
6513
6514 // NOTE - REF #0002
6515 cddata->Mmc.WriteAllowed = FALSE;
6516 InterlockedCompareExchange(&(cddata->Mmc.UpdateState),
6517 CdromMmcUpdateRequired,
6518 CdromMmcUpdateComplete);
6519
6520 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6521 "CdromErrorHandler: bus reset detected, need to "
6522 "update drive capabilities\n"));
6523 break;
6524
6525 } // end SCSI_ADSENSE_BUS_RESET
6526
6527 case SCSI_ADSENSE_OPERATOR_REQUEST: {
6528
6529 BOOLEAN b = FALSE;
6530
6531 switch (senseBuffer->AdditionalSenseCodeQualifier) {
6532 case SCSI_SENSEQ_MEDIUM_REMOVAL: {
6533
6534 //
6535 // eject notification currently handled by classpnp
6536 //
6537
6538 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6539 "CdromErrorHandler: Eject requested by user\n"));
6540 *Retry = TRUE;
6541 *Status = STATUS_DEVICE_BUSY;
6542 break;
6543 }
6544
6545 case SCSI_SENSEQ_WRITE_PROTECT_DISABLE:
6546 b = TRUE;
6547 case SCSI_SENSEQ_WRITE_PROTECT_ENABLE: {
6548
6549 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6550 "CdromErrorHandler: Write protect %s requested "
6551 "by user\n",
6552 (b ? "disable" : "enable")));
6553 *Retry = TRUE;
6554 *Status = STATUS_DEVICE_BUSY;
6555 // NOTE - REF #0002
6556 cddata->Mmc.WriteAllowed = FALSE;
6557 InterlockedCompareExchange(&(cddata->Mmc.UpdateState),
6558 CdromMmcUpdateRequired,
6559 CdromMmcUpdateComplete);
6560
6561 }
6562
6563 } // end of AdditionalSenseCodeQualifier switch
6564
6565
6566 break;
6567
6568 } // end SCSI_ADSENSE_OPERATOR_REQUEST
6569
6570 default: {
6571 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6572 "CdromErrorHandler: Unit attention %02x/%02x\n",
6573 senseBuffer->AdditionalSenseCode,
6574 senseBuffer->AdditionalSenseCodeQualifier));
6575 break;
6576 }
6577
6578 } // end of AdditionSenseCode switch
6579 break;
6580
6581 } // end SCSI_SENSE_UNIT_ATTENTION
6582
6583 case SCSI_SENSE_ILLEGAL_REQUEST: {
6584 if (senseBuffer->AdditionalSenseCode ==
6585 SCSI_ADSENSE_WRITE_PROTECT) {
6586
6587 if (cddata->Mmc.WriteAllowed) {
6588 KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
6589 "CdromErrorHandler: media was writable, but "
6590 "failed request with WRITE_PROTECT error...\n"));
6591 }
6592 // NOTE - REF #0002
6593 // do not update all the capabilities just because
6594 // we can't write to the disc.
6595 cddata->Mmc.WriteAllowed = FALSE;
6596 }
6597 break;
6598 } // end SCSI_SENSE_ILLEGAL_REQUEST
6599
6600 } // end of SenseKey switch
6601
6602 } // end of SRB_STATUS_AUTOSENSE_VALID
6603
6604 return STATUS_SUCCESS;
6605 }
6606
6607 /*++
6608
6609 Routine Description:
6610
6611 This routine checks for a device-specific error handler
6612 and calls it if it exists. This allows multiple drives
6613 that require their own error handler to co-exist.
6614
6615 --*/
6616 VOID
6617 CdRomErrorHandler(
6618 PDEVICE_OBJECT DeviceObject,
6619 PSCSI_REQUEST_BLOCK Srb,
6620 NTSTATUS *Status,
6621 BOOLEAN *Retry
6622 )
6623 {
6624 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
6625 PCDROM_DATA cddata = (PCDROM_DATA)commonExtension->DriverData;
6626 PSENSE_DATA sense = Srb->SenseInfoBuffer;
6627
6628 if ((Srb->SenseInfoBufferLength >=
6629 RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA,AdditionalSenseCodeQualifier)) &&
6630 TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
6631
6632 //
6633 // Many non-WHQL certified drives (mostly CD-RW) return
6634 // 2/4/0 when they have no media instead of the obvious
6635 // choice of:
6636 //
6637 // SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
6638 //
6639 // These drives should not pass WHQL certification due
6640 // to this discrepency.
6641 //
6642 // However, we have to retry on 2/4/0 (Not ready, LUN not ready,
6643 // no info) and also 3/2/0 (no seek complete).
6644 //
6645 // These conditions occur when the shell tries to examine an
6646 // injected CD (e.g. for autoplay) before the CD is spun up.
6647 //
6648 // The drive should be returning an ASCQ of SCSI_SENSEQ_BECOMING_READY
6649 // (0x01) in order to comply with WHQL standards.
6650 //
6651 // The default retry timeout of one second is acceptable to balance
6652 // these discrepencies. don't modify the status, though....
6653 //
6654
6655 if (((sense->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) &&
6656 (sense->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
6657 (sense->AdditionalSenseCodeQualifier == SCSI_SENSEQ_CAUSE_NOT_REPORTABLE)
6658 ) {
6659
6660 *Retry = TRUE;
6661
6662 } else if (((sense->SenseKey & 0xf) == SCSI_SENSE_MEDIUM_ERROR) &&
6663 (sense->AdditionalSenseCode == 0x2) &&
6664 (sense->AdditionalSenseCodeQualifier == 0x0)
6665 ) {
6666
6667 *Retry = TRUE;
6668
6669 } else if ((sense->AdditionalSenseCode == 0x57) &&
6670 (sense->AdditionalSenseCodeQualifier == 0x00)
6671 ) {
6672
6673 //
6674 // UNABLE_TO_RECOVER_TABLE_OF_CONTENTS
6675 // the Matshita CR-585 returns this for all read commands
6676 // on blank CD-R and CD-RW media, and we need to handle
6677 // this for READ_CD detection ability.
6678 //
6679
6680 *Retry = FALSE;
6681 *Status = STATUS_UNRECOGNIZED_MEDIA;
6682
6683 }
6684
6685 }
6686
6687 //
6688 // tail recursion in both cases takes no stack
6689 //
6690
6691 if (cddata->ErrorHandler) {
6692 cddata->ErrorHandler(DeviceObject, Srb, Status, Retry);
6693 }
6694 return;
6695 }
6696 \f
6697
6698 /*++
6699
6700 Routine Description:
6701
6702 This routine is called for a shutdown and flush IRPs.
6703 These are sent by the system before it actually shuts
6704 down or when the file system does a flush.
6705
6706 Arguments:
6707
6708 DriverObject - Pointer to device object to being shutdown by system.
6709
6710 Irp - IRP involved.
6711
6712 Return Value:
6713
6714 NT Status
6715
6716 --*/
6717 NTSTATUS
6718 CdRomShutdownFlush(
6719 IN PDEVICE_OBJECT DeviceObject,
6720 IN PIRP Irp
6721 )
6722 {
6723 IoMarkIrpPending(Irp);
6724 IoStartPacket(DeviceObject, Irp, NULL, NULL);
6725 return STATUS_PENDING;
6726
6727 }
6728
6729 /*++
6730
6731 Routine Description:
6732
6733 This routine is called for intermediate work a shutdown or
6734 flush IRPs would need to do. We just want to free our resources
6735 and return STATUS_MORE_PROCESSING_REQUIRED.
6736
6737 Arguments:
6738
6739 DeviceObject - NULL?
6740
6741 Irp - IRP to free
6742
6743 Context - NULL
6744
6745 Return Value:
6746
6747 NT Status
6748
6749 --*/
6750 NTSTATUS
6751 CdRomShutdownFlushCompletion(
6752 IN PDEVICE_OBJECT Fdo,
6753 IN PIRP NewIrp,
6754 IN PIRP OriginalIrp
6755 )
6756 {
6757 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
6758 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
6759 PIO_STACK_LOCATION originalIrpStack;
6760 ULONG_PTR iteration;
6761 NTSTATUS status = STATUS_SUCCESS;
6762
6763 ASSERT(OriginalIrp);
6764
6765 originalIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
6766
6767 //
6768 // always use a new irp so we can call
6769 // CdRomCompleteIrpAndStartNextPacketSafely() from this routine.
6770 //
6771
6772 if (NewIrp != NULL) {
6773 status = NewIrp->IoStatus.Status;
6774 IoFreeIrp(NewIrp);
6775 NewIrp = NULL;
6776 }
6777
6778 if (!NT_SUCCESS(status)) {
6779 BAIL_OUT(OriginalIrp);
6780 goto SafeExit;
6781 }
6782
6783 //
6784 // the current irpstack saves the counter which states
6785 // what part of the multi-part shutdown or flush we are in.
6786 //
6787
6788 iteration = (ULONG_PTR)originalIrpStack->Parameters.Others.Argument1;
6789 iteration++;
6790 originalIrpStack->Parameters.Others.Argument1 = (PVOID)iteration;
6791
6792 switch (iteration) {
6793 case 2:
6794 if (originalIrpStack->MajorFunction != IRP_MJ_SHUTDOWN) {
6795 //
6796 // then we don't want to send the unlock command
6797 // the incrementing of the state was done above.
6798 // return the completion routine's result.
6799 //
6800 return CdRomShutdownFlushCompletion(Fdo, NULL, OriginalIrp);
6801 }
6802 // else fall through....
6803
6804 case 1: {
6805
6806 PIRP newIrp = NULL;
6807 PSCSI_REQUEST_BLOCK newSrb = NULL;
6808 PCDB newCdb = NULL;
6809 PIO_STACK_LOCATION newIrpStack = NULL;
6810 ULONG isRemoved;
6811
6812 newIrp = IoAllocateIrp((CCHAR)(Fdo->StackSize+1), FALSE);
6813 if (newIrp == NULL) {
6814 BAIL_OUT(OriginalIrp);
6815 status = STATUS_INSUFFICIENT_RESOURCES;
6816 goto SafeExit;
6817 }
6818 newSrb = ExAllocatePoolWithTag(NonPagedPool,
6819 sizeof(SCSI_REQUEST_BLOCK),
6820 CDROM_TAG_SRB);
6821 if (newSrb == NULL) {
6822 IoFreeIrp(newIrp);
6823 BAIL_OUT(OriginalIrp);
6824 status = STATUS_INSUFFICIENT_RESOURCES;
6825 goto SafeExit;
6826 }
6827
6828 //
6829 // ClassIoComplete will free the SRB, but we need a routine
6830 // that will free the irp. then just call ClassSendAsync,
6831 // and don't care about the return value, since the completion
6832 // routine will be called anyways.
6833 //
6834
6835 IoSetNextIrpStackLocation(newIrp);
6836 newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
6837 newIrpStack->DeviceObject = Fdo;
6838 IoSetCompletionRoutine(newIrp,
6839 CdRomShutdownFlushCompletion,
6840 OriginalIrp,
6841 TRUE, TRUE, TRUE);
6842 IoSetNextIrpStackLocation(newIrp);
6843 newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
6844 newIrpStack->DeviceObject = Fdo;
6845
6846 //
6847 // setup the request
6848 //
6849
6850 RtlZeroMemory(newSrb, sizeof(SCSI_REQUEST_BLOCK));
6851 newCdb = (PCDB)(newSrb->Cdb);
6852
6853 newSrb->QueueTag = SP_UNTAGGED;
6854 newSrb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
6855 newSrb->Function = SRB_FUNCTION_EXECUTE_SCSI;
6856
6857 //
6858 // tell classpnp not to call StartNextPacket()
6859 //
6860
6861 newSrb->SrbFlags = SRB_FLAGS_DONT_START_NEXT_PACKET;
6862
6863 if (iteration == 1) {
6864
6865 //
6866 // first synchronize the cache
6867 //
6868
6869 newSrb->TimeOutValue = fdoExtension->TimeOutValue * 4;
6870 newSrb->CdbLength = 10;
6871 newCdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
6872
6873 } else if (iteration == 2) {
6874
6875 //
6876 // then unlock the medium
6877 //
6878
6879 ASSERT( originalIrpStack->MajorFunction == IRP_MJ_SHUTDOWN );
6880
6881 newSrb->TimeOutValue = fdoExtension->TimeOutValue;
6882 newSrb->CdbLength = 6;
6883 newCdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
6884 newCdb->MEDIA_REMOVAL.Prevent = FALSE;
6885
6886 }
6887
6888
6889 isRemoved = ClassAcquireRemoveLock(Fdo, newIrp);
6890 if (isRemoved) {
6891 IoFreeIrp(newIrp);
6892 ExFreePool(newSrb);
6893 ClassReleaseRemoveLock(Fdo, newIrp);
6894 BAIL_OUT(OriginalIrp);
6895 status = STATUS_DEVICE_DOES_NOT_EXIST;
6896 goto SafeExit;
6897 }
6898 ClassSendSrbAsynchronous(Fdo, newSrb, newIrp, NULL, 0, FALSE);
6899 break;
6900 }
6901
6902 case 3: {
6903
6904 PSCSI_REQUEST_BLOCK srb;
6905 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(OriginalIrp);
6906
6907 //
6908 // forward this request to the device appropriately,
6909 // don't use this completion routine anymore...
6910 //
6911
6912 srb = ExAllocatePoolWithTag(NonPagedPool,
6913 sizeof(SCSI_REQUEST_BLOCK),
6914 CDROM_TAG_SRB);
6915 if (srb == NULL) {
6916 BAIL_OUT(OriginalIrp);
6917 status = STATUS_INSUFFICIENT_RESOURCES;
6918 goto SafeExit;
6919 }
6920
6921 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
6922 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
6923 srb->TimeOutValue = fdoExtension->TimeOutValue * 4;
6924 srb->QueueTag = SP_UNTAGGED;
6925 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
6926 srb->SrbFlags = fdoExtension->SrbFlags;
6927 srb->CdbLength = 0;
6928 srb->OriginalRequest = OriginalIrp;
6929
6930 if (originalIrpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
6931 srb->Function = SRB_FUNCTION_SHUTDOWN;
6932 } else {
6933 srb->Function = SRB_FUNCTION_FLUSH;
6934 }
6935
6936 //
6937 // Set up IoCompletion routine address.
6938 //
6939
6940 IoSetCompletionRoutine(OriginalIrp,
6941 ClassIoComplete,
6942 srb,
6943 TRUE, TRUE, TRUE);
6944
6945 //
6946 // Set the retry count to zero.
6947 //
6948
6949 originalIrpStack->Parameters.Others.Argument4 = (PVOID) 0;
6950
6951 //
6952 // Get next stack location and set major function code.
6953 //
6954
6955 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
6956
6957 //
6958 // Set up SRB for execute scsi request.
6959 // Save SRB address in next stack for port driver.
6960 //
6961
6962 nextIrpStack->Parameters.Scsi.Srb = srb;
6963
6964 //
6965 // Call the port driver to process the request.
6966 //
6967
6968 IoCallDriver(commonExtension->LowerDeviceObject, OriginalIrp);
6969
6970 break;
6971
6972 }
6973 default: {
6974 ASSERT(FALSE);
6975 break;
6976 }
6977
6978 } // end switch
6979
6980 status = STATUS_SUCCESS;
6981
6982 SafeExit:
6983
6984 if (!NT_SUCCESS(status)) {
6985 OriginalIrp->IoStatus.Status = status;
6986 CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
6987 }
6988
6989 //
6990 // always return STATUS_MORE_PROCESSING_REQUIRED, so noone else tries
6991 // to access the new irp that we free'd....
6992 //
6993
6994 return STATUS_MORE_PROCESSING_REQUIRED;
6995
6996 } // end CdromShutdownFlush()
6997
6998
6999 VOID
7000 CdromFakePartitionInfo(
7001 IN PCOMMON_DEVICE_EXTENSION CommonExtension,
7002 IN PIRP Irp
7003 )
7004 {
7005 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
7006 ULONG ioctl = currentIrpStack->Parameters.DeviceIoControl.IoControlCode;
7007 PVOID systemBuffer = Irp->AssociatedIrp.SystemBuffer;
7008
7009 ASSERT(systemBuffer);
7010
7011 if ((ioctl != IOCTL_DISK_GET_DRIVE_LAYOUT) &&
7012 (ioctl != IOCTL_DISK_GET_DRIVE_LAYOUT_EX) &&
7013 (ioctl != IOCTL_DISK_GET_PARTITION_INFO) &&
7014 (ioctl != IOCTL_DISK_GET_PARTITION_INFO_EX)) {
7015 TraceLog((CdromDebugError,
7016 "CdromFakePartitionInfo: unhandled ioctl %x\n", ioctl));
7017 Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
7018 Irp->IoStatus.Information = 0;
7019 CdRomCompleteIrpAndStartNextPacketSafely(CommonExtension->DeviceObject,
7020 Irp);
7021 return;
7022 }
7023
7024 //
7025 // nothing to fail from this point on, so set the size appropriately
7026 // and set irp's status to success.
7027 //
7028
7029 TraceLog((CdromDebugWarning,
7030 "CdromFakePartitionInfo: incoming ioctl %x\n", ioctl));
7031
7032
7033 Irp->IoStatus.Status = STATUS_SUCCESS;
7034 switch (ioctl) {
7035 case IOCTL_DISK_GET_DRIVE_LAYOUT:
7036 Irp->IoStatus.Information = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
7037 PartitionEntry[1]);
7038 RtlZeroMemory(systemBuffer, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,
7039 PartitionEntry[1]));
7040 break;
7041 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
7042 Irp->IoStatus.Information = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX,
7043 PartitionEntry[1]);
7044 RtlZeroMemory(systemBuffer, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX,
7045 PartitionEntry[1]));
7046 break;
7047 case IOCTL_DISK_GET_PARTITION_INFO:
7048 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
7049 RtlZeroMemory(systemBuffer, sizeof(PARTITION_INFORMATION));
7050 break;
7051 case IOCTL_DISK_GET_PARTITION_INFO_EX:
7052 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
7053 RtlZeroMemory(systemBuffer, sizeof(PARTITION_INFORMATION_EX));
7054 break;
7055 default:
7056 ASSERT(!"Invalid ioctl should not have reached this point\n");
7057 break;
7058 }
7059
7060 //
7061 // if we are getting the drive layout, then we need to start by
7062 // adding some of the non-partition stuff that says we have
7063 // exactly one partition available.
7064 //
7065
7066
7067 if (ioctl == IOCTL_DISK_GET_DRIVE_LAYOUT) {
7068
7069 PDRIVE_LAYOUT_INFORMATION layout;
7070 layout = (PDRIVE_LAYOUT_INFORMATION)systemBuffer;
7071 layout->PartitionCount = 1;
7072 layout->Signature = 1;
7073 systemBuffer = (PVOID)(layout->PartitionEntry);
7074 ioctl = IOCTL_DISK_GET_PARTITION_INFO;
7075
7076 } else if (ioctl == IOCTL_DISK_GET_DRIVE_LAYOUT_EX) {
7077
7078 PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
7079 layoutEx = (PDRIVE_LAYOUT_INFORMATION_EX)systemBuffer;
7080 layoutEx->PartitionStyle = PARTITION_STYLE_MBR;
7081 layoutEx->PartitionCount = 1;
7082 layoutEx->Mbr.Signature = 1;
7083 systemBuffer = (PVOID)(layoutEx->PartitionEntry);
7084 ioctl = IOCTL_DISK_GET_PARTITION_INFO_EX;
7085
7086 }
7087
7088 //
7089 // NOTE: the local var 'ioctl' is now modified to either EX or
7090 // non-EX version. the local var 'systemBuffer' is now pointing
7091 // to the partition information structure.
7092 //
7093
7094 if (ioctl == IOCTL_DISK_GET_PARTITION_INFO) {
7095
7096 PPARTITION_INFORMATION partitionInfo;
7097 partitionInfo = (PPARTITION_INFORMATION)systemBuffer;
7098 partitionInfo->RewritePartition = FALSE;
7099 partitionInfo->RecognizedPartition = TRUE;
7100 partitionInfo->PartitionType = PARTITION_FAT32;
7101 partitionInfo->BootIndicator = FALSE;
7102 partitionInfo->HiddenSectors = 0;
7103 partitionInfo->StartingOffset.QuadPart = 0;
7104 partitionInfo->PartitionLength = CommonExtension->PartitionLength;
7105 partitionInfo->PartitionNumber = 0;
7106
7107 } else {
7108
7109 PPARTITION_INFORMATION_EX partitionInfo;
7110 partitionInfo = (PPARTITION_INFORMATION_EX)systemBuffer;
7111 partitionInfo->PartitionStyle = PARTITION_STYLE_MBR;
7112 partitionInfo->RewritePartition = FALSE;
7113 partitionInfo->Mbr.RecognizedPartition = TRUE;
7114 partitionInfo->Mbr.PartitionType = PARTITION_FAT32;
7115 partitionInfo->Mbr.BootIndicator = FALSE;
7116 partitionInfo->Mbr.HiddenSectors = 0;
7117 partitionInfo->StartingOffset.QuadPart = 0;
7118 partitionInfo->PartitionLength = CommonExtension->PartitionLength;
7119 partitionInfo->PartitionNumber = 0;
7120
7121 }
7122 TraceLog((CdromDebugWarning,
7123 "CdromFakePartitionInfo: finishing ioctl %x\n",
7124 currentIrpStack->Parameters.DeviceIoControl.IoControlCode));
7125
7126 //
7127 // complete the irp
7128 //
7129
7130 CdRomCompleteIrpAndStartNextPacketSafely(CommonExtension->DeviceObject,
7131 Irp);
7132 return;
7133
7134 }
7135
7136