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