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