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