f86f2decf5e1f82be0eff4c5603784a99c90154c
[reactos.git] / reactos / drivers / storage / class / cdrom / cdrom.c
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 capabilites (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 issueing 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 UpdateCapcity - "
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:
2185 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
2186
2187 //
2188 // Issue ReadCapacity to update device extension
2189 // with information for current media.
2190 //
2191
2192 DebugPrint((3,
2193 "CdRomStartIo: Get drive capacity\n"));
2194
2195 //
2196 // setup remaining srb and cdb parameters.
2197 //
2198
2199 srb->SrbFlags = deviceExtension->SrbFlags;
2200 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2201 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
2202 srb->CdbLength = 10;
2203 srb->TimeOutValue = deviceExtension->TimeOutValue;
2204
2205 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(READ_CAPACITY_DATA));
2206 if (!dataBuffer) {
2207 Irp->IoStatus.Information = 0;
2208 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2209 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2210 ExFreePool(senseBuffer);
2211 ExFreePool(srb);
2212 IoFreeIrp(irp2);
2213 IoStartNextPacket(DeviceObject, FALSE);
2214 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
2215 return;
2216
2217 }
2218
2219 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2220 sizeof(READ_CAPACITY_DATA),
2221 FALSE,
2222 FALSE,
2223 (PIRP) NULL);
2224
2225 if (!irp2->MdlAddress) {
2226 Irp->IoStatus.Information = 0;
2227 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2228 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2229 ExFreePool(senseBuffer);
2230 ExFreePool(srb);
2231 ExFreePool(dataBuffer);
2232 IoFreeIrp(irp2);
2233 IoStartNextPacket(DeviceObject, FALSE);
2234 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
2235 return;
2236 }
2237
2238 //
2239 // Prepare the MDL
2240 //
2241
2242 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2243
2244 srb->DataBuffer = dataBuffer;
2245 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
2246
2247 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2248 return;
2249 }
2250
2251 case IOCTL_CDROM_CHECK_VERIFY: {
2252
2253 //
2254 // Since a test unit ready is about to be performed, reset the timer
2255 // value to decrease the opportunities for it to race with this code.
2256 //
2257
2258 cdData->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
2259
2260 //
2261 // Set up the SRB/CDB
2262 //
2263
2264 srb->CdbLength = 6;
2265 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
2266 srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
2267 srb->SrbFlags = deviceExtension->SrbFlags;
2268 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2269
2270 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Sending CHECK_VERIFY irp %lx\n", Irp, irp2));
2271 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2272 return;
2273 }
2274
2275 case IOCTL_CDROM_GET_LAST_SESSION:
2276
2277 //
2278 // Set format to return first and last session numbers.
2279 //
2280
2281 cdb->READ_TOC.Format = GET_LAST_SESSION;
2282
2283 //
2284 // Fall through to READ TOC code.
2285 //
2286
2287 case IOCTL_CDROM_READ_TOC: {
2288
2289
2290 if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) {
2291
2292 //
2293 // Use MSF addressing if not request for session information.
2294 //
2295
2296 cdb->READ_TOC.Msf = CDB_USE_MSF;
2297 }
2298
2299 //
2300 // Set size of TOC structure.
2301 //
2302
2303 transferByteCount =
2304 currentIrpStack->Parameters.Read.Length >
2305 sizeof(CDROM_TOC) ? sizeof(CDROM_TOC):
2306 currentIrpStack->Parameters.Read.Length;
2307
2308 cdb->READ_TOC.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
2309 cdb->READ_TOC.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
2310
2311 cdb->READ_TOC.Control = 0;
2312
2313 //
2314 // Start at beginning of disc.
2315 //
2316
2317 cdb->READ_TOC.StartingTrack = 0;
2318
2319 //
2320 // setup remaining srb and cdb parameters.
2321 //
2322
2323 srb->SrbFlags = deviceExtension->SrbFlags;
2324 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2325 srb->DataTransferLength = transferByteCount;
2326 srb->CdbLength = 10;
2327 srb->TimeOutValue = deviceExtension->TimeOutValue;
2328
2329 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount);
2330 if (!dataBuffer) {
2331 Irp->IoStatus.Information = 0;
2332 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2333 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2334 ExFreePool(senseBuffer);
2335 ExFreePool(srb);
2336 IoFreeIrp(irp2);
2337 IoStartNextPacket(DeviceObject, FALSE);
2338 return;
2339
2340 }
2341
2342 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2343 transferByteCount,
2344 FALSE,
2345 FALSE,
2346 (PIRP) NULL);
2347
2348 if (!irp2->MdlAddress) {
2349 Irp->IoStatus.Information = 0;
2350 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2351 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2352 ExFreePool(senseBuffer);
2353 ExFreePool(srb);
2354 ExFreePool(dataBuffer);
2355 IoFreeIrp(irp2);
2356 IoStartNextPacket(DeviceObject, FALSE);
2357 return;
2358 }
2359
2360 //
2361 // Prepare the MDL
2362 //
2363
2364 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2365
2366 srb->DataBuffer = dataBuffer;
2367 cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
2368
2369 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2370 return;
2371
2372 }
2373
2374 case IOCTL_CDROM_PLAY_AUDIO_MSF: {
2375
2376 PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2377
2378 //
2379 // Set up the SRB/CDB
2380 //
2381
2382 srb->CdbLength = 10;
2383 cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
2384
2385 cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
2386 cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
2387 cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
2388
2389 cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
2390 cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
2391 cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
2392
2393 srb->TimeOutValue = deviceExtension->TimeOutValue;
2394 srb->SrbFlags = deviceExtension->SrbFlags;
2395 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2396
2397 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2398 return;
2399
2400 }
2401
2402 case IOCTL_CDROM_READ_Q_CHANNEL: {
2403
2404 PCDROM_SUB_Q_DATA_FORMAT inputBuffer =
2405 Irp->AssociatedIrp.SystemBuffer;
2406
2407 //
2408 // Allocate buffer for subq channel information.
2409 //
2410
2411 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
2412 sizeof(SUB_Q_CHANNEL_DATA));
2413
2414 if (!dataBuffer) {
2415 Irp->IoStatus.Information = 0;
2416 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2417 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2418 ExFreePool(senseBuffer);
2419 ExFreePool(srb);
2420 IoFreeIrp(irp2);
2421 IoStartNextPacket(DeviceObject, FALSE);
2422 return;
2423
2424 }
2425
2426 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2427 transferByteCount,
2428 FALSE,
2429 FALSE,
2430 (PIRP) NULL);
2431
2432 if (!irp2->MdlAddress) {
2433 Irp->IoStatus.Information = 0;
2434 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2435 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2436 ExFreePool(senseBuffer);
2437 ExFreePool(srb);
2438 ExFreePool(dataBuffer);
2439 IoFreeIrp(irp2);
2440 IoStartNextPacket(DeviceObject, FALSE);
2441 return;
2442 }
2443
2444 //
2445 // Prepare the MDL
2446 //
2447
2448 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2449
2450 srb->DataBuffer = dataBuffer;
2451
2452 //
2453 // Always logical unit 0, but only use MSF addressing
2454 // for IOCTL_CDROM_CURRENT_POSITION
2455 //
2456
2457 if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION)
2458 cdb->SUBCHANNEL.Msf = CDB_USE_MSF;
2459
2460 //
2461 // Return subchannel data
2462 //
2463
2464 cdb->SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK;
2465
2466 //
2467 // Specify format of informatin to return
2468 //
2469
2470 cdb->SUBCHANNEL.Format = inputBuffer->Format;
2471
2472 //
2473 // Specify which track to access (only used by Track ISRC reads)
2474 //
2475
2476 if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC) {
2477 cdb->SUBCHANNEL.TrackNumber = inputBuffer->Track;
2478 }
2479
2480 //
2481 // Set size of channel data -- however, this is dependent on
2482 // what information we are requesting (which Format)
2483 //
2484
2485 switch( inputBuffer->Format ) {
2486
2487 case IOCTL_CDROM_CURRENT_POSITION:
2488 transferByteCount = sizeof(SUB_Q_CURRENT_POSITION);
2489 break;
2490
2491 case IOCTL_CDROM_MEDIA_CATALOG:
2492 transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
2493 break;
2494
2495 case IOCTL_CDROM_TRACK_ISRC:
2496 transferByteCount = sizeof(SUB_Q_TRACK_ISRC);
2497 break;
2498 }
2499
2500 cdb->SUBCHANNEL.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
2501 cdb->SUBCHANNEL.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
2502 cdb->SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL;
2503 srb->SrbFlags = deviceExtension->SrbFlags;
2504 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2505 srb->DataTransferLength = transferByteCount;
2506 srb->CdbLength = 10;
2507 srb->TimeOutValue = deviceExtension->TimeOutValue;
2508
2509 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2510 return;
2511
2512 }
2513
2514 case IOCTL_CDROM_PAUSE_AUDIO: {
2515
2516 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
2517 cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE;
2518
2519 srb->CdbLength = 10;
2520 srb->TimeOutValue = deviceExtension->TimeOutValue;
2521 srb->SrbFlags = deviceExtension->SrbFlags;
2522 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2523
2524 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2525 return;
2526 }
2527
2528 case IOCTL_CDROM_RESUME_AUDIO: {
2529
2530 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
2531 cdb->PAUSE_RESUME.Action = CDB_AUDIO_RESUME;
2532
2533 srb->CdbLength = 10;
2534 srb->TimeOutValue = deviceExtension->TimeOutValue;
2535 srb->SrbFlags = deviceExtension->SrbFlags;
2536 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2537
2538 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2539 return;
2540 }
2541
2542 case IOCTL_CDROM_SEEK_AUDIO_MSF: {
2543
2544 PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2545 ULONG logicalBlockAddress;
2546
2547 logicalBlockAddress = MSF_TO_LBA(inputBuffer->M, inputBuffer->S, inputBuffer->F);
2548
2549 cdb->SEEK.OperationCode = SCSIOP_SEEK;
2550 cdb->SEEK.LogicalBlockAddress[0] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
2551 cdb->SEEK.LogicalBlockAddress[1] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
2552 cdb->SEEK.LogicalBlockAddress[2] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
2553 cdb->SEEK.LogicalBlockAddress[3] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
2554
2555 srb->CdbLength = 10;
2556 srb->TimeOutValue = deviceExtension->TimeOutValue;
2557 srb->SrbFlags = deviceExtension->SrbFlags;
2558 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2559
2560 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2561 return;
2562
2563 }
2564
2565 case IOCTL_CDROM_STOP_AUDIO: {
2566
2567 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
2568 cdb->START_STOP.Immediate = 1;
2569 cdb->START_STOP.Start = 0;
2570 cdb->START_STOP.LoadEject = 0;
2571
2572 srb->CdbLength = 6;
2573 srb->TimeOutValue = deviceExtension->TimeOutValue;
2574
2575 srb->SrbFlags = deviceExtension->SrbFlags;
2576 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2577
2578 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2579 return;
2580 }
2581
2582 case IOCTL_CDROM_GET_CONTROL: {
2583 //
2584 // Allocate buffer for volume control information.
2585 //
2586
2587 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
2588 MODE_DATA_SIZE);
2589
2590 if (!dataBuffer) {
2591 Irp->IoStatus.Information = 0;
2592 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2593 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2594 ExFreePool(senseBuffer);
2595 ExFreePool(srb);
2596 IoFreeIrp(irp2);
2597 IoStartNextPacket(DeviceObject, FALSE);
2598 return;
2599
2600 }
2601
2602 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2603 MODE_DATA_SIZE,
2604 FALSE,
2605 FALSE,
2606 (PIRP) NULL);
2607
2608 if (!irp2->MdlAddress) {
2609 Irp->IoStatus.Information = 0;
2610 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2611 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2612 ExFreePool(senseBuffer);
2613 ExFreePool(srb);
2614 ExFreePool(dataBuffer);
2615 IoFreeIrp(irp2);
2616 IoStartNextPacket(DeviceObject, FALSE);
2617 return;
2618 }
2619
2620 //
2621 // Prepare the MDL
2622 //
2623
2624 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2625 srb->DataBuffer = dataBuffer;
2626
2627 RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
2628
2629 //
2630 // Setup for either 6 or 10 byte CDBs.
2631 //
2632
2633 if (use6Byte) {
2634
2635 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2636 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2637 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
2638
2639 //
2640 // Disable block descriptors.
2641 //
2642
2643 cdb->MODE_SENSE.Dbd = TRUE;
2644
2645 srb->CdbLength = 6;
2646 } else {
2647
2648 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
2649 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2650 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
2651 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
2652
2653 //
2654 // Disable block descriptors.
2655 //
2656
2657 cdb->MODE_SENSE10.Dbd = TRUE;
2658
2659 srb->CdbLength = 10;
2660 }
2661
2662 srb->TimeOutValue = deviceExtension->TimeOutValue;
2663 srb->DataTransferLength = MODE_DATA_SIZE;
2664 srb->SrbFlags = deviceExtension->SrbFlags;
2665 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2666
2667 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2668 return;
2669
2670 }
2671
2672 case IOCTL_CDROM_GET_VOLUME:
2673 case IOCTL_CDROM_SET_VOLUME: {
2674
2675 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
2676 MODE_DATA_SIZE);
2677
2678 if (!dataBuffer) {
2679 Irp->IoStatus.Information = 0;
2680 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2681 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2682 ExFreePool(senseBuffer);
2683 ExFreePool(srb);
2684 IoFreeIrp(irp2);
2685 IoStartNextPacket(DeviceObject, FALSE);
2686 return;
2687 }
2688
2689 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2690 MODE_DATA_SIZE,
2691 FALSE,
2692 FALSE,
2693 (PIRP) NULL);
2694
2695 if (!irp2->MdlAddress) {
2696 Irp->IoStatus.Information = 0;
2697 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2698 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2699 ExFreePool(senseBuffer);
2700 ExFreePool(srb);
2701 ExFreePool(dataBuffer);
2702 IoFreeIrp(irp2);
2703 IoStartNextPacket(DeviceObject, FALSE);
2704 return;
2705 }
2706
2707 //
2708 // Prepare the MDL
2709 //
2710
2711 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2712 srb->DataBuffer = dataBuffer;
2713
2714 RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
2715
2716
2717 if (use6Byte) {
2718 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2719 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2720 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
2721
2722 srb->CdbLength = 6;
2723
2724 } else {
2725
2726 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
2727 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2728 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
2729 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
2730
2731 srb->CdbLength = 10;
2732 }
2733
2734 srb->TimeOutValue = deviceExtension->TimeOutValue;
2735 srb->DataTransferLength = MODE_DATA_SIZE;
2736 srb->SrbFlags = deviceExtension->SrbFlags;
2737 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2738
2739 if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_SET_VOLUME) {
2740
2741 //
2742 // Setup a different completion routine as the mode sense data is needed in order
2743 // to send the mode select.
2744 //
2745
2746 IoSetCompletionRoutine(irp2,
2747 CdRomSetVolumeIntermediateCompletion,
2748 srb,
2749 TRUE,
2750 TRUE,
2751 TRUE);
2752
2753 }
2754
2755 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2756 return;
2757
2758 }
2759
2760 default:
2761
2762 //
2763 // Just complete the request - CdRomClassIoctlCompletion will take
2764 // care of it for us
2765 //
2766
2767 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2768 ExFreePool(senseBuffer);
2769 ExFreePool(srb);
2770 IoFreeIrp(irp2);
2771 return;
2772
2773 } // end switch()
2774 }
2775
2776 //
2777 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
2778 // are expected and composed of AutoRun Irps, at present.
2779 //
2780
2781 IoCallDriver(deviceExtension->PortDeviceObject, Irp);
2782 return;
2783 }
2784
2785
2786 NTSTATUS
2787 NTAPI
2788 ScsiCdRomReadVerification(
2789 IN PDEVICE_OBJECT DeviceObject,
2790 IN PIRP Irp
2791 )
2792
2793 /*++
2794
2795 Routine Description:
2796
2797 This is the entry called by the I/O system for read requests.
2798 It builds the SRB and sends it to the port driver.
2799
2800 Arguments:
2801
2802 DeviceObject - the system object for the device.
2803 Irp - IRP involved.
2804
2805 Return Value:
2806
2807 NT Status
2808
2809 --*/
2810
2811 {
2812 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2813 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
2814 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
2815 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
2816
2817 //
2818 // If the cd is playing music then reject this request.
2819 //
2820
2821 if (PLAY_ACTIVE(deviceExtension)) {
2822 Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
2823 return STATUS_DEVICE_BUSY;
2824 }
2825
2826 //
2827 // Verify parameters of this request.
2828 // Check that ending sector is on disc and
2829 // that number of bytes to transfer is a multiple of
2830 // the sector size.
2831 //
2832
2833 startingOffset.QuadPart = currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
2834 transferByteCount;
2835
2836 if (!deviceExtension->DiskGeometry->Geometry.BytesPerSector) {
2837 deviceExtension->DiskGeometry->Geometry.BytesPerSector = 2048;
2838 }
2839
2840 if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) ||
2841 (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1))) {
2842
2843 DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n"));
2844 DebugPrint((1, "\toffset %x:%x, Length %x:%x\n",
2845 startingOffset.u.HighPart,
2846 startingOffset.u.LowPart,
2847 deviceExtension->PartitionLength.u.HighPart,
2848 deviceExtension->PartitionLength.u.LowPart));
2849 DebugPrint((1, "\tbps %x\n", deviceExtension->DiskGeometry->Geometry.BytesPerSector));
2850
2851 //
2852 // Fail request with status of invalid parameters.
2853 //
2854
2855 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2856
2857 return STATUS_INVALID_PARAMETER;
2858 }
2859
2860
2861 return STATUS_SUCCESS;
2862
2863 } // end ScsiCdRomReadVerification()
2864
2865
2866 NTSTATUS
2867 NTAPI
2868 CdRomDeviceControlCompletion(
2869 IN PDEVICE_OBJECT DeviceObject,
2870 IN PIRP Irp,
2871 IN PVOID Context
2872 )
2873 {
2874 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2875 PDEVICE_EXTENSION physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension;
2876 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
2877 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension + 1);
2878 BOOLEAN use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
2879 PIO_STACK_LOCATION realIrpStack;
2880 PIO_STACK_LOCATION realIrpNextStack;
2881 PSCSI_REQUEST_BLOCK srb = Context;
2882 PIRP realIrp = NULL;
2883 NTSTATUS status;
2884 BOOLEAN retry;
2885
2886 //
2887 // Extract the 'real' irp from the irpstack.
2888 //
2889
2890 realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
2891 realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
2892 realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
2893
2894 //
2895 // Check SRB status for success of completing request.
2896 //
2897
2898 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
2899
2900 DebugPrint((2,
2901 "CdRomDeviceControlCompletion: Irp %lx, Srb %lx Real Irp %lx Status %lx\n",
2902 Irp,
2903 srb,
2904 realIrp,
2905 srb->SrbStatus));
2906
2907 //
2908 // Release the queue if it is frozen.
2909 //
2910
2911 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
2912 DebugPrint((2, "CdRomDeviceControlCompletion: Releasing Queue\n"));
2913 ScsiClassReleaseQueue(DeviceObject);
2914 }
2915
2916
2917 retry = ScsiClassInterpretSenseInfo(DeviceObject,
2918 srb,
2919 irpStack->MajorFunction,
2920 irpStack->Parameters.DeviceIoControl.IoControlCode,
2921 MAXIMUM_RETRIES - ((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
2922 &status);
2923
2924 DebugPrint((2, "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
2925 (retry ? "" : "not ")));
2926
2927 //
2928 // Some of the Device Controls need special cases on non-Success status's.
2929 //
2930
2931 if (realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
2932 if ((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) ||
2933 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) ||
2934 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_CONTROL) ||
2935 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_VOLUME)) {
2936
2937 if (status == STATUS_DATA_OVERRUN) {
2938 status = STATUS_SUCCESS;
2939 retry = FALSE;
2940 }
2941 }
2942
2943 if (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_Q_CHANNEL) {
2944 PLAY_ACTIVE(deviceExtension) = FALSE;
2945 }
2946 }
2947
2948 //
2949 // If the status is verified required and the this request
2950 // should bypass verify required then retry the request.
2951 //
2952
2953 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
2954 status == STATUS_VERIFY_REQUIRED) {
2955
2956 if (((realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) ||
2957 (realIrpStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)) &&
2958 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY)) {
2959
2960 ExFreePool(srb->SenseInfoBuffer);
2961 if (srb->DataBuffer) {
2962 ExFreePool(srb->DataBuffer);
2963 }
2964 ExFreePool(srb);
2965 if (Irp->MdlAddress) {
2966 IoFreeMdl(Irp->MdlAddress);
2967 }
2968
2969 IoFreeIrp(Irp);
2970
2971 //
2972 // Update the geometry information, as the media could have changed.
2973 // The completion routine for this will complete the real irp and start
2974 // the next packet.
2975 //
2976
2977 status = CdRomUpdateCapacity(deviceExtension,realIrp, NULL);
2978 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] CdRomUpdateCapacity completed with status %lx\n", realIrp, status));
2979 ASSERT(status == STATUS_PENDING);
2980
2981 return STATUS_MORE_PROCESSING_REQUIRED;
2982
2983 } else {
2984
2985 status = STATUS_IO_DEVICE_ERROR;
2986 retry = TRUE;
2987 }
2988
2989 }
2990
2991 if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1-1))) {
2992
2993
2994 if (((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
2995
2996 //
2997 // Retry request.
2998 //
2999
3000 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp));
3001
3002
3003 ExFreePool(srb->SenseInfoBuffer);
3004 if (srb->DataBuffer) {
3005 ExFreePool(srb->DataBuffer);
3006 }
3007 ExFreePool(srb);
3008 if (Irp->MdlAddress) {
3009 IoFreeMdl(Irp->MdlAddress);
3010 }
3011
3012 IoFreeIrp(Irp);
3013
3014 //
3015 // Call StartIo directly since IoStartNextPacket hasn't been called,
3016 // the serialisation is still intact.
3017 //
3018
3019 ScsiCdRomStartIo(DeviceObject, realIrp);
3020 return STATUS_MORE_PROCESSING_REQUIRED;
3021
3022 }
3023
3024 //
3025 // Exhausted retries. Fall through and complete the request with the appropriate status.
3026 //
3027
3028 }
3029 } else {
3030
3031 //
3032 // Set status for successful request.
3033 //
3034
3035 status = STATUS_SUCCESS;
3036 }
3037
3038 if (NT_SUCCESS(status)) {
3039
3040 switch (realIrpStack->Parameters.DeviceIoControl.IoControlCode) {
3041
3042 case IOCTL_DISK_GET_LENGTH_INFO: {
3043
3044 PREAD_CAPACITY_DATA readCapacityBuffer = srb->DataBuffer;
3045 ULONG lastSector;
3046 ULONG bps;
3047 ULONG lastBit;
3048 ULONG tmp;
3049
3050 //
3051 // Swizzle bytes from Read Capacity and translate into
3052 // the necessary geometry information in the device extension.
3053 //
3054
3055 tmp = readCapacityBuffer->BytesPerBlock;
3056 ((PFOUR_BYTE)&bps)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
3057 ((PFOUR_BYTE)&bps)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
3058 ((PFOUR_BYTE)&bps)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
3059 ((PFOUR_BYTE)&bps)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
3060
3061 //
3062 // Insure that bps is a power of 2.
3063 // This corrects a problem with the HP 4020i CDR where it
3064 // returns an incorrect number for bytes per sector.
3065 //
3066
3067 if (!bps) {
3068 bps = 2048;
3069 } else {
3070 lastBit = (ULONG) -1;
3071 while (bps) {
3072 lastBit++;
3073 bps = bps >> 1;
3074 }
3075
3076 bps = 1 << lastBit;
3077 }
3078 deviceExtension->DiskGeometry->Geometry.BytesPerSector = bps;
3079
3080 DebugPrint((2,
3081 "CdRomDeviceControlCompletion: Calculated bps %#x\n",
3082 deviceExtension->DiskGeometry->Geometry.BytesPerSector));
3083
3084 //
3085 // Copy last sector in reverse byte order.
3086 //
3087
3088 tmp = readCapacityBuffer->LogicalBlockAddress;
3089 ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
3090 ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
3091 ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
3092 ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
3093
3094 //
3095 // Calculate sector to byte shift.
3096 //
3097
3098 WHICH_BIT(bps, deviceExtension->SectorShift);
3099
3100 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
3101 deviceExtension->DiskGeometry->Geometry.BytesPerSector));
3102
3103 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
3104 lastSector + 1));
3105
3106 //
3107 // Calculate media capacity in bytes.
3108 //
3109
3110 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
3111
3112 //
3113 // Calculate number of cylinders.
3114 //
3115
3116 deviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64));
3117
3118 deviceExtension->PartitionLength.QuadPart =
3119 (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
3120
3121 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
3122
3123 //
3124 // This device supports removable media.
3125 //
3126
3127 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia;
3128
3129 } else {
3130
3131 //
3132 // Assume media type is fixed disk.
3133 //
3134
3135 deviceExtension->DiskGeometry->Geometry.MediaType = FixedMedia;
3136 }
3137
3138 //
3139 // Assume sectors per track are 32;
3140 //
3141
3142 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack = 32;
3143
3144 //
3145 // Assume tracks per cylinder (number of heads) is 64.
3146 //
3147
3148 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder = 64;
3149
3150 //
3151 // Copy the device extension's geometry info into the user buffer.
3152 //
3153
3154 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
3155 &deviceExtension->PartitionLength,
3156 sizeof(GET_LENGTH_INFORMATION));
3157
3158 //
3159 // update information field.
3160 //
3161
3162 realIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
3163 break;
3164 }
3165
3166 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
3167 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
3168
3169 PREAD_CAPACITY_DATA readCapacityBuffer = srb->DataBuffer;
3170 ULONG lastSector;
3171 ULONG bps;
3172 ULONG lastBit;
3173 ULONG tmp;
3174
3175 //
3176 // Swizzle bytes from Read Capacity and translate into
3177 // the necessary geometry information in the device extension.
3178 //
3179
3180 tmp = readCapacityBuffer->BytesPerBlock;
3181 ((PFOUR_BYTE)&bps)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
3182 ((PFOUR_BYTE)&bps)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
3183 ((PFOUR_BYTE)&bps)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
3184 ((PFOUR_BYTE)&bps)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
3185
3186 //
3187 // Insure that bps is a power of 2.
3188 // This corrects a problem with the HP 4020i CDR where it
3189 // returns an incorrect number for bytes per sector.
3190 //
3191
3192 if (!bps) {
3193 bps = 2048;
3194 } else {
3195 lastBit = (ULONG) -1;
3196 while (bps) {
3197 lastBit++;
3198 bps = bps >> 1;
3199 }
3200
3201 bps = 1 << lastBit;
3202 }
3203 deviceExtension->DiskGeometry->Geometry.BytesPerSector = bps;
3204
3205 DebugPrint((2,
3206 "CdRomDeviceControlCompletion: Calculated bps %#x\n",
3207 deviceExtension->DiskGeometry->Geometry.BytesPerSector));
3208
3209 //
3210 // Copy last sector in reverse byte order.
3211 //
3212
3213 tmp = readCapacityBuffer->LogicalBlockAddress;
3214 ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
3215 ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
3216 ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
3217 ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
3218
3219 //
3220 // Calculate sector to byte shift.
3221 //
3222
3223 WHICH_BIT(bps, deviceExtension->SectorShift);
3224
3225 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
3226 deviceExtension->DiskGeometry->Geometry.BytesPerSector));
3227
3228 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
3229 lastSector + 1));
3230
3231 //
3232 // Calculate media capacity in bytes.
3233 //
3234
3235 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
3236
3237 //
3238 // Calculate number of cylinders.
3239 //
3240
3241 deviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64));
3242
3243 deviceExtension->PartitionLength.QuadPart =
3244 (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
3245
3246 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
3247
3248 //
3249 // This device supports removable media.
3250 //
3251
3252 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia;
3253
3254 } else {
3255
3256 //
3257 // Assume media type is fixed disk.
3258 //
3259
3260 deviceExtension->DiskGeometry->Geometry.MediaType = FixedMedia;
3261 }
3262
3263 //
3264 // Assume sectors per track are 32;
3265 //
3266
3267 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack = 32;
3268
3269 //
3270 // Assume tracks per cylinder (number of heads) is 64.
3271 //
3272
3273 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder = 64;
3274
3275 //
3276 // Copy the device extension's geometry info into the user buffer.
3277 //
3278
3279 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
3280 deviceExtension->DiskGeometry,
3281 sizeof(DISK_GEOMETRY));
3282
3283 //
3284 // update information field.
3285 //
3286
3287 realIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
3288 break;
3289 }
3290
3291 case IOCTL_CDROM_CHECK_VERIFY:
3292
3293 if((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY) &&
3294 (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength)) {
3295
3296 *((PULONG)realIrp->AssociatedIrp.SystemBuffer) =
3297 physicalExtension->MediaChangeCount;
3298 realIrp->IoStatus.Information = sizeof(ULONG);
3299 } else {
3300 realIrp->IoStatus.Information = 0;
3301 }
3302
3303 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] completing CHECK_VERIFY buddy irp %lx\n", realIrp, Irp));
3304 break;
3305
3306 case IOCTL_CDROM_GET_LAST_SESSION:
3307 case IOCTL_CDROM_READ_TOC: {
3308
3309 PCDROM_TOC toc = srb->DataBuffer;
3310
3311 //
3312 // Copy the device extension's geometry info into the user buffer.
3313 //
3314
3315 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
3316 toc,
3317 srb->DataTransferLength);
3318
3319 //
3320 // update information field.
3321 //
3322
3323 realIrp->IoStatus.Information = srb->DataTransferLength;
3324 break;
3325 }
3326
3327 case IOCTL_CDROM_PLAY_AUDIO_MSF:
3328
3329 PLAY_ACTIVE(deviceExtension) = TRUE;
3330
3331 break;
3332
3333 case IOCTL_CDROM_READ_Q_CHANNEL: {
3334
3335 PSUB_Q_CHANNEL_DATA userChannelData = realIrp->AssociatedIrp.SystemBuffer;
3336 #if DBG
3337 PCDROM_SUB_Q_DATA_FORMAT inputBuffer = realIrp->AssociatedIrp.SystemBuffer;
3338 #endif
3339 PSUB_Q_CHANNEL_DATA subQPtr = srb->DataBuffer;
3340
3341 #if DBG
3342 switch( inputBuffer->Format ) {
3343
3344 case IOCTL_CDROM_CURRENT_POSITION:
3345 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->CurrentPosition.Header.AudioStatus ));
3346 DebugPrint((2,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr->CurrentPosition.ADR ));
3347 DebugPrint((2,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr->CurrentPosition.Control ));
3348 DebugPrint((2,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr->CurrentPosition.TrackNumber ));
3349 DebugPrint((2,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr->CurrentPosition.IndexNumber ));
3350 DebugPrint((2,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG)subQPtr->CurrentPosition.AbsoluteAddress) ));
3351 DebugPrint((2,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG)subQPtr->CurrentPosition.TrackRelativeAddress) ));
3352 break;
3353
3354 case IOCTL_CDROM_MEDIA_CATALOG:
3355 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->MediaCatalog.Header.AudioStatus ));
3356 DebugPrint((2,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr->MediaCatalog.Mcval ));
3357 break;
3358
3359 case IOCTL_CDROM_TRACK_ISRC:
3360 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->TrackIsrc.Header.AudioStatus ));
3361 DebugPrint((2,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr->TrackIsrc.Tcval ));
3362 break;
3363
3364 }
3365 #endif
3366
3367 //
3368 // Update the play active status.
3369 //
3370
3371 if (subQPtr->CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
3372
3373 PLAY_ACTIVE(deviceExtension) = TRUE;
3374
3375 } else {
3376
3377 PLAY_ACTIVE(deviceExtension) = FALSE;
3378
3379 }
3380
3381 //
3382 // Check if output buffer is large enough to contain
3383 // the data.
3384 //
3385
3386 if (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
3387 srb->DataTransferLength) {
3388
3389 srb->DataTransferLength =
3390 realIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
3391 }
3392
3393 //
3394 // Copy our buffer into users.
3395 //
3396
3397 RtlMoveMemory(userChannelData,
3398 subQPtr,
3399 srb->DataTransferLength);
3400
3401 realIrp->IoStatus.Information = srb->DataTransferLength;
3402 break;
3403 }
3404
3405 case IOCTL_CDROM_PAUSE_AUDIO:
3406
3407 PLAY_ACTIVE(deviceExtension) = FALSE;
3408 realIrp->IoStatus.Information = 0;
3409 break;
3410
3411 case IOCTL_CDROM_RESUME_AUDIO:
3412
3413 realIrp->IoStatus.Information = 0;
3414 break;
3415
3416 case IOCTL_CDROM_SEEK_AUDIO_MSF:
3417
3418 realIrp->IoStatus.Information = 0;
3419 break;
3420
3421 case IOCTL_CDROM_STOP_AUDIO:
3422
3423 PLAY_ACTIVE(deviceExtension) = FALSE;
3424
3425 realIrp->IoStatus.Information = 0;
3426 break;
3427
3428 case IOCTL_CDROM_GET_CONTROL: {
3429
3430 PCDROM_AUDIO_CONTROL audioControl = srb->DataBuffer;
3431 PAUDIO_OUTPUT audioOutput;
3432 ULONG bytesTransferred;
3433
3434 audioOutput = ScsiClassFindModePage((PCHAR)audioControl,
3435 srb->DataTransferLength,
3436 CDROM_AUDIO_CONTROL_PAGE,
3437 use6Byte);
3438 //
3439 // Verify the page is as big as expected.
3440 //
3441
3442 bytesTransferred = (PCHAR) audioOutput - (PCHAR) audioControl +
3443 sizeof(AUDIO_OUTPUT);
3444
3445 if (audioOutput != NULL &&
3446 srb->DataTransferLength >= bytesTransferred) {
3447
3448 audioControl->LbaFormat = audioOutput->LbaFormat;
3449
3450 audioControl->LogicalBlocksPerSecond =
3451 (audioOutput->LogicalBlocksPerSecond[0] << (UCHAR)8) |
3452 audioOutput->LogicalBlocksPerSecond[1];
3453
3454 realIrp->IoStatus.Information = sizeof(CDROM_AUDIO_CONTROL);
3455
3456 } else {
3457 realIrp->IoStatus.Information = 0;
3458 status = STATUS_INVALID_DEVICE_REQUEST;
3459 }
3460 break;
3461 }
3462
3463 case IOCTL_CDROM_GET_VOLUME: {
3464
3465 PAUDIO_OUTPUT audioOutput;
3466 PVOLUME_CONTROL volumeControl = srb->DataBuffer;
3467 ULONG i,bytesTransferred;
3468
3469 audioOutput = ScsiClassFindModePage((PCHAR)volumeControl,
3470 srb->DataTransferLength,
3471 CDROM_AUDIO_CONTROL_PAGE,
3472 use6Byte);
3473
3474 //
3475 // Verify the page is as big as expected.
3476 //
3477
3478 bytesTransferred = (PCHAR) audioOutput - (PCHAR) volumeControl +
3479 sizeof(AUDIO_OUTPUT);
3480
3481 if (audioOutput != NULL &&
3482 srb->DataTransferLength >= bytesTransferred) {
3483
3484 for (i=0; i<4; i++) {
3485 volumeControl->PortVolume[i] =
3486 audioOutput->PortOutput[i].Volume;
3487 }
3488
3489 //
3490 // Set bytes transferred in IRP.
3491 //
3492
3493 realIrp->IoStatus.Information = sizeof(VOLUME_CONTROL);
3494
3495 } else {
3496 realIrp->IoStatus.Information = 0;
3497 status = STATUS_INVALID_DEVICE_REQUEST;
3498 }
3499
3500 break;
3501 }
3502
3503 case IOCTL_CDROM_SET_VOLUME:
3504
3505 realIrp->IoStatus.Information = sizeof(VOLUME_CONTROL);
3506 break;
3507
3508 default:
3509
3510 ASSERT(FALSE);
3511 realIrp->IoStatus.Information = 0;
3512 status = STATUS_INVALID_DEVICE_REQUEST;
3513
3514 } // end switch()
3515 }
3516
3517 //
3518 // Deallocate srb and sense buffer.
3519 //
3520
3521 if (srb) {
3522 if (srb->DataBuffer) {
3523 ExFreePool(srb->DataBuffer);
3524 }
3525 if (srb->SenseInfoBuffer) {
3526 ExFreePool(srb->SenseInfoBuffer);
3527 }
3528 ExFreePool(srb);
3529 }
3530
3531 if (realIrp->PendingReturned) {
3532 IoMarkIrpPending(realIrp);
3533 }
3534
3535 if (Irp->MdlAddress) {
3536 IoFreeMdl(Irp->MdlAddress);
3537 }
3538
3539 IoFreeIrp(Irp);
3540
3541 //
3542 // Set status in completing IRP.
3543 //
3544
3545 realIrp->IoStatus.Status = status;
3546
3547 //
3548 // Set the hard error if necessary.
3549 //
3550
3551 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
3552
3553 //
3554 // Store DeviceObject for filesystem, and clear
3555 // in IoStatus.Information field.
3556 //
3557
3558 DebugPrint((1, "CdRomDeviceCompletion - Setting Hard Error on realIrp %lx\n",
3559 realIrp));
3560 IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
3561 realIrp->IoStatus.Information = 0;
3562 }
3563
3564 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
3565
3566 IoStartNextPacket(DeviceObject, FALSE);
3567
3568 return STATUS_MORE_PROCESSING_REQUIRED;
3569 }
3570
3571 NTSTATUS
3572 NTAPI
3573 CdRomSetVolumeIntermediateCompletion(
3574 IN PDEVICE_OBJECT DeviceObject,
3575 IN PIRP Irp,
3576 IN PVOID Context
3577 )
3578 {
3579 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3580 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
3581 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension + 1);
3582 BOOLEAN use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
3583 PIO_STACK_LOCATION realIrpStack;
3584 PIO_STACK_LOCATION realIrpNextStack;
3585 PSCSI_REQUEST_BLOCK srb = Context;
3586 PIRP realIrp = NULL;
3587 NTSTATUS status;
3588 BOOLEAN retry;
3589
3590 //
3591 // Extract the 'real' irp from the irpstack.
3592 //
3593
3594 realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
3595 realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
3596 realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
3597
3598 //
3599 // Check SRB status for success of completing request.
3600 //
3601
3602 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
3603
3604 DebugPrint((2,
3605 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3606 Irp,
3607 srb,
3608 realIrp));
3609
3610 //
3611 // Release the queue if it is frozen.
3612 //
3613
3614 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
3615 ScsiClassReleaseQueue(DeviceObject);
3616 }
3617
3618
3619 retry = ScsiClassInterpretSenseInfo(DeviceObject,
3620 srb,
3621 irpStack->MajorFunction,
3622 irpStack->Parameters.DeviceIoControl.IoControlCode,
3623 MAXIMUM_RETRIES - ((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
3624 &status);
3625
3626 if (status == STATUS_DATA_OVERRUN) {
3627 status = STATUS_SUCCESS;
3628 retry = FALSE;
3629 }
3630
3631 //
3632 // If the status is verified required and the this request
3633 // should bypass verify required then retry the request.
3634 //
3635
3636 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
3637 status == STATUS_VERIFY_REQUIRED) {
3638
3639 status = STATUS_IO_DEVICE_ERROR;
3640 retry = TRUE;
3641 }
3642
3643 if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1-1))) {
3644
3645 if (((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
3646
3647 //
3648 // Retry request.
3649 //
3650
3651 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp));
3652
3653
3654 ExFreePool(srb->SenseInfoBuffer);
3655 ExFreePool(srb->DataBuffer);
3656 ExFreePool(srb);
3657 if (Irp->MdlAddress) {
3658 IoFreeMdl(Irp->MdlAddress);
3659 }
3660
3661 IoFreeIrp(Irp);
3662
3663 //
3664 // Call StartIo directly since IoStartNextPacket hasn't been called,
3665 // the serialisation is still intact.
3666 //
3667 ScsiCdRomStartIo(DeviceObject, realIrp);
3668 return STATUS_MORE_PROCESSING_REQUIRED;
3669
3670 }
3671
3672 //
3673 // Exhausted retries. Fall through and complete the request with the appropriate status.
3674 //
3675
3676 }
3677 } else {
3678
3679 //
3680 // Set status for successful request.
3681 //
3682
3683 status = STATUS_SUCCESS;
3684 }
3685
3686 if (NT_SUCCESS(status)) {
3687
3688 PAUDIO_OUTPUT audioInput = NULL;
3689 PAUDIO_OUTPUT audioOutput;
3690 PVOLUME_CONTROL volumeControl = realIrp->AssociatedIrp.SystemBuffer;
3691 ULONG i,bytesTransferred,headerLength;
3692 PVOID dataBuffer;
3693 PCDB cdb;
3694
3695 audioInput = ScsiClassFindModePage((PCHAR)srb->DataBuffer,
3696 srb->DataTransferLength,
3697 CDROM_AUDIO_CONTROL_PAGE,
3698 use6Byte);
3699
3700 //
3701 // Check to make sure the mode sense data is valid before we go on
3702 //
3703
3704 if(audioInput == NULL) {
3705
3706 DebugPrint((1, "Mode Sense Page %d not found\n",
3707 CDROM_AUDIO_CONTROL_PAGE));
3708
3709 realIrp->IoStatus.Information = 0;
3710 realIrp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
3711 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
3712 ExFreePool(srb->SenseInfoBuffer);
3713 ExFreePool(srb);
3714 IoFreeMdl(Irp->MdlAddress);
3715 IoFreeIrp(Irp);
3716 return STATUS_MORE_PROCESSING_REQUIRED;
3717 }
3718
3719 if (use6Byte) {
3720 headerLength = sizeof(MODE_PARAMETER_HEADER);
3721 } else {
3722 headerLength = sizeof(MODE_PARAMETER_HEADER10);
3723 }
3724
3725 bytesTransferred = sizeof(AUDIO_OUTPUT) + headerLength;
3726
3727 //
3728 // Allocate a new buffer for the mode select.
3729 //
3730
3731 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, bytesTransferred);
3732
3733 if (!dataBuffer) {
3734 realIrp->IoStatus.Information = 0;
3735 realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3736 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
3737 ExFreePool(srb->SenseInfoBuffer);
3738 ExFreePool(srb);
3739 IoFreeMdl(Irp->MdlAddress);
3740 IoFreeIrp(Irp);
3741 return STATUS_MORE_PROCESSING_REQUIRED;
3742 }
3743
3744 RtlZeroMemory(dataBuffer, bytesTransferred);
3745
3746 //
3747 // Rebuild the data buffer to include the user requested values.
3748 //
3749
3750 audioOutput = (PAUDIO_OUTPUT) ((PCHAR) dataBuffer + headerLength);
3751
3752 for (i=0; i<4; i++) {
3753 audioOutput->PortOutput[i].Volume =
3754 volumeControl->PortVolume[i];
3755 audioOutput->PortOutput[i].ChannelSelection =
3756 audioInput->PortOutput[i].ChannelSelection;
3757 }
3758
3759 audioOutput->CodePage = CDROM_AUDIO_CONTROL_PAGE;
3760 audioOutput->ParameterLength = sizeof(AUDIO_OUTPUT) - 2;
3761 audioOutput->Immediate = MODE_SELECT_IMMEDIATE;
3762
3763 //
3764 // Free the old data buffer, mdl.
3765 //
3766
3767 ExFreePool(srb->DataBuffer);
3768 IoFreeMdl(Irp->MdlAddress);
3769
3770 //
3771 // rebuild the srb.
3772 //
3773
3774 cdb = (PCDB)srb->Cdb;
3775 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
3776
3777 srb->SrbStatus = srb->ScsiStatus = 0;
3778 srb->SrbFlags = deviceExtension->SrbFlags;
3779 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
3780 srb->DataTransferLength = bytesTransferred;
3781
3782 if (use6Byte) {
3783
3784 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
3785 cdb->MODE_SELECT.ParameterListLength = (UCHAR) bytesTransferred;
3786 cdb->MODE_SELECT.PFBit = 1;
3787 srb->CdbLength = 6;
3788 } else {
3789
3790 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
3791 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR) (bytesTransferred >> 8);
3792 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR) (bytesTransferred & 0xFF);
3793 cdb->MODE_SELECT10.PFBit = 1;
3794 srb->CdbLength = 10;
3795 }
3796
3797 //
3798 // Prepare the MDL
3799 //
3800
3801 Irp->MdlAddress = IoAllocateMdl(dataBuffer,
3802 bytesTransferred,
3803 FALSE,
3804 FALSE,
3805 (PIRP) NULL);
3806
3807 if (!Irp->MdlAddress) {
3808 realIrp->IoStatus.Information = 0;
3809 realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3810 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
3811 ExFreePool(srb->SenseInfoBuffer);
3812 ExFreePool(srb);
3813 ExFreePool(dataBuffer);
3814 IoFreeIrp(Irp);
3815 return STATUS_MORE_PROCESSING_REQUIRED;
3816
3817 }
3818
3819 MmBuildMdlForNonPagedPool(Irp->MdlAddress);
3820 srb->DataBuffer = dataBuffer;
3821
3822 irpStack = IoGetNextIrpStackLocation(Irp);
3823 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
3824 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
3825 irpStack->Parameters.Scsi.Srb = srb;
3826
3827 //
3828 // reset the irp completion.
3829 //
3830
3831 IoSetCompletionRoutine(Irp,
3832 CdRomDeviceControlCompletion,
3833 srb,
3834 TRUE,
3835 TRUE,
3836 TRUE);
3837 //
3838 // Call the port driver.
3839 //
3840
3841 IoCallDriver(deviceExtension->PortDeviceObject, Irp);
3842
3843 return STATUS_MORE_PROCESSING_REQUIRED;
3844 }
3845
3846 //
3847 // Deallocate srb and sense buffer.
3848 //
3849
3850 if (srb) {
3851 if (srb->DataBuffer) {
3852 ExFreePool(srb->DataBuffer);
3853 }
3854 if (srb->SenseInfoBuffer) {
3855 ExFreePool(srb->SenseInfoBuffer);
3856 }
3857 ExFreePool(srb);
3858 }
3859
3860 if (Irp->PendingReturned) {
3861 IoMarkIrpPending(Irp);
3862 }
3863
3864 if (realIrp->PendingReturned) {
3865 IoMarkIrpPending(realIrp);
3866 }
3867
3868 if (Irp->MdlAddress) {
3869 IoFreeMdl(Irp->MdlAddress);
3870 }
3871
3872 IoFreeIrp(Irp);
3873
3874 //
3875 // Set status in completing IRP.
3876 //
3877
3878 realIrp->IoStatus.Status = status;
3879
3880 //
3881 // Set the hard error if necessary.
3882 //
3883
3884 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
3885
3886 //
3887 // Store DeviceObject for filesystem, and clear
3888 // in IoStatus.Information field.
3889 //
3890
3891 IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
3892 realIrp->IoStatus.Information = 0;
3893 }
3894
3895 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
3896
3897 IoStartNextPacket(DeviceObject, FALSE);
3898
3899 return STATUS_MORE_PROCESSING_REQUIRED;
3900 }
3901
3902
3903 NTSTATUS
3904 NTAPI
3905 CdRomSwitchModeCompletion(
3906 IN PDEVICE_OBJECT DeviceObject,
3907 IN PIRP Irp,
3908 IN PVOID Context
3909 )
3910 {
3911 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3912 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
3913 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension + 1);
3914 PIO_STACK_LOCATION realIrpStack;
3915 PIO_STACK_LOCATION realIrpNextStack;
3916 PSCSI_REQUEST_BLOCK srb = Context;
3917 PIRP realIrp = NULL;
3918 NTSTATUS status;
3919 BOOLEAN retry;
3920
3921 //
3922 // Extract the 'real' irp from the irpstack.
3923 //
3924
3925 realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
3926 realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
3927 realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
3928
3929 //
3930 // Check SRB status for success of completing request.
3931 //
3932
3933 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
3934
3935 DebugPrint((2,
3936 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3937 Irp,
3938 srb,
3939 realIrp));
3940
3941 //
3942 // Release the queue if it is frozen.
3943 //
3944
3945 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
3946 ScsiClassReleaseQueue(DeviceObject);
3947 }
3948
3949
3950 retry = ScsiClassInterpretSenseInfo(DeviceObject,
3951 srb,
3952 irpStack->MajorFunction,
3953 irpStack->Parameters.DeviceIoControl.IoControlCode,
3954 MAXIMUM_RETRIES - ((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
3955 &status);
3956
3957 //
3958 // If the status is verified required and the this request
3959 // should bypass verify required then retry the request.
3960 //
3961
3962 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
3963 status == STATUS_VERIFY_REQUIRED) {
3964
3965 status = STATUS_IO_DEVICE_ERROR;
3966 retry = TRUE;
3967 }
3968
3969 if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1-1))) {
3970
3971 if (((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
3972
3973 //
3974 // Retry request.
3975 //
3976
3977 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp));
3978
3979
3980 ExFreePool(srb->SenseInfoBuffer);
3981 ExFreePool(srb->DataBuffer);
3982 ExFreePool(srb);
3983 if (Irp->MdlAddress) {
3984 IoFreeMdl(Irp->MdlAddress);
3985 }
3986
3987 IoFreeIrp(Irp);
3988
3989 //
3990 // Call StartIo directly since IoStartNextPacket hasn't been called,
3991 // the serialisation is still intact.
3992 //
3993
3994 ScsiCdRomStartIo(DeviceObject, realIrp);
3995 return STATUS_MORE_PROCESSING_REQUIRED;
3996
3997 }
3998
3999 //
4000 // Exhausted retries. Fall through and complete the request with the appropriate status.
4001 //
4002 }
4003 } else {
4004
4005 //
4006 // Set status for successful request.
4007 //
4008
4009 status = STATUS_SUCCESS;
4010 }
4011
4012 if (NT_SUCCESS(status)) {
4013
4014 ULONG sectorSize, startingSector, transferByteCount;
4015 PCDB cdb;
4016
4017 //
4018 // Update device ext. to show which mode we are currently using.
4019 //
4020
4021 sectorSize = cdData->u1.BlockDescriptor.BlockLength[0] << 16;
4022 sectorSize |= (cdData->u1.BlockDescriptor.BlockLength[1] << 8);
4023 sectorSize |= (cdData->u1.BlockDescriptor.BlockLength[2]);
4024
4025 cdData->RawAccess = (sectorSize == RAW_SECTOR_SIZE) ? TRUE : FALSE;
4026
4027 //
4028 // Free the old data buffer, mdl.
4029 //
4030
4031 ExFreePool(srb->DataBuffer);
4032 IoFreeMdl(Irp->MdlAddress);
4033 IoFreeIrp(Irp);
4034
4035 //
4036 // rebuild the srb.
4037 //
4038
4039 cdb = (PCDB)srb->Cdb;
4040 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
4041
4042
4043 if (cdData->RawAccess) {
4044
4045 PRAW_READ_INFO rawReadInfo =
4046 (PRAW_READ_INFO)realIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
4047
4048 ULONG maximumTransferLength;
4049 ULONG transferPages;
4050
4051 //
4052 // Calculate starting offset.
4053 //
4054
4055 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
4056 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
4057 maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
4058 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp->MdlAddress),
4059 transferByteCount);
4060
4061 //
4062 // Determine if request is within limits imposed by miniport.
4063 // If the request is larger than the miniport's capabilities, split it.
4064 //
4065
4066 if (transferByteCount > maximumTransferLength ||
4067 transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
4068
4069 realIrp->IoStatus.Information = 0;
4070 realIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
4071 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
4072
4073 ExFreePool(srb->SenseInfoBuffer);
4074 ExFreePool(srb);
4075
4076 IoStartNextPacket(DeviceObject, FALSE);
4077
4078 return STATUS_MORE_PROCESSING_REQUIRED;
4079 }
4080
4081 srb->OriginalRequest = realIrp;
4082 srb->SrbFlags = deviceExtension->SrbFlags;
4083 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
4084 srb->DataTransferLength = transferByteCount;
4085 srb->TimeOutValue = deviceExtension->TimeOutValue;
4086 srb->CdbLength = 10;
4087 srb->DataBuffer = MmGetMdlVirtualAddress(realIrp->MdlAddress);
4088
4089 if (rawReadInfo->TrackMode == CDDA) {
4090 if (cdData->XAFlags & PLEXTOR_CDDA) {
4091
4092 srb->CdbLength = 12;
4093
4094 cdb->PLXTR_READ_CDDA.LogicalUnitNumber = deviceExtension->Lun;
4095 cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
4096 cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
4097 cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
4098 cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
4099
4100 cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
4101 cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
4102 cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
4103 cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
4104
4105 cdb->PLXTR_READ_CDDA.SubCode = 0;
4106 cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
4107
4108 } else if (cdData->XAFlags & NEC_CDDA) {
4109
4110 cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
4111 cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
4112 cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
4113 cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
4114
4115 cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
4116 cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
4117
4118 cdb->NEC_READ_CDDA.OperationCode = 0xD4;
4119 }
4120 } else {
4121 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
4122
4123 cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8);
4124 cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
4125
4126 cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
4127 cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
4128 cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
4129 cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
4130
4131 cdb->CDB10.OperationCode = SCSIOP_READ;
4132 }
4133
4134 srb->SrbStatus = srb->ScsiStatus = 0;
4135
4136
4137 irpStack = IoGetNextIrpStackLocation(realIrp);
4138 irpStack->MajorFunction = IRP_MJ_SCSI;
4139 irpStack->Parameters.Scsi.Srb = srb;
4140
4141 if (!(irpStack->Parameters.Others.Argument1)) {
4142
4143 //
4144 // Only jam this in if it doesn't exist. The completion routines can
4145 // call StartIo directly in the case of retries and resetting it will
4146 // cause infinite loops.
4147 //
4148
4149 irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
4150 }
4151
4152 //
4153 // Set up IoCompletion routine address.
4154 //
4155
4156 IoSetCompletionRoutine(realIrp,
4157 CdRomXACompletion,
4158 srb,
4159 TRUE,
4160 TRUE,
4161 TRUE);
4162 } else {
4163
4164 ULONG maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
4165 ULONG transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp->MdlAddress),
4166 realIrpStack->Parameters.Read.Length);
4167 //
4168 // Back to cooked sectors. Build and send a normal read.
4169 // The real work for setting offsets and checking for splitrequests was
4170 // done in startio
4171 //
4172
4173 if ((realIrpStack->Parameters.Read.Length > maximumTransferLength) ||
4174 (transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages)) {
4175
4176 //
4177 // Request needs to be split. Completion of each portion of the request will
4178 // fire off the next portion. The final request will signal Io to send a new request.
4179 //
4180
4181 ScsiClassSplitRequest(DeviceObject, realIrp, maximumTransferLength);
4182 return STATUS_MORE_PROCESSING_REQUIRED;
4183
4184 } else {
4185
4186 //
4187 // Build SRB and CDB for this IRP.
4188 //
4189
4190 ScsiClassBuildRequest(DeviceObject, realIrp);
4191
4192 }
4193 }
4194
4195 //
4196 // Call the port driver.
4197 //
4198
4199 IoCallDriver(deviceExtension->PortDeviceObject, realIrp);
4200
4201 return STATUS_MORE_PROCESSING_REQUIRED;
4202 }
4203
4204 //
4205 // Update device Extension flags to indicate that XA isn't supported.
4206 //
4207
4208 cdData->XAFlags |= XA_NOT_SUPPORTED;
4209
4210 //
4211 // Deallocate srb and sense buffer.
4212 //
4213
4214 if (srb) {
4215 if (srb->DataBuffer) {
4216 ExFreePool(srb->DataBuffer);
4217 }
4218 if (srb->SenseInfoBuffer) {
4219 ExFreePool(srb->SenseInfoBuffer);
4220 }
4221 ExFreePool(srb);
4222 }
4223
4224 if (Irp->PendingReturned) {
4225 IoMarkIrpPending(Irp);
4226 }
4227
4228 if (realIrp->PendingReturned) {
4229 IoMarkIrpPending(realIrp);
4230 }
4231
4232 if (Irp->MdlAddress) {
4233 IoFreeMdl(Irp->MdlAddress);
4234 }
4235
4236 IoFreeIrp(Irp);
4237
4238 //
4239 // Set status in completing IRP.
4240 //
4241
4242 realIrp->IoStatus.Status = status;
4243
4244 //
4245 // Set the hard error if necessary.
4246 //
4247
4248 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
4249
4250 //
4251 // Store DeviceObject for filesystem, and clear
4252 // in IoStatus.Information field.
4253 //
4254
4255 IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
4256 realIrp->IoStatus.Information = 0;
4257 }
4258
4259 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
4260
4261 IoStartNextPacket(DeviceObject, FALSE);
4262
4263 return STATUS_MORE_PROCESSING_REQUIRED;
4264 }
4265
4266 NTSTATUS
4267 NTAPI
4268 CdRomXACompletion(
4269 IN PDEVICE_OBJECT DeviceObject,
4270 IN PIRP Irp,
4271 IN PVOID Context
4272 )
4273
4274 /*++
4275
4276 Routine Description:
4277
4278 This routine executes when the port driver has completed a request.
4279 It looks at the SRB status in the completing SRB and if not success
4280 it checks for valid request sense buffer information. If valid, the
4281 info is used to update status with more precise message of type of
4282 error. This routine deallocates the SRB.
4283
4284 Arguments:
4285
4286 DeviceObject - Supplies the device object which represents the logical
4287 unit.
4288
4289 Irp - Supplies the Irp which has completed.
4290
4291 Context - Supplies a pointer to the SRB.
4292
4293 Return Value:
4294
4295 NT status
4296
4297 --*/
4298
4299 {
4300 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
4301 PIO_STACK_LOCATION irpNextStack = IoGetNextIrpStackLocation(Irp);
4302 PSCSI_REQUEST_BLOCK srb = Context;
4303 NTSTATUS status;
4304 BOOLEAN retry;
4305
4306 //
4307 // Check SRB status for success of completing request.
4308 //
4309
4310 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
4311
4312 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp, srb));
4313
4314 //
4315 // Release the queue if it is frozen.
4316 //
4317
4318 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
4319 ScsiClassReleaseQueue(DeviceObject);
4320 }
4321
4322 retry = ScsiClassInterpretSenseInfo(
4323 DeviceObject,
4324 srb,
4325 irpStack->MajorFunction,
4326 irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
4327 MAXIMUM_RETRIES - ((ULONG_PTR)irpNextStack->Parameters.Others.Argument1),
4328 &status);
4329
4330 //
4331 // If the status is verified required and the this request
4332 // should bypass verify required then retry the request.
4333 //
4334
4335 if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
4336 status == STATUS_VERIFY_REQUIRED) {
4337
4338 status = STATUS_IO_DEVICE_ERROR;
4339 retry = TRUE;
4340 }
4341
4342 if (retry && (irpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)irpNextStack->Parameters.Others.Argument1-1))) {
4343
4344 if (((ULONG_PTR)irpNextStack->Parameters.Others.Argument1)) {
4345
4346 //
4347 // Retry request.
4348 //
4349
4350 DebugPrint((1, "CdRomXACompletion: Retry request %lx - Calling StartIo\n", Irp));
4351
4352
4353 ExFreePool(srb->SenseInfoBuffer);
4354 ExFreePool(srb->DataBuffer);
4355 ExFreePool(srb);
4356
4357 //
4358 // Call StartIo directly since IoStartNextPacket hasn't been called,
4359 // the serialisation is still intact.
4360 //
4361
4362 ScsiCdRomStartIo(DeviceObject, Irp);
4363 return STATUS_MORE_PROCESSING_REQUIRED;
4364
4365 }
4366
4367 //
4368 // Exhausted retries. Fall through and complete the request with the appropriate status.
4369 //
4370 }
4371 } else {
4372
4373 //
4374 // Set status for successful request.
4375 //
4376
4377 status = STATUS_SUCCESS;
4378
4379 } // end if (SRB_STATUS(srb->SrbStatus) ...
4380
4381 //
4382 // Return SRB to nonpaged pool.
4383 //
4384
4385 ExFreePool(srb);
4386
4387 //
4388 // Set status in completing IRP.
4389 //
4390
4391 Irp->IoStatus.Status = status;
4392
4393 //
4394 // Set the hard error if necessary.
4395 //
4396
4397 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
4398
4399 //
4400 // Store DeviceObject for filesystem, and clear
4401 // in IoStatus.Information field.
4402 //
4403
4404 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
4405 Irp->IoStatus.Information = 0;
4406 }
4407
4408 //
4409 // If pending has be returned for this irp then mark the current stack as
4410 // pending.
4411 //
4412
4413 if (Irp->PendingReturned) {
4414 IoMarkIrpPending(Irp);
4415 }
4416
4417 //IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4418 IoStartNextPacket(DeviceObject, FALSE);
4419
4420 return status;
4421 }
4422
4423 NTSTATUS
4424 NTAPI
4425 CdRomDeviceControl(
4426 IN PDEVICE_OBJECT DeviceObject,
4427 IN PIRP Irp
4428 )
4429
4430 /*++
4431
4432 Routine Description:
4433
4434 This is the NT device control handler for CDROMs.
4435
4436 Arguments:
4437
4438 DeviceObject - for this CDROM
4439
4440 Irp - IO Request packet
4441
4442 Return Value:
4443
4444 NTSTATUS
4445
4446 --*/
4447
4448 {
4449 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
4450 PIO_STACK_LOCATION nextStack;
4451 PKEVENT deviceControlEvent;
4452 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4453 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension+1);
4454 SCSI_REQUEST_BLOCK srb;
4455 NTSTATUS status;
4456 KIRQL irql;
4457
4458 ULONG ioctlCode;
4459 ULONG baseCode;
4460 ULONG functionCode;
4461
4462 RetryControl:
4463
4464 //
4465 // Zero the SRB on stack.
4466 //
4467
4468 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
4469
4470 Irp->IoStatus.Information = 0;
4471
4472 //
4473 // if this is a class driver ioctl then we need to change the base code
4474 // to IOCTL_CDROM_BASE so that the switch statement can handle it.
4475 //
4476 // WARNING - currently the scsi class ioctl function codes are between
4477 // 0x200 & 0x300. this routine depends on that fact
4478 //
4479
4480 ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
4481 baseCode = ioctlCode >> 16;
4482 functionCode = (ioctlCode & (~0xffffc003)) >> 2;
4483
4484 DebugPrint((1, "CdRomDeviceControl: Ioctl Code = %#08lx, Base Code = %#lx,"
4485 " Function Code = %#lx\n",
4486 ioctlCode,
4487 baseCode,
4488 functionCode
4489 ));
4490
4491 if((functionCode >= 0x200) && (functionCode <= 0x300)) {
4492
4493 ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE, 0, 0, 0);
4494
4495 DebugPrint((1, "CdRomDeviceControl: Class Code - new ioctl code is %#08lx\n",
4496 ioctlCode));
4497
4498 irpStack->Parameters.DeviceIoControl.IoControlCode = ioctlCode;
4499
4500 }
4501
4502 switch (ioctlCode) {
4503
4504 case IOCTL_CDROM_RAW_READ: {
4505
4506 LARGE_INTEGER startingOffset;
4507 ULONG transferBytes;
4508 PRAW_READ_INFO rawReadInfo = (PRAW_READ_INFO)irpStack->Parameters.DeviceIoControl.Type3InputBuffer;
4509 PUCHAR userData = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
4510
4511 //
4512 // Ensure that XA reads are supported.
4513 //
4514
4515 if (cdData->XAFlags & XA_NOT_SUPPORTED) {
4516
4517 DebugPrint((1,
4518 "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
4519 cdData->XAFlags));
4520
4521 status = STATUS_INVALID_DEVICE_REQUEST;
4522 break;
4523 }
4524
4525 //
4526 // Check that ending sector is on disc and buffers are there and of
4527 // correct size.
4528 //
4529
4530 if (rawReadInfo == NULL) {
4531
4532 //
4533 // Called from user space. Validate the buffers.
4534 //
4535
4536 rawReadInfo = (PRAW_READ_INFO)userData;
4537 irpStack->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID)userData;
4538
4539 if (rawReadInfo == NULL) {
4540
4541 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (No extent info\n"));
4542
4543 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
4544
4545 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4546 return STATUS_INVALID_PARAMETER;
4547 }
4548
4549 if (irpStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(RAW_READ_INFO)) {
4550
4551 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Invalid info buffer\n"));
4552
4553 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
4554
4555 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4556 return STATUS_INVALID_PARAMETER;
4557 }
4558 }
4559
4560 startingOffset.QuadPart = rawReadInfo->DiskOffset.QuadPart;
4561 transferBytes = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
4562
4563 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < transferBytes) {
4564
4565 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Bad buffer size)\n"));
4566
4567 //
4568 // Fail request with status of invalid parameters.
4569 //
4570
4571 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
4572
4573 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4574 return STATUS_INVALID_PARAMETER;
4575 }
4576
4577 if ((startingOffset.QuadPart + transferBytes) > deviceExtension->PartitionLength.QuadPart) {
4578
4579 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Request Out of Bounds)\n"));
4580
4581 //
4582 // Fail request with status of invalid parameters.
4583 //
4584
4585 status = STATUS_INVALID_PARAMETER;
4586 break;
4587 }
4588
4589 IoMarkIrpPending(Irp);
4590 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4591
4592 return STATUS_PENDING;
4593 }
4594
4595 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
4596
4597 DebugPrint((2,"CdRomDeviceControl: Get drive geometry\n"));
4598
4599 if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4600 sizeof( DISK_GEOMETRY ) ) {
4601
4602 status = STATUS_INFO_LENGTH_MISMATCH;
4603 break;
4604 }
4605
4606 IoMarkIrpPending(Irp);
4607 IoStartPacket(DeviceObject,Irp, NULL,NULL);
4608
4609 return STATUS_PENDING;
4610 }
4611
4612 case IOCTL_CDROM_GET_LAST_SESSION:
4613 case IOCTL_CDROM_READ_TOC: {
4614
4615 //
4616 // If the cd is playing music then reject this request.
4617 //
4618
4619 if (CdRomIsPlayActive(DeviceObject)) {
4620 Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
4621 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4622 return STATUS_DEVICE_BUSY;
4623 }
4624
4625 IoMarkIrpPending(Irp);
4626 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4627
4628 return STATUS_PENDING;
4629 }
4630
4631 case IOCTL_CDROM_PLAY_AUDIO_MSF: {
4632
4633 //
4634 // Play Audio MSF
4635 //
4636
4637 DebugPrint((2,"CdRomDeviceControl: Play audio MSF\n"));
4638
4639 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
4640 sizeof(CDROM_PLAY_AUDIO_MSF)) {
4641
4642 //
4643 // Indicate unsuccessful status.
4644 //
4645
4646 status = STATUS_BUFFER_TOO_SMALL;
4647 break;
4648 }
4649
4650 IoMarkIrpPending(Irp);
4651 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4652
4653 return STATUS_PENDING;
4654 }
4655
4656 case IOCTL_CDROM_SEEK_AUDIO_MSF: {
4657
4658
4659 //
4660 // Seek Audio MSF
4661 //
4662
4663 DebugPrint((2,"CdRomDeviceControl: Seek audio MSF\n"));
4664
4665 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
4666 sizeof(CDROM_SEEK_AUDIO_MSF)) {
4667
4668 //
4669 // Indicate unsuccessful status.
4670 //
4671
4672 status = STATUS_BUFFER_TOO_SMALL;
4673 break;
4674 } else {
4675 IoMarkIrpPending(Irp);
4676 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4677
4678 return STATUS_PENDING;
4679
4680 }
4681 }
4682
4683 case IOCTL_CDROM_PAUSE_AUDIO: {
4684
4685 //
4686 // Pause audio
4687 //
4688
4689 DebugPrint((2, "CdRomDeviceControl: Pause audio\n"));
4690
4691 IoMarkIrpPending(Irp);
4692 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4693
4694 return STATUS_PENDING;
4695
4696 break;
4697 }
4698
4699 case IOCTL_CDROM_RESUME_AUDIO: {
4700
4701 //
4702 // Resume audio
4703 //
4704
4705 DebugPrint((2, "CdRomDeviceControl: Resume audio\n"));
4706
4707 IoMarkIrpPending(Irp);
4708 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4709
4710 return STATUS_PENDING;
4711 }
4712
4713 case IOCTL_CDROM_READ_Q_CHANNEL: {
4714
4715 if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
4716 sizeof(CDROM_SUB_Q_DATA_FORMAT)) {
4717
4718 status = STATUS_BUFFER_TOO_SMALL;
4719 Irp->IoStatus.Information = 0;
4720 break;
4721 }
4722
4723 IoMarkIrpPending(Irp);
4724 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4725
4726 return STATUS_PENDING;
4727 }
4728
4729 case IOCTL_CDROM_GET_CONTROL: {
4730
4731 DebugPrint((2, "CdRomDeviceControl: Get audio control\n"));
4732
4733 //
4734 // Verify user buffer is large enough for the data.
4735 //
4736
4737 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4738 sizeof(CDROM_AUDIO_CONTROL)) {
4739
4740 //
4741 // Indicate unsuccessful status and no data transferred.
4742 //
4743
4744 status = STATUS_BUFFER_TOO_SMALL;
4745 Irp->IoStatus.Information = 0;
4746 break;
4747
4748 } else {
4749
4750 IoMarkIrpPending(Irp);
4751 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4752
4753 return STATUS_PENDING;
4754 }
4755 }
4756
4757 case IOCTL_CDROM_GET_VOLUME: {
4758
4759 DebugPrint((2, "CdRomDeviceControl: Get volume control\n"));
4760
4761 //
4762 // Verify user buffer is large enough for data.
4763 //
4764
4765 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4766 sizeof(VOLUME_CONTROL)) {
4767
4768 //
4769 // Indicate unsuccessful status and no data transferred.
4770 //
4771
4772 status = STATUS_BUFFER_TOO_SMALL;
4773 Irp->IoStatus.Information = 0;
4774 break;
4775
4776 } else {
4777 IoMarkIrpPending(Irp);
4778 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4779
4780 return STATUS_PENDING;
4781 }
4782 }
4783
4784 case IOCTL_CDROM_SET_VOLUME: {
4785
4786 DebugPrint((2, "CdRomDeviceControl: Set volume control\n"));
4787
4788 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
4789 sizeof(VOLUME_CONTROL)) {
4790
4791 //
4792 // Indicate unsuccessful status.
4793 //
4794
4795 status = STATUS_BUFFER_TOO_SMALL;
4796 break;
4797 } else {
4798
4799 IoMarkIrpPending(Irp);
4800 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4801
4802 return STATUS_PENDING;
4803 }
4804 }
4805
4806 case IOCTL_CDROM_STOP_AUDIO: {
4807
4808 //
4809 // Stop play.
4810 //
4811
4812 DebugPrint((2, "CdRomDeviceControl: Stop audio\n"));
4813
4814 IoMarkIrpPending(Irp);
4815 IoStartPacket(DeviceObject,Irp, NULL,NULL);
4816
4817 return STATUS_PENDING;
4818 }
4819
4820 case IOCTL_CDROM_CHECK_VERIFY: {
4821 DebugPrint((1, "CdRomDeviceControl: [%lx] Check Verify\n", Irp));
4822 IoMarkIrpPending(Irp);
4823
4824 if((irpStack->Parameters.DeviceIoControl.OutputBufferLength) &&
4825 (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))) {
4826
4827 DebugPrint((1, "CdRomDeviceControl: Check Verify: media count "
4828 "buffer too small\n"));
4829
4830 status = STATUS_BUFFER_TOO_SMALL;
4831 break;
4832 }
4833
4834 IoStartPacket(DeviceObject,Irp, NULL,NULL);
4835
4836 return STATUS_PENDING;
4837 }
4838
4839 default: {
4840
4841 //
4842 // allocate an event and stuff it into our stack location.
4843 //
4844
4845 deviceControlEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
4846
4847 if(!deviceControlEvent) {
4848
4849 status = STATUS_INSUFFICIENT_RESOURCES;
4850
4851 } else {
4852
4853 PIO_STACK_LOCATION currentStack;
4854
4855 KeInitializeEvent(deviceControlEvent, NotificationEvent, FALSE);
4856
4857 currentStack = IoGetCurrentIrpStackLocation(Irp);
4858 nextStack = IoGetNextIrpStackLocation(Irp);
4859
4860 //
4861 // Copy the stack down a notch
4862 //
4863
4864 *nextStack = *currentStack;
4865
4866 IoSetCompletionRoutine(
4867 Irp,
4868 CdRomClassIoctlCompletion,
4869 deviceControlEvent,
4870 TRUE,
4871 TRUE,
4872 TRUE
4873 );
4874
4875 IoSetNextIrpStackLocation(Irp);
4876
4877 Irp->IoStatus.Status = STATUS_SUCCESS;
4878 Irp->IoStatus.Information = 0;
4879
4880 //
4881 // Override volume verifies on this stack location so that we
4882 // will be forced through the synchronization. Once this location
4883 // goes away we get the old value back
4884 //
4885
4886 nextStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
4887
4888 IoMarkIrpPending(Irp);
4889
4890 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4891
4892 //
4893 // Wait for CdRomClassIoctlCompletion to set the event. This
4894 // ensures serialization remains intact for these unhandled device
4895 // controls.
4896 //
4897
4898 KeWaitForSingleObject(
4899 deviceControlEvent,
4900 Suspended,
4901 KernelMode,
4902 FALSE,
4903 NULL);
4904
4905 ExFreePool(deviceControlEvent);
4906
4907 DebugPrint((2, "CdRomDeviceControl: irp %#08lx synchronized\n", Irp));
4908
4909 //
4910 // If an error occured then propagate that back up - we are no longer
4911 // guaranteed synchronization and the upper layers will have to
4912 // retry.
4913 //
4914 // If no error occured, call down to the class driver directly
4915 // then start up the next request.
4916 //
4917
4918 if(Irp->IoStatus.Status == STATUS_SUCCESS) {
4919
4920 status = ScsiClassDeviceControl(DeviceObject, Irp);
4921
4922 KeRaiseIrql(DISPATCH_LEVEL, &irql);
4923
4924 IoStartNextPacket(DeviceObject, FALSE);
4925
4926 KeLowerIrql(irql);
4927 }
4928 }
4929
4930 return status;
4931 }
4932
4933 } // end switch()
4934
4935 if (status == STATUS_VERIFY_REQUIRED) {
4936
4937 //
4938 // If the status is verified required and this request
4939 // should bypass verify required then retry the request.
4940 //
4941
4942 if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
4943
4944 status = STATUS_IO_DEVICE_ERROR;
4945 goto RetryControl;
4946
4947 }
4948 }
4949
4950 if (IoIsErrorUserInduced(status)) {
4951
4952 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
4953
4954 }
4955
4956 //
4957 // Update IRP with completion status.
4958 //
4959
4960 Irp->IoStatus.Status = status;
4961
4962 //
4963 // Complete the request.
4964 //
4965
4966 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4967 DebugPrint((2, "CdRomDeviceControl: Status is %lx\n", status));
4968 return status;
4969
4970 } // end ScsiCdRomDeviceControl()
4971
4972 VOID
4973 NTAPI
4974 ScanForSpecial(
4975 PDEVICE_OBJECT DeviceObject,
4976 PINQUIRYDATA InquiryData,
4977 PIO_SCSI_CAPABILITIES PortCapabilities
4978 )
4979
4980 /*++
4981
4982 Routine Description:
4983
4984 This function checks to see if an SCSI logical unit requires an special
4985 initialization or error processing.
4986
4987 Arguments:
4988
4989 DeviceObject - Supplies the device object to be tested.
4990
4991 InquiryData - Supplies the inquiry data returned by the device of interest.
4992
4993 PortCapabilities - Supplies the capabilities of the device object.
4994
4995 Return Value:
4996
4997 None.
4998
4999 --*/
5000
5001 {
5002 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
5003 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension+1);
5004
5005 //
5006 // Look for a Hitachi CDR-1750. Read-ahead must be disabled in order
5007 // to get this cdrom drive to work on scsi adapters that use PIO.
5008 //
5009
5010 if ((strncmp((PCHAR)InquiryData->VendorId, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
5011 strncmp((PCHAR)InquiryData->VendorId, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0)
5012 && PortCapabilities->AdapterUsesPio) {
5013
5014 DebugPrint((1, "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
5015
5016 //
5017 // Setup an error handler to reinitialize the cd rom after it is reset.
5018 //
5019
5020 deviceExtension->ClassError = HitachProcessError;
5021
5022 } else if (( RtlCompareMemory( InquiryData->VendorId,"FUJITSU", 7 ) == 7 ) &&
5023 (( RtlCompareMemory( InquiryData->ProductId,"FMCD-101", 8 ) == 8 ) ||
5024 ( RtlCompareMemory( InquiryData->ProductId,"FMCD-102", 8 ) == 8 ))) {
5025
5026 //
5027 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
5028 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
5029 // error status.
5030 //
5031
5032 deviceExtension->TimeOutValue = 20;
5033
5034 } else if (( RtlCompareMemory( InquiryData->VendorId,"TOSHIBA", 7) == 7) &&
5035 (( RtlCompareMemory( InquiryData->ProductId,"CD-ROM XM-34", 12) == 12))) {
5036
5037 SCSI_REQUEST_BLOCK srb;
5038 PCDB cdb;
5039 ULONG length;
5040 PUCHAR buffer;
5041 NTSTATUS status;
5042
5043 //
5044 // Set the density code and the error handler.
5045 //
5046
5047 length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH);
5048
5049 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
5050
5051 //
5052 // Build the MODE SENSE CDB.
5053 //
5054
5055 srb.CdbLength = 6;
5056 cdb = (PCDB)srb.Cdb;
5057
5058 //
5059 // Set timeout value from device extension.
5060 //
5061
5062 srb.TimeOutValue = deviceExtension->TimeOutValue;
5063
5064 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
5065 cdb->MODE_SENSE.PageCode = 0x1;
5066 cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
5067
5068 buffer = ExAllocatePool(NonPagedPoolCacheAligned, (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH));
5069 if (!buffer) {
5070 return;
5071 }
5072
5073 status = ScsiClassSendSrbSynchronous(DeviceObject,
5074 &srb,
5075 buffer,
5076 length,
5077 FALSE);
5078
5079 ((PERROR_RECOVERY_DATA)buffer)->BlockDescriptor.DensityCode = 0x83;
5080 ((PERROR_RECOVERY_DATA)buffer)->Header.ModeDataLength = 0x0;
5081
5082 RtlCopyMemory(&cdData->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA));
5083
5084 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
5085
5086 //
5087 // Build the MODE SENSE CDB.
5088 //
5089
5090 srb.CdbLength = 6;
5091 cdb = (PCDB)srb.Cdb;
5092
5093 //
5094 // Set timeout value from device extension.
5095 //
5096
5097 srb.TimeOutValue = deviceExtension->TimeOutValue;
5098
5099 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
5100 cdb->MODE_SELECT.PFBit = 1;
5101 cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
5102
5103 status = ScsiClassSendSrbSynchronous(DeviceObject,
5104 &srb,
5105 buffer,
5106 length,
5107 TRUE);
5108
5109 if (!NT_SUCCESS(status)) {
5110 DebugPrint((1,
5111 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
5112 status));
5113 }
5114
5115 deviceExtension->ClassError = ToshibaProcessError;
5116
5117 ExFreePool(buffer);
5118
5119 }
5120
5121 //
5122 // Determine special CD-DA requirements.
5123 //
5124
5125 if (RtlCompareMemory( InquiryData->VendorId,"PLEXTOR",7) == 7) {
5126 cdData->XAFlags |= PLEXTOR_CDDA;
5127 } else if (RtlCompareMemory ( InquiryData->VendorId,"NEC",3) == 3) {
5128 cdData->XAFlags |= NEC_CDDA;
5129 }
5130
5131 return;
5132 }
5133
5134 VOID
5135 NTAPI
5136 HitachProcessError(
5137 PDEVICE_OBJECT DeviceObject,
5138 PSCSI_REQUEST_BLOCK Srb,
5139 NTSTATUS *Status,
5140 BOOLEAN *Retry
5141 )
5142 /*++
5143
5144 Routine Description:
5145
5146 This routine checks the type of error. If the error indicates CD-ROM the
5147 CD-ROM needs to be reinitialized then a Mode sense command is sent to the
5148 device. This command disables read-ahead for the device.
5149
5150 Arguments:
5151
5152 DeviceObject - Supplies a pointer to the device object.
5153
5154 Srb - Supplies a pointer to the failing Srb.
5155
5156 Status - Not used.
5157
5158 Retry - Not used.
5159
5160 Return Value:
5161
5162 None.
5163
5164 --*/
5165
5166 {
5167 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
5168 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
5169 LARGE_INTEGER largeInt;
5170 PUCHAR modePage;
5171 PIO_STACK_LOCATION irpStack;
5172 PIRP irp;
5173 PSCSI_REQUEST_BLOCK srb;
5174 PCOMPLETION_CONTEXT context;
5175 PCDB cdb;
5176 ULONG alignment;
5177
5178 UNREFERENCED_PARAMETER(Status);
5179 UNREFERENCED_PARAMETER(Retry);
5180
5181 largeInt.QuadPart = (LONGLONG) 1;
5182
5183 //
5184 // Check the status. The initialization command only needs to be sent
5185 // if UNIT ATTENTION is returned.
5186 //
5187
5188 if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
5189
5190 //
5191 // The drive does not require reinitialization.
5192 //
5193
5194 return;
5195 }
5196
5197 //
5198 // Found a bad HITACHI cd-rom. These devices do not work with PIO
5199 // adapters when read-ahead is enabled. Read-ahead is disabled by
5200 // a mode select command. The mode select page code is zero and the
5201 // length is 6 bytes. All of the other bytes should be zero.
5202 //
5203
5204
5205 if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
5206
5207 DebugPrint((1, "HitachiProcessError: Reinitializing the CD-ROM.\n"));
5208
5209 //
5210 // Send the special mode select command to disable read-ahead
5211 // on the CD-ROM reader.
5212 //
5213
5214 alignment = DeviceObject->AlignmentRequirement ?
5215 DeviceObject->AlignmentRequirement : 1;
5216
5217 context = ExAllocatePool(
5218 NonPagedPool,
5219 sizeof(COMPLETION_CONTEXT) + HITACHI_MODE_DATA_SIZE + alignment
5220 );
5221
5222 if (context == NULL) {
5223
5224 //
5225 // If there is not enough memory to fulfill this request,
5226 // simply return. A subsequent retry will fail and another
5227 // chance to start the unit.
5228 //
5229
5230 return;
5231 }
5232
5233 context->DeviceObject = DeviceObject;
5234 srb = &context->Srb;
5235
5236 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
5237
5238 //
5239 // Write length to SRB.
5240 //
5241
5242 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
5243
5244 //
5245 // Set up SCSI bus address.
5246 //
5247
5248 srb->PathId = deviceExtension->PathId;
5249 srb->TargetId = deviceExtension->TargetId;
5250 srb->Lun = deviceExtension->Lun;
5251
5252 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
5253 srb->TimeOutValue = deviceExtension->TimeOutValue;
5254
5255 //
5256 // Set the transfer length.
5257 //
5258
5259 srb->DataTransferLength = HITACHI_MODE_DATA_SIZE;
5260 srb->SrbFlags = SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
5261
5262 //
5263 // The data buffer must be aligned.
5264 //
5265
5266 srb->DataBuffer = (PVOID) (((ULONG_PTR) (context + 1) + (alignment - 1)) &
5267 ~(alignment - 1));
5268
5269
5270 //
5271 // Build the HITACHI read-ahead mode select CDB.
5272 //
5273
5274 srb->CdbLength = 6;
5275 cdb = (PCDB)srb->Cdb;
5276 cdb->MODE_SENSE.LogicalUnitNumber = srb->Lun;
5277 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SELECT;
5278 cdb->MODE_SENSE.AllocationLength = HITACHI_MODE_DATA_SIZE;
5279
5280 //
5281 // Initialize the mode sense data.
5282 //
5283
5284 modePage = srb->DataBuffer;
5285
5286 RtlZeroMemory(modePage, HITACHI_MODE_DATA_SIZE);
5287
5288 //
5289 // Set the page length field to 6.
5290 //
5291
5292 modePage[5] = 6;
5293
5294 //
5295 // Build the asynchronous request to be sent to the port driver.
5296 //
5297
5298 irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE,
5299 DeviceObject,
5300 srb->DataBuffer,
5301 srb->DataTransferLength,
5302 &largeInt,
5303 NULL);
5304
5305 IoSetCompletionRoutine(irp,
5306 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
5307 context,
5308 TRUE,
5309 TRUE,
5310 TRUE);
5311
5312 irpStack = IoGetNextIrpStackLocation(irp);
5313
5314 irpStack->MajorFunction = IRP_MJ_SCSI;
5315
5316 srb->OriginalRequest = irp;
5317
5318 //
5319 // Save SRB address in next stack for port driver.
5320 //
5321
5322 irpStack->Parameters.Scsi.Srb = (PVOID)srb;
5323
5324 //
5325 // Set up IRP Address.
5326 //
5327
5328 (VOID)IoCallDriver(deviceExtension->PortDeviceObject, irp);
5329
5330 }
5331 }
5332
5333 NTSTATUS
5334 NTAPI
5335 ToshibaProcessErrorCompletion(
5336 PDEVICE_OBJECT DeviceObject,
5337 PIRP Irp,
5338 PVOID Context
5339 )
5340
5341 /*++
5342
5343 Routine Description:
5344
5345 Completion routine for the ClassError routine to handle older Toshiba units
5346 that require setting the density code.
5347
5348 Arguments:
5349
5350 DeviceObject - Supplies a pointer to the device object.
5351
5352 Irp - Pointer to irp created to set the density code.
5353
5354 Context - Supplies a pointer to the Mode Select Srb.
5355
5356
5357 Return Value:
5358
5359 STATUS_MORE_PROCESSING_REQUIRED
5360
5361 --*/
5362
5363 {
5364
5365 PSCSI_REQUEST_BLOCK srb = Context;
5366
5367 //
5368 // Check for a frozen queue.
5369 //
5370
5371 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
5372
5373 //
5374 // Unfreeze the queue getting the device object from the context.
5375 //
5376
5377 ScsiClassReleaseQueue(DeviceObject);
5378 }
5379
5380 //
5381 // Free all of the allocations.
5382 //
5383
5384 ExFreePool(srb->DataBuffer);
5385 ExFreePool(srb);
5386 IoFreeMdl(Irp->MdlAddress);
5387 IoFreeIrp(Irp);
5388
5389 //
5390 // Indicate the I/O system should stop processing the Irp completion.
5391 //
5392
5393 return STATUS_MORE_PROCESSING_REQUIRED;
5394 }
5395
5396 VOID
5397 NTAPI
5398 ToshibaProcessError(
5399 PDEVICE_OBJECT DeviceObject,
5400 PSCSI_REQUEST_BLOCK Srb,
5401 NTSTATUS *Status,
5402 BOOLEAN *Retry
5403 )
5404
5405 /*++
5406
5407 Routine Description:
5408
5409 This routine checks the type of error. If the error indicates a unit attention,
5410 the density code needs to be set via a Mode select command.
5411
5412 Arguments:
5413
5414 DeviceObject - Supplies a pointer to the device object.
5415
5416 Srb - Supplies a pointer to the failing Srb.
5417
5418 Status - Not used.
5419
5420 Retry - Not used.
5421
5422 Return Value:
5423
5424 None.
5425
5426 --*/
5427
5428 {
5429 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
5430 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension+1);
5431 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
5432 PIO_STACK_LOCATION irpStack;
5433 PIRP irp;
5434 PSCSI_REQUEST_BLOCK srb;
5435 ULONG length;
5436 PCDB cdb;
5437 PUCHAR dataBuffer;
5438
5439
5440 if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
5441 return;
5442 }
5443
5444 //
5445 // The Toshiba's require the density code to be set on power up and media changes.
5446 //
5447
5448 if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
5449
5450
5451 irp = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1),
5452 FALSE);
5453
5454 if (!irp) {
5455 return;
5456 }
5457
5458 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
5459 if (!srb) {
5460 IoFreeIrp(irp);
5461 return;
5462 }
5463
5464
5465 length = sizeof(ERROR_RECOVERY_DATA);
5466 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, length);
5467 if (!dataBuffer) {
5468 ExFreePool(srb);
5469 IoFreeIrp(irp);
5470 return;
5471 }
5472
5473 irp->MdlAddress = IoAllocateMdl(dataBuffer,
5474 length,
5475 FALSE,
5476 FALSE,
5477 (PIRP) NULL);
5478
5479 if (!irp->MdlAddress) {
5480 ExFreePool(srb);
5481 ExFreePool(dataBuffer);
5482 IoFreeIrp(irp);
5483 return;
5484 }
5485
5486 //
5487 // Prepare the MDL
5488 //
5489
5490 MmBuildMdlForNonPagedPool(irp->MdlAddress);
5491
5492 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
5493
5494 srb->DataBuffer = dataBuffer;
5495 cdb = (PCDB)srb->Cdb;
5496
5497 //
5498 // Set up the irp.
5499 //
5500
5501 IoSetNextIrpStackLocation(irp);
5502 irp->IoStatus.Status = STATUS_SUCCESS;
5503 irp->IoStatus.Information = 0;
5504 irp->Flags = 0;
5505 irp->UserBuffer = NULL;
5506
5507 //
5508 // Save the device object and irp in a private stack location.
5509 //
5510
5511 irpStack = IoGetCurrentIrpStackLocation(irp);
5512 irpStack->DeviceObject = deviceExtension->DeviceObject;
5513
5514 //
5515 // Construct the IRP stack for the lower level driver.
5516 //
5517
5518 irpStack = IoGetNextIrpStackLocation(irp);
5519 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
5520 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_OUT;
5521 irpStack->Parameters.Scsi.Srb = srb;
5522
5523 IoSetCompletionRoutine(irp,
5524 ToshibaProcessErrorCompletion,
5525 srb,
5526 TRUE,
5527 TRUE,
5528 TRUE);
5529
5530 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
5531 srb->PathId = deviceExtension->PathId;
5532 srb->TargetId = deviceExtension->TargetId;
5533 srb->Lun = deviceExtension->Lun;
5534 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
5535 srb->Cdb[1] |= deviceExtension->Lun << 5;
5536 srb->SrbStatus = srb->ScsiStatus = 0;
5537 srb->NextSrb = 0;
5538 srb->OriginalRequest = irp;
5539 srb->SenseInfoBufferLength = 0;
5540
5541 //
5542 // Set the transfer length.
5543 //
5544
5545 srb->DataTransferLength = length;
5546 srb->SrbFlags = SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
5547
5548
5549 srb->CdbLength = 6;
5550 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
5551 cdb->MODE_SELECT.PFBit = 1;
5552 cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
5553
5554 //
5555 // Copy the Mode page into the databuffer.
5556 //
5557
5558 RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, length);
5559
5560 //
5561 // Set the density code.
5562 //
5563
5564 ((PERROR_RECOVERY_DATA)srb->DataBuffer)->BlockDescriptor.DensityCode = 0x83;
5565
5566 IoCallDriver(deviceExtension->PortDeviceObject, irp);
5567 }
5568 }
5569
5570 BOOLEAN
5571 NTAPI
5572 CdRomIsPlayActive(
5573 IN PDEVICE_OBJECT DeviceObject
5574 )
5575
5576 /*++
5577
5578 Routine Description:
5579
5580 This routine determines if the cd is currently playing music.
5581
5582 Arguments:
5583
5584 DeviceObject - Device object to test.
5585
5586 Return Value:
5587
5588 TRUE if the device is playing music.
5589
5590 --*/
5591 {
5592 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
5593 PIRP irp;
5594 IO_STATUS_BLOCK ioStatus;
5595 KEVENT event;
5596 NTSTATUS status;
5597 PSUB_Q_CURRENT_POSITION currentBuffer;
5598
5599 if (!PLAY_ACTIVE(deviceExtension)) {
5600 return(FALSE);
5601 }
5602
5603 currentBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(SUB_Q_CURRENT_POSITION));
5604
5605 if (currentBuffer == NULL) {
5606 return(FALSE);
5607 }
5608
5609 ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION;
5610 ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0;
5611
5612 //
5613 // Create notification event object to be used to signal the
5614 // request completion.
5615 //
5616
5617 KeInitializeEvent(&event, NotificationEvent, FALSE);
5618
5619 //
5620 // Build the synchronous request to be sent to the port driver
5621 // to perform the request.
5622 //
5623
5624 irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL,
5625 deviceExtension->DeviceObject,
5626 currentBuffer,
5627 sizeof(CDROM_SUB_Q_DATA_FORMAT),
5628 currentBuffer,
5629 sizeof(SUB_Q_CURRENT_POSITION),
5630 FALSE,
5631 &event,
5632 &ioStatus);
5633
5634 if (irp == NULL) {
5635 ExFreePool(currentBuffer);
5636 return FALSE;
5637 }
5638
5639 //
5640 // Pass request to port driver and wait for request to complete.
5641 //
5642
5643 status = IoCallDriver(deviceExtension->DeviceObject, irp);
5644
5645 if (status == STATUS_PENDING) {
5646 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
5647 status = ioStatus.Status;
5648 }
5649
5650 if (!NT_SUCCESS(status)) {
5651 ExFreePool(currentBuffer);
5652 return FALSE;
5653 }
5654
5655 ExFreePool(currentBuffer);
5656
5657 return(PLAY_ACTIVE(deviceExtension));
5658
5659 }
5660
5661 IO_COMPLETION_ROUTINE CdRomMediaChangeCompletion;
5662 NTSTATUS
5663 NTAPI
5664 CdRomMediaChangeCompletion(
5665 PDEVICE_OBJECT DeviceObject,
5666 PIRP Irp,
5667 PVOID Context
5668 )
5669
5670 /*++
5671
5672 Routine Description:
5673
5674 This routine handles the completion of the test unit ready irps
5675 used to determine if the media has changed. If the media has
5676 changed, this code signals the named event to wake up other
5677 system services that react to media change (aka AutoPlay).
5678
5679 Arguments:
5680
5681 DeviceObject - the object for the completion
5682 Irp - the IRP being completed
5683 Context - the SRB from the IRP
5684
5685 Return Value:
5686
5687 NTSTATUS
5688
5689 --*/
5690
5691 {
5692 PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK) Context;
5693 PIO_STACK_LOCATION cdStack = IoGetCurrentIrpStackLocation(Irp);
5694 PIO_STACK_LOCATION irpNextStack = IoGetNextIrpStackLocation(Irp);
5695 PDEVICE_EXTENSION deviceExtension;
5696 PDEVICE_EXTENSION physicalExtension;
5697 PSENSE_DATA senseBuffer;
5698 PCDROM_DATA cddata;
5699
5700 ASSERT(Irp);
5701 ASSERT(cdStack);
5702 DeviceObject = cdStack->DeviceObject;
5703 ASSERT(DeviceObject);
5704
5705 deviceExtension = DeviceObject->DeviceExtension;
5706 physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension;
5707 cddata = (PCDROM_DATA)(deviceExtension + 1);
5708
5709 ASSERT(cddata->MediaChangeIrp == NULL);
5710
5711 //
5712 // If the sense data field is valid, look for a media change.
5713 // otherwise this iteration of the polling will just assume nothing
5714 // changed.
5715 //
5716
5717 DebugPrint((3, "CdRomMediaChangeHandler: Completing Autorun Irp 0x%lx "
5718 "for device %d\n",
5719 Irp, deviceExtension->DeviceNumber));
5720
5721 if (srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
5722 if (srb->SenseInfoBufferLength >= FIELD_OFFSET(SENSE_DATA, CommandSpecificInformation)) {
5723
5724 //
5725 // See if this is a media change.
5726 //
5727
5728 senseBuffer = srb->SenseInfoBuffer;
5729 if ((senseBuffer->SenseKey & 0x0f) == SCSI_SENSE_UNIT_ATTENTION) {
5730 if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_MEDIUM_CHANGED) {
5731
5732 DebugPrint((1, "CdRomMediaChangeCompletion: New media inserted "
5733 "into CdRom%d [irp = 0x%lx]\n",
5734 deviceExtension->DeviceNumber, Irp));
5735
5736 //
5737 // Media change event occurred - signal the named event.
5738 //
5739
5740 KeSetEvent(deviceExtension->MediaChangeEvent,
5741 (KPRIORITY) 0,
5742 FALSE);
5743
5744 deviceExtension->MediaChangeNoMedia = FALSE;
5745
5746 }
5747
5748 if (DeviceObject->Vpb->Flags & VPB_MOUNTED) {
5749
5750 //
5751 // Must remember the media changed and force the
5752 // file system to verify on next access
5753 //
5754
5755 DeviceObject->Flags |= DO_VERIFY_VOLUME;
5756 }
5757
5758 physicalExtension->MediaChangeCount++;
5759
5760 } else if(((senseBuffer->SenseKey & 0x0f) == SCSI_SENSE_NOT_READY)&&
5761 (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE)&&
5762 (!deviceExtension->MediaChangeNoMedia)){
5763
5764 //
5765 // If there was no media in the device then signal the waiters if
5766 // we haven't already done so before.
5767 //
5768
5769 DebugPrint((1, "CdRomMediaChangeCompletion: No media in device"
5770 "CdRom%d [irp = 0x%lx]\n",
5771 deviceExtension->DeviceNumber, Irp));
5772
5773 KeSetEvent(deviceExtension->MediaChangeEvent,
5774 (KPRIORITY) 0,
5775 FALSE);
5776
5777 deviceExtension->MediaChangeNoMedia = TRUE;
5778
5779 }
5780 }
5781 } else if((srb->SrbStatus == SRB_STATUS_SUCCESS)&&
5782 (deviceExtension->MediaChangeNoMedia)) {
5783 //
5784 // We didn't have any media before and now the requests are succeeding
5785 // we probably missed the Media change somehow. Signal the change
5786 // anyway
5787 //
5788
5789 DebugPrint((1, "CdRomMediaChangeCompletion: Request completed normally"
5790 "for CdRom%d which was marked w/NoMedia [irp = 0x%lx]\n",
5791 deviceExtension->DeviceNumber, Irp));
5792
5793 KeSetEvent(deviceExtension->MediaChangeEvent,
5794 (KPRIORITY) 0,
5795 FALSE);
5796
5797 deviceExtension->MediaChangeNoMedia = FALSE;
5798
5799 }
5800
5801 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
5802 ScsiClassReleaseQueue(deviceExtension->DeviceObject);
5803 }
5804
5805 //
5806 // Remember the IRP and SRB for use the next time.
5807 //
5808
5809 irpNextStack->Parameters.Scsi.Srb = srb;
5810 cddata->MediaChangeIrp = Irp;
5811
5812 if (deviceExtension->ClassError) {
5813
5814 NTSTATUS status;
5815 BOOLEAN retry;
5816
5817 //
5818 // Throw away the status and retry values. Just give the error routine a chance
5819 // to do what it needs to.
5820 //
5821
5822 deviceExtension->ClassError(DeviceObject,
5823 srb,
5824 &status,
5825 &retry);
5826 }
5827
5828 IoStartNextPacket(DeviceObject, FALSE);
5829
5830 return STATUS_MORE_PROCESSING_REQUIRED;
5831 }
5832
5833 VOID
5834 NTAPI
5835 CdRomTickHandler(
5836 IN PDEVICE_OBJECT DeviceObject,
5837 IN PVOID Context
5838 )
5839
5840 /*++
5841
5842 Routine Description:
5843
5844 This routine handles the once per second timer provided by the
5845 Io subsystem. It is only used when the cdrom device itself is
5846 a candidate for autoplay support. It should never be called if
5847 the cdrom device is a changer device.
5848
5849 Arguments:
5850
5851 DeviceObject - what to check.
5852 Context - not used.
5853
5854 Return Value:
5855
5856 None.
5857
5858 --*/
5859
5860 {
5861 PIRP irp;
5862 PIRP heldIrpList;
5863 PIRP nextIrp;
5864 PLIST_ENTRY listEntry;
5865 PCDROM_DATA cddata;
5866 PIO_STACK_LOCATION irpStack;
5867 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
5868
5869 cddata = (PCDROM_DATA)(deviceExtension + 1);
5870
5871 if (cddata->MediaChange) {
5872 if (cddata->MediaChangeIrp != NULL) {
5873
5874 //
5875 // Media change support is active and the IRP is waiting.
5876 // Decrement the timer.
5877 // There is no MP protection on the timer counter. This
5878 // code is the only code that will manipulate the timer
5879 // and only one instance of it should be running at any
5880 // given time.
5881 //
5882
5883 cddata->MediaChangeCountDown--;
5884
5885 #if DBG
5886 cddata->MediaChangeIrpTimeInUse = 0;
5887 cddata->MediaChangeIrpLost = FALSE;
5888 #endif
5889
5890 if (!cddata->MediaChangeCountDown) {
5891 PSCSI_REQUEST_BLOCK srb;
5892 PIO_STACK_LOCATION irpNextStack;
5893 PCDB cdb;
5894
5895 //
5896 // Reset the timer.
5897 //
5898
5899 cddata->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
5900
5901 //
5902 // Prepare the IRP for the test unit ready
5903 //
5904
5905 irp = cddata->MediaChangeIrp;
5906 cddata->MediaChangeIrp = NULL;
5907
5908 irp->IoStatus.Status = STATUS_SUCCESS;
5909 irp->IoStatus.Information = 0;
5910 irp->Flags = 0;
5911 irp->UserBuffer = NULL;
5912
5913 //
5914 // If the irp is sent down when the volume needs to be
5915 // verified, CdRomUpdateGeometryCompletion won't complete
5916 // it since it's not associated with a thread. Marking
5917 // it to override the verify causes it always be sent
5918 // to the port driver
5919 //
5920
5921 irpStack = IoGetCurrentIrpStackLocation(irp);
5922 irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
5923
5924 irpNextStack = IoGetNextIrpStackLocation(irp);
5925 irpNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
5926 irpNextStack->Parameters.DeviceIoControl.IoControlCode =
5927 IOCTL_SCSI_EXECUTE_NONE;
5928
5929 //
5930 // Prepare the SRB for execution.
5931 //
5932
5933 srb = irpNextStack->Parameters.Scsi.Srb;
5934 srb->SrbStatus = srb->ScsiStatus = 0;
5935 srb->NextSrb = 0;
5936 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
5937 srb->PathId = deviceExtension->PathId;
5938 srb->TargetId = deviceExtension->TargetId;
5939 srb->Lun = deviceExtension->Lun;
5940 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
5941 srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
5942 SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
5943 srb->DataTransferLength = 0;
5944 srb->OriginalRequest = irp;
5945
5946 RtlZeroMemory(srb->SenseInfoBuffer, SENSE_BUFFER_SIZE);
5947 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
5948
5949 cdb = (PCDB) &srb->Cdb[0];
5950 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
5951 cdb->CDB6GENERIC.LogicalUnitNumber = srb->Lun;
5952
5953 //
5954 // Setup the IRP to perform a test unit ready.
5955 //
5956
5957 IoSetCompletionRoutine(irp,
5958 CdRomMediaChangeCompletion,
5959 srb,
5960 TRUE,
5961 TRUE,
5962 TRUE);
5963
5964 //
5965 // Issue the request.
5966 //
5967
5968 IoStartPacket(DeviceObject, irp, NULL, NULL);
5969 }
5970 } else {
5971
5972 #if DBG
5973 if(cddata->MediaChangeIrpLost == FALSE) {
5974 if(cddata->MediaChangeIrpTimeInUse++ >
5975 MEDIA_CHANGE_TIMEOUT_TIME) {
5976
5977 DebugPrint((0, "CdRom%d: AutoPlay has lost it's irp and "
5978 "doesn't know where to find it. Leave it "
5979 "alone and it'll come home dragging it's "
5980 "stack behind it.\n",
5981 deviceExtension->DeviceNumber));
5982 cddata->MediaChangeIrpLost = TRUE;
5983 }
5984 }
5985
5986 #endif
5987 }
5988 }
5989
5990 //
5991 // Process all generic timer IRPS in the timer list. As IRPs are pulled
5992 // off of the TimerIrpList they must be remembered in the first loop
5993 // if they are not sent to the lower driver. After all items have
5994 // been pulled off the list, it is possible to put the held IRPs back
5995 // into the TimerIrpList.
5996 //
5997
5998 heldIrpList = NULL;
5999 if (IsListEmpty(&cddata->TimerIrpList)) {
6000 listEntry = NULL;
6001 } else {
6002 listEntry = ExInterlockedRemoveHeadList(&cddata->TimerIrpList,
6003 &cddata->TimerIrpSpinLock);
6004 }
6005 while (listEntry) {
6006
6007 //
6008 // There is something in the timer list. Pick up the IRP and
6009 // see if it is ready to be submitted.
6010 //
6011
6012 irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
6013 irpStack = IoGetCurrentIrpStackLocation(irp);
6014
6015 if (irpStack->Parameters.Others.Argument3) {
6016 ULONG_PTR count;
6017
6018 //
6019 // Decrement the countdown timer and put the IRP back in the list.
6020 //
6021
6022 count = (ULONG_PTR) irpStack->Parameters.Others.Argument3;
6023 count--;
6024 irpStack->Parameters.Others.Argument3 = (PVOID) count;
6025
6026 ASSERT(irp->AssociatedIrp.MasterIrp == NULL);
6027 if (heldIrpList) {
6028 irp->AssociatedIrp.MasterIrp = (PVOID) heldIrpList;
6029 }
6030 heldIrpList = irp;
6031
6032 } else {
6033
6034 //
6035 // Submit this IRP to the lower driver. This IRP does not
6036 // need to be remembered here. It will be handled again when
6037 // it completes.
6038 //
6039
6040 DebugPrint((1, "CdRomTickHandler: Reissuing request %lx (thread = %lx)\n", irp, irp->Tail.Overlay.Thread));
6041
6042 //
6043 // feed this to the appropriate port driver
6044 //
6045
6046 IoCallDriver (deviceExtension->PortDeviceObject, irp);
6047
6048 }
6049
6050 //
6051 // Pick up the next IRP from the timer list.
6052 //
6053
6054 listEntry = ExInterlockedRemoveHeadList(&cddata->TimerIrpList,
6055 &cddata->TimerIrpSpinLock);
6056 }
6057
6058 //
6059 // Move all held IRPs back onto the timer list.
6060 //
6061
6062 while (heldIrpList) {
6063
6064 //
6065 // Save the single list pointer before queueing this IRP.
6066 //
6067
6068 nextIrp = (PIRP) heldIrpList->AssociatedIrp.MasterIrp;
6069 heldIrpList->AssociatedIrp.MasterIrp = NULL;
6070
6071 //
6072 // Return the held IRP to the timer list.
6073 //
6074
6075 ExInterlockedInsertTailList(&cddata->TimerIrpList,
6076 &heldIrpList->Tail.Overlay.ListEntry,
6077 &cddata->TimerIrpSpinLock);
6078
6079 //
6080 // Continue processing the held IRPs
6081 //
6082
6083 heldIrpList = nextIrp;
6084 }
6085 }
6086
6087 BOOLEAN
6088 NTAPI
6089 CdRomCheckRegistryForMediaChangeValue(
6090 IN PUNICODE_STRING RegistryPath,
6091 IN ULONG DeviceNumber
6092 )
6093
6094 /*++
6095
6096 Routine Description:
6097
6098 The user must specify that AutoPlay is to run on the platform
6099 by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
6100 Services\Cdrom\Autorun:REG_DWORD:1.
6101
6102 The user can override the global setting to enable or disable Autorun on a
6103 specific cdrom device by setting the key HKEY_LOCAL_MACHINE\System\
6104 CurrentControlSet\Services\Cdrom\Device<N>\Autorun:REG_DWORD to one or zero.
6105 (CURRENTLY UNIMPLEMENTED)
6106
6107 If this registry value does not exist or contains the value zero then
6108 the timer to check for media change does not run.
6109
6110 Arguments:
6111
6112 RegistryPath - pointer to the unicode string inside
6113 ...\CurrentControlSet\Services\Cdrom
6114 DeviceNumber - The number of the device object
6115
6116 Return Value:
6117
6118 TRUE - Autorun is enabled.
6119 FALSE - no autorun.
6120
6121 --*/
6122
6123 {
6124 #define ITEMS_TO_QUERY 2 /* always 1 greater than what is searched */
6125 PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
6126 NTSTATUS status;
6127 LONG zero = 0;
6128
6129 LONG tmp = 0;
6130 LONG doRun = 0;
6131
6132 CHAR buf[32];
6133 ANSI_STRING paramNum;
6134
6135 UNICODE_STRING paramStr;
6136
6137 UNICODE_STRING paramSuffix;
6138 UNICODE_STRING paramPath;
6139 UNICODE_STRING paramDevPath;
6140
6141 //
6142 // First append \Parameters to the passed in registry path
6143 //
6144
6145 RtlInitUnicodeString(&paramStr, L"\\Parameters");
6146
6147 RtlInitUnicodeString(&paramPath, NULL);
6148
6149 paramPath.MaximumLength = RegistryPath->Length +
6150 paramStr.Length +
6151 sizeof(WCHAR);
6152
6153 paramPath.Buffer = ExAllocatePool(PagedPool, paramPath.MaximumLength);
6154
6155 if(!paramPath.Buffer) {
6156
6157 DebugPrint((1,"CdRomCheckRegAP: couldn't allocate paramPath\n"));
6158
6159 return FALSE;
6160 }
6161
6162 RtlZeroMemory(paramPath.Buffer, paramPath.MaximumLength);
6163 RtlAppendUnicodeToString(&paramPath, RegistryPath->Buffer);
6164 RtlAppendUnicodeToString(&paramPath, paramStr.Buffer);
6165
6166 DebugPrint((2, "CdRomCheckRegAP: paramPath [%d] = %ws\n",
6167 paramPath.Length,
6168 paramPath.Buffer));
6169
6170 //
6171 // build a counted ANSI string that contains
6172 // the suffix for the path
6173 //
6174
6175 sprintf(buf, "\\Device%lu", DeviceNumber);
6176 RtlInitAnsiString(&paramNum, buf);
6177
6178 //
6179 // Next convert this into a unicode string
6180 //
6181
6182 status = RtlAnsiStringToUnicodeString(&paramSuffix, &paramNum, TRUE);
6183
6184 if(!NT_SUCCESS(status)) {
6185 DebugPrint((1,"CdRomCheckRegAP: couldn't convert paramNum to paramSuffix\n"));
6186 ExFreePool(paramPath.Buffer);
6187 return FALSE;
6188 }
6189
6190 RtlInitUnicodeString(&paramDevPath, NULL);
6191
6192 //
6193 // now build the device specific path
6194 //
6195
6196 paramDevPath.MaximumLength = paramPath.Length +
6197 paramSuffix.Length +
6198 sizeof(WCHAR);
6199 paramDevPath.Buffer = ExAllocatePool(PagedPool, paramDevPath.MaximumLength);
6200
6201 if(!paramDevPath.Buffer) {
6202 RtlFreeUnicodeString(&paramSuffix);
6203 ExFreePool(paramPath.Buffer);
6204 return FALSE;
6205 }
6206
6207 RtlZeroMemory(paramDevPath.Buffer, paramDevPath.MaximumLength);
6208 RtlAppendUnicodeToString(&paramDevPath, paramPath.Buffer);
6209 RtlAppendUnicodeToString(&paramDevPath, paramSuffix.Buffer);
6210
6211 DebugPrint((2, "CdRomCheckRegAP: paramDevPath [%d] = %ws\n",
6212 paramPath.Length,
6213 paramPath.Buffer));
6214
6215 parameters = ExAllocatePool(NonPagedPool,
6216 sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY);
6217
6218 if (parameters) {
6219
6220 //
6221 // Check for the Autorun value.
6222 //
6223
6224 RtlZeroMemory(parameters,
6225 (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY));
6226
6227 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
6228 parameters[0].Name = L"Autorun";
6229 parameters[0].EntryContext = &doRun;
6230 parameters[0].DefaultType = REG_DWORD;
6231 parameters[0].DefaultData = &zero;
6232 parameters[0].DefaultLength = sizeof(ULONG);
6233
6234 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
6235 RegistryPath->Buffer,
6236 parameters,
6237 NULL,
6238 NULL);
6239
6240 DebugPrint((2, "CdRomCheckRegAP: cdrom/Autorun flag = %d\n", doRun));
6241
6242 RtlZeroMemory(parameters,
6243 (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY));
6244
6245 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
6246 parameters[0].Name = L"Autorun";
6247 parameters[0].EntryContext = &tmp;
6248 parameters[0].DefaultType = REG_DWORD;
6249 parameters[0].DefaultData = &doRun;
6250 parameters[0].DefaultLength = sizeof(ULONG);
6251
6252 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
6253 paramPath.Buffer,
6254 parameters,
6255 NULL,
6256 NULL);
6257
6258 DebugPrint((2, "CdRomCheckRegAP: cdrom/parameters/autorun flag = %d\n", tmp));
6259
6260 RtlZeroMemory(parameters,
6261 (sizeof(RTL_QUERY_REGISTRY_TABLE) * ITEMS_TO_QUERY));
6262
6263 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
6264 parameters[0].Name = L"Autorun";
6265 parameters[0].EntryContext = &doRun;
6266 parameters[0].DefaultType = REG_DWORD;
6267 parameters[0].DefaultData = &tmp;
6268 parameters[0].DefaultLength = sizeof(ULONG);
6269
6270 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
6271 paramDevPath.Buffer,
6272 parameters,
6273 NULL,
6274 NULL);
6275
6276 DebugPrint((1, "CdRomCheckRegAP: cdrom/parameters/device%d/autorun flag = %d\n", DeviceNumber, doRun));
6277
6278 ExFreePool(parameters);
6279
6280 }
6281
6282 ExFreePool(paramPath.Buffer);
6283 ExFreePool(paramDevPath.Buffer);
6284 RtlFreeUnicodeString(&paramSuffix);
6285
6286 DebugPrint((1, "CdRomCheckRegAP: Autoplay for device %d is %s\n",
6287 DeviceNumber,
6288 (doRun ? "on" : "off")));
6289
6290 if(doRun) {
6291 return TRUE;
6292 }
6293
6294 return FALSE;
6295 }
6296
6297
6298 BOOLEAN
6299 NTAPI
6300 IsThisASanyo(
6301 IN PDEVICE_OBJECT DeviceObject,
6302 IN UCHAR PathId,
6303 IN UCHAR TargetId
6304 )
6305
6306 /*++
6307
6308 Routine Description:
6309
6310 This routine is called by DriverEntry to determine whether a Sanyo 3-CD
6311 changer device is present.
6312
6313 Arguments:
6314
6315 DeviceObject - Supplies the device object for the 'real' device.
6316
6317 PathId -
6318
6319 Return Value:
6320
6321 TRUE - if an Atapi changer device is found.
6322
6323 --*/
6324
6325 {
6326 KEVENT event;
6327 PIRP irp;
6328 PCHAR inquiryBuffer;
6329 IO_STATUS_BLOCK ioStatus;
6330 NTSTATUS status;
6331 PSCSI_ADAPTER_BUS_INFO adapterInfo;
6332 ULONG scsiBus;
6333 PINQUIRYDATA inquiryData;
6334 PSCSI_INQUIRY_DATA lunInfo;
6335
6336 inquiryBuffer = ExAllocatePool(NonPagedPool, 2048);
6337 KeInitializeEvent(&event, NotificationEvent, FALSE);
6338 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
6339 DeviceObject,
6340 NULL,
6341 0,
6342 inquiryBuffer,
6343 2048,
6344 FALSE,
6345 &event,
6346 &ioStatus);
6347 if (!irp) {
6348 return FALSE;
6349 }
6350
6351 status = IoCallDriver(DeviceObject, irp);
6352
6353 if (status == STATUS_PENDING) {
6354 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
6355 status = ioStatus.Status;
6356 }
6357
6358 if (!NT_SUCCESS(status)) {
6359 return FALSE;
6360 }
6361
6362 adapterInfo = (PVOID) inquiryBuffer;
6363
6364 for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) {
6365
6366 //
6367 // Get the SCSI bus scan data for this bus.
6368 //
6369
6370 lunInfo = (PVOID) (inquiryBuffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
6371
6372 for (;;) {
6373
6374 if (lunInfo->PathId == PathId && lunInfo->TargetId == TargetId) {
6375
6376 inquiryData = (PVOID) lunInfo->InquiryData;
6377
6378 if (RtlCompareMemory(inquiryData->VendorId, "TORiSAN CD-ROM CDR-C", 20) == 20) {
6379 ExFreePool(inquiryBuffer);
6380 return TRUE;
6381 }
6382
6383 ExFreePool(inquiryBuffer);
6384 return FALSE;
6385 }
6386
6387 if (!lunInfo->NextInquiryDataOffset) {
6388 break;
6389 }
6390
6391 lunInfo = (PVOID) (inquiryBuffer + lunInfo->NextInquiryDataOffset);
6392 }
6393 }
6394
6395 ExFreePool(inquiryBuffer);
6396 return FALSE;
6397 }
6398
6399 BOOLEAN
6400 NTAPI
6401 IsThisAnAtapiChanger(
6402 IN PDEVICE_OBJECT DeviceObject,
6403 OUT PULONG DiscsPresent
6404 )
6405
6406 /*++
6407
6408 Routine Description:
6409
6410 This routine is called by DriverEntry to determine whether an Atapi
6411 changer device is present.
6412
6413 Arguments:
6414
6415 DeviceObject - Supplies the device object for the 'real' device.
6416
6417 DiscsPresent - Supplies a pointer to the number of Discs supported by the changer.
6418
6419 Return Value:
6420
6421 TRUE - if an Atapi changer device is found.
6422
6423 --*/
6424
6425 {
6426 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
6427 PMECHANICAL_STATUS_INFORMATION_HEADER mechanicalStatusBuffer;
6428 NTSTATUS status;
6429 SCSI_REQUEST_BLOCK srb;
6430 PCDB cdb = (PCDB) &srb.Cdb[0];
6431 BOOLEAN retVal = FALSE;
6432
6433 *DiscsPresent = 0;
6434
6435 //
6436 // Some devices can't handle 12 byte CDB's gracefully
6437 //
6438
6439 if(deviceExtension->DeviceFlags & DEV_NO_12BYTE_CDB) {
6440
6441 return FALSE;
6442
6443 }
6444
6445 //
6446 // Build and issue the mechanical status command.
6447 //
6448
6449 mechanicalStatusBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
6450 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER));
6451
6452 if (!mechanicalStatusBuffer) {
6453 retVal = FALSE;
6454 } else {
6455
6456 //
6457 // Build and send the Mechanism status CDB.
6458 //
6459
6460 RtlZeroMemory(&srb, sizeof(srb));
6461
6462 srb.CdbLength = 12;
6463 srb.TimeOutValue = 20;
6464
6465 cdb->MECH_STATUS.OperationCode = SCSIOP_MECHANISM_STATUS;
6466 cdb->MECH_STATUS.AllocationLength[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
6467
6468 status = ScsiClassSendSrbSynchronous(DeviceObject,
6469 &srb,
6470 mechanicalStatusBuffer,
6471 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER),
6472 FALSE);
6473
6474
6475 if (status == STATUS_SUCCESS) {
6476
6477 //
6478 // Indicate number of slots available
6479 //
6480
6481 *DiscsPresent = mechanicalStatusBuffer->NumberAvailableSlots;
6482 if (*DiscsPresent > 1) {
6483 retVal = TRUE;
6484 } else {
6485
6486 //
6487 // If only one disc, no need for this driver.
6488 //
6489
6490 retVal = FALSE;
6491 }
6492 } else {
6493
6494 //
6495 // Device doesn't support this command.
6496 //
6497
6498 retVal = FALSE;
6499 }
6500
6501 ExFreePool(mechanicalStatusBuffer);
6502 }
6503
6504 return retVal;
6505 }
6506
6507 BOOLEAN
6508 NTAPI
6509 IsThisAMultiLunDevice(
6510 IN PDEVICE_OBJECT DeviceObject,
6511 IN PDEVICE_OBJECT PortDeviceObject
6512 )
6513 /*++
6514
6515 Routine Description:
6516
6517 This routine is called to determine whether a multi-lun
6518 device is present.
6519
6520 Arguments:
6521
6522 DeviceObject - Supplies the device object for the 'real' device.
6523
6524 Return Value:
6525
6526 TRUE - if a Multi-lun device is found.
6527
6528 --*/
6529 {
6530 PCHAR buffer;
6531 PSCSI_INQUIRY_DATA lunInfo;
6532 PSCSI_ADAPTER_BUS_INFO adapterInfo;
6533 PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
6534 PINQUIRYDATA inquiryData;
6535 ULONG scsiBus;
6536 NTSTATUS status;
6537 UCHAR lunCount = 0;
6538
6539 status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
6540
6541 if (!NT_SUCCESS(status)) {
6542 DebugPrint((1,"IsThisAMultiLunDevice: ScsiClassGetInquiryData failed\n"));
6543 return FALSE;
6544 }
6545
6546 adapterInfo = (PVOID) buffer;
6547
6548 //
6549 // For each SCSI bus this adapter supports ...
6550 //
6551
6552 for (scsiBus=0; scsiBus < adapterInfo->NumberOfBuses; scsiBus++) {
6553
6554 //
6555 // Get the SCSI bus scan data for this bus.
6556 //
6557
6558 lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
6559
6560 while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
6561
6562 inquiryData = (PVOID)lunInfo->InquiryData;
6563
6564 if ((lunInfo->PathId == deviceExtension->PathId) &&
6565 (lunInfo->TargetId == deviceExtension->TargetId) &&
6566 (inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE)) {
6567
6568 DebugPrint((1,"IsThisAMultiLunDevice: Vendor string is %.24s\n",
6569 inquiryData->VendorId));
6570
6571 //
6572 // If this device has more than one cdrom-type lun then we
6573 // won't support autoplay on it
6574 //
6575
6576 if (lunCount++) {
6577 ExFreePool(buffer);
6578 return TRUE;
6579 }
6580 }
6581
6582 //
6583 // Get next LunInfo.
6584 //
6585
6586 if (lunInfo->NextInquiryDataOffset == 0) {
6587 break;
6588 }
6589
6590 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
6591 }
6592 }
6593
6594 ExFreePool(buffer);
6595 return FALSE;
6596
6597 }
6598
6599 IO_COMPLETION_ROUTINE CdRomUpdateGeometryCompletion;
6600 NTSTATUS
6601 NTAPI
6602 CdRomUpdateGeometryCompletion(
6603 PDEVICE_OBJECT DeviceObject,
6604 PIRP Irp,
6605 PVOID Context
6606 )
6607
6608 /*++
6609
6610 Routine Description:
6611
6612 This routine andles the completion of the test unit ready irps
6613 used to determine if the media has changed. If the media has
6614 changed, this code signals the named event to wake up other
6615 system services that react to media change (aka AutoPlay).
6616
6617 Arguments:
6618
6619 DeviceObject - the object for the completion
6620 Irp - the IRP being completed
6621 Context - the SRB from the IRP
6622
6623 Return Value:
6624
6625 NTSTATUS
6626
6627 --*/
6628
6629 {
6630 PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK) Context;
6631 PREAD_CAPACITY_DATA readCapacityBuffer;
6632 PDEVICE_EXTENSION deviceExtension;
6633 PIO_STACK_LOCATION irpStack;
6634 NTSTATUS status;
6635 BOOLEAN retry;
6636 ULONG_PTR retryCount;
6637 ULONG lastSector;
6638 PIRP originalIrp;
6639 PCDROM_DATA cddata;
6640
6641 //
6642 // Get items saved in the private IRP stack location.
6643 //
6644
6645 irpStack = IoGetCurrentIrpStackLocation(Irp);
6646 retryCount = (ULONG_PTR) irpStack->Parameters.Others.Argument1;
6647 originalIrp = (PIRP) irpStack->Parameters.Others.Argument2;
6648
6649 if (!DeviceObject) {
6650 DeviceObject = irpStack->DeviceObject;
6651 }
6652 ASSERT(DeviceObject);
6653
6654 deviceExtension = DeviceObject->DeviceExtension;
6655 cddata = (PCDROM_DATA) (deviceExtension + 1);
6656 readCapacityBuffer = srb->DataBuffer;
6657
6658 if ((NT_SUCCESS(Irp->IoStatus.Status)) && (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)) {
6659 PFOUR_BYTE from;
6660 PFOUR_BYTE to;
6661
6662 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] successful completion of buddy-irp %lx\n", originalIrp, Irp));
6663 //
6664 // Copy sector size from read capacity buffer to device extension
6665 // in reverse byte order.
6666 //
6667
6668 from = (PFOUR_BYTE) &readCapacityBuffer->BytesPerBlock;
6669 to = (PFOUR_BYTE) &deviceExtension->DiskGeometry->Geometry.BytesPerSector;
6670 to->Byte0 = from->Byte3;
6671 to->Byte1 = from->Byte2;
6672 to->Byte2 = from->Byte1;
6673 to->Byte3 = from->Byte0;
6674
6675 //
6676 // Using the new BytesPerBlock, calculate and store the SectorShift.
6677 //
6678
6679 WHICH_BIT(deviceExtension->DiskGeometry->Geometry.BytesPerSector, deviceExtension->SectorShift);
6680
6681 //
6682 // Copy last sector in reverse byte order.
6683 //
6684
6685 from = (PFOUR_BYTE) &readCapacityBuffer->LogicalBlockAddress;
6686 to = (PFOUR_BYTE) &lastSector;
6687 to->Byte0 = from->Byte3;
6688 to->Byte1 = from->Byte2;
6689 to->Byte2 = from->Byte1;
6690 to->Byte3 = from->Byte0;
6691 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
6692
6693 //
6694 // Calculate number of cylinders.
6695 //
6696
6697 deviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64));
6698 deviceExtension->PartitionLength.QuadPart =
6699 (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
6700 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia;
6701
6702 //
6703 // Assume sectors per track are 32;
6704 //
6705
6706 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack = 32;
6707
6708 //
6709 // Assume tracks per cylinder (number of heads) is 64.
6710 //
6711
6712 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder = 64;
6713
6714 } else {
6715
6716 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] unsuccessful completion of buddy-irp %lx (status - %lx)\n", originalIrp, Irp, Irp->IoStatus.Status));
6717
6718 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
6719 ScsiClassReleaseQueue(DeviceObject);
6720 }
6721
6722 retry = ScsiClassInterpretSenseInfo(DeviceObject,
6723 srb,
6724 IRP_MJ_SCSI,
6725 0,
6726 retryCount,
6727 &status);
6728 if (retry) {
6729 retryCount--;
6730 if (retryCount) {
6731 PCDB cdb;
6732
6733 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] Retrying request %lx .. thread is %lx\n", originalIrp, Irp, Irp->Tail.Overlay.Thread));
6734 //
6735 // set up a one shot timer to get this process started over
6736 //
6737
6738 irpStack->Parameters.Others.Argument1 = (PVOID) retryCount;
6739 irpStack->Parameters.Others.Argument2 = (PVOID) originalIrp;
6740 irpStack->Parameters.Others.Argument3 = (PVOID) 2;
6741
6742 //
6743 // Setup the IRP to be submitted again in the timer routine.
6744 //
6745
6746 irpStack = IoGetNextIrpStackLocation(Irp);
6747 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
6748 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
6749 irpStack->Parameters.Scsi.Srb = srb;
6750 IoSetCompletionRoutine(Irp,
6751 CdRomUpdateGeometryCompletion,
6752 srb,
6753 TRUE,
6754 TRUE,
6755 TRUE);
6756
6757 //
6758 // Set up the SRB for read capacity.
6759 //
6760
6761 srb->CdbLength = 10;
6762 srb->TimeOutValue = deviceExtension->TimeOutValue;
6763 srb->SrbStatus = srb->ScsiStatus = 0;
6764 srb->NextSrb = 0;
6765 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
6766 srb->PathId = deviceExtension->PathId;
6767 srb->TargetId = deviceExtension->TargetId;
6768 srb->Lun = deviceExtension->Lun;
6769 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
6770 srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
6771 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
6772
6773 //
6774 // Set up the CDB
6775 //
6776
6777 cdb = (PCDB) &srb->Cdb[0];
6778 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
6779 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
6780
6781 //
6782 // Requests queued onto this list will be sent to the
6783 // lower level driver during CdRomTickHandler
6784 //
6785
6786 ExInterlockedInsertHeadList(&cddata->TimerIrpList,
6787 &Irp->Tail.Overlay.ListEntry,
6788 &cddata->TimerIrpSpinLock);
6789
6790 return STATUS_MORE_PROCESSING_REQUIRED;
6791 } else {
6792
6793 //
6794 // This has been bounced for a number of times. Error the
6795 // original request.
6796 //
6797
6798 originalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
6799 RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY_EX));
6800 deviceExtension->DiskGeometry->Geometry.BytesPerSector = 2048;
6801 deviceExtension->SectorShift = 11;
6802 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
6803 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia;
6804 }
6805 } else {
6806
6807 //
6808 // Set up reasonable defaults
6809 //
6810
6811 RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY_EX));
6812 deviceExtension->DiskGeometry->Geometry.BytesPerSector = 2048;
6813 deviceExtension->SectorShift = 11;
6814 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
6815 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia;
6816 }
6817 }
6818
6819 //
6820 // Free resources held.
6821 //
6822
6823 ExFreePool(srb->SenseInfoBuffer);
6824 ExFreePool(srb->DataBuffer);
6825 ExFreePool(srb);
6826 if (Irp->MdlAddress) {
6827 IoFreeMdl(Irp->MdlAddress);
6828 }
6829 IoFreeIrp(Irp);
6830 if (originalIrp->Tail.Overlay.Thread) {
6831
6832 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] completing original IRP\n", originalIrp));
6833 IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
6834
6835 } else {
6836 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] original irp has "
6837 "no thread\n",
6838 originalIrp
6839 ));
6840 }
6841
6842 //
6843 // It's now safe to either start the next request or let the waiting ioctl
6844 // request continue along it's merry way
6845 //
6846
6847 IoStartNextPacket(DeviceObject, FALSE);
6848
6849 return STATUS_MORE_PROCESSING_REQUIRED;
6850 }
6851
6852 NTSTATUS
6853 NTAPI
6854 CdRomUpdateCapacity(
6855 IN PDEVICE_EXTENSION DeviceExtension,
6856 IN PIRP IrpToComplete,
6857 IN OPTIONAL PKEVENT IoctlEvent
6858 )
6859
6860 /*++
6861
6862 Routine Description:
6863
6864 This routine updates the capacity of the disk as recorded in the device extension.
6865 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
6866 when a media change has occurred and it is necessary to determine the capacity of the
6867 new media prior to the next access.
6868
6869 Arguments:
6870
6871 DeviceExtension - the device to update
6872 IrpToComplete - the request that needs to be completed when done.
6873
6874 Return Value:
6875
6876 NTSTATUS
6877
6878 --*/
6879
6880 {
6881 PCDB cdb;
6882 PIRP irp;
6883 PSCSI_REQUEST_BLOCK srb;
6884 PREAD_CAPACITY_DATA capacityBuffer;
6885 PIO_STACK_LOCATION irpStack;
6886 PUCHAR senseBuffer;
6887
6888 irp = IoAllocateIrp((CCHAR)(DeviceExtension->DeviceObject->StackSize+1),
6889 FALSE);
6890
6891 if (irp) {
6892
6893 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
6894 if (srb) {
6895 capacityBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
6896 sizeof(READ_CAPACITY_DATA));
6897
6898 if (capacityBuffer) {
6899
6900
6901 senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
6902
6903 if (senseBuffer) {
6904
6905 irp->MdlAddress = IoAllocateMdl(capacityBuffer,
6906 sizeof(READ_CAPACITY_DATA),
6907 FALSE,
6908 FALSE,
6909 (PIRP) NULL);
6910
6911 if (irp->MdlAddress) {
6912
6913 //
6914 // Have all resources. Set up the IRP to send for the capacity.
6915 //
6916
6917 IoSetNextIrpStackLocation(irp);
6918 irp->IoStatus.Status = STATUS_SUCCESS;
6919 irp->IoStatus.Information = 0;
6920 irp->Flags = 0;
6921 irp->UserBuffer = NULL;
6922
6923 //
6924 // Save the device object and retry count in a private stack location.
6925 //
6926
6927 irpStack = IoGetCurrentIrpStackLocation(irp);
6928 irpStack->DeviceObject = DeviceExtension->DeviceObject;
6929 irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
6930 irpStack->Parameters.Others.Argument2 = (PVOID) IrpToComplete;
6931
6932 //
6933 // Construct the IRP stack for the lower level driver.
6934 //
6935
6936 irpStack = IoGetNextIrpStackLocation(irp);
6937 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
6938 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
6939 irpStack->Parameters.Scsi.Srb = srb;
6940 IoSetCompletionRoutine(irp,
6941 CdRomUpdateGeometryCompletion,
6942 srb,
6943 TRUE,
6944 TRUE,
6945 TRUE);
6946 //
6947 // Prepare the MDL
6948 //
6949
6950 MmBuildMdlForNonPagedPool(irp->MdlAddress);
6951
6952
6953 //
6954 // Set up the SRB for read capacity.
6955 //
6956
6957 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
6958 RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);
6959 srb->CdbLength = 10;
6960 srb->TimeOutValue = DeviceExtension->TimeOutValue;
6961 srb->SrbStatus = srb->ScsiStatus = 0;
6962 srb->NextSrb = 0;
6963 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
6964 srb->PathId = DeviceExtension->PathId;
6965 srb->TargetId = DeviceExtension->TargetId;
6966 srb->Lun = DeviceExtension->Lun;
6967 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
6968 srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
6969 srb->DataBuffer = capacityBuffer;
6970 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
6971 srb->OriginalRequest = irp;
6972 srb->SenseInfoBuffer = senseBuffer;
6973 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
6974
6975 //
6976 // Set up the CDB
6977 //
6978
6979 cdb = (PCDB) &srb->Cdb[0];
6980 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
6981 cdb->CDB10.LogicalUnitNumber = DeviceExtension->Lun;
6982
6983 //
6984 // Set the return value in the IRP that will be completed
6985 // upon completion of the read capacity.
6986 //
6987
6988 IrpToComplete->IoStatus.Status = STATUS_VERIFY_REQUIRED;
6989 IoMarkIrpPending(IrpToComplete);
6990
6991 IoCallDriver(DeviceExtension->PortDeviceObject, irp);
6992
6993 //
6994 // status is not checked because the completion routine for this
6995 // IRP will always get called and it will free the resources.
6996 //
6997
6998 return STATUS_PENDING;
6999
7000 } else {
7001 ExFreePool(senseBuffer);
7002 ExFreePool(capacityBuffer);
7003 ExFreePool(srb);
7004 IoFreeIrp(irp);
7005 }
7006 } else {
7007 ExFreePool(capacityBuffer);
7008 ExFreePool(srb);
7009 IoFreeIrp(irp);
7010 }
7011 } else {
7012 ExFreePool(srb);
7013 IoFreeIrp(irp);
7014 }
7015 } else {
7016 IoFreeIrp(irp);
7017 }
7018 }
7019
7020 return STATUS_INSUFFICIENT_RESOURCES;
7021 }
7022
7023 NTSTATUS
7024 NTAPI
7025 CdRomClassIoctlCompletion(
7026 IN PDEVICE_OBJECT DeviceObject,
7027 IN PIRP Irp,
7028 IN PVOID Context
7029 )
7030
7031 /*++
7032
7033 Routine Description:
7034
7035 This routine signals the event used by CdRomDeviceControl to synchronize
7036 class driver (and lower level driver) ioctls with cdrom's startio routine.
7037 The irp completion is short-circuited so that CdRomDeviceControl can
7038 reissue it once it wakes up.
7039
7040 Arguments:
7041
7042 DeviceObject - the device object
7043 Irp - the request we are synchronizing
7044 Context - a PKEVENT that we need to signal
7045
7046 Return Value:
7047
7048 NTSTATUS
7049
7050 --*/
7051
7052 {
7053 PKEVENT syncEvent = (PKEVENT) Context;
7054
7055 DebugPrint((2, "CdRomClassIoctlCompletion: setting event for irp %#08lx\n",
7056 Irp
7057 ));
7058
7059 KeSetEvent(syncEvent, IO_DISK_INCREMENT, FALSE);
7060
7061 return STATUS_MORE_PROCESSING_REQUIRED;
7062 }