ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

cdrom.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Storage Stack
00003  * LICENSE:         DDK - see license.txt in the root dir
00004  * FILE:            drivers/storage/cdrom/cdrom.c
00005  * PURPOSE:         CDROM driver
00006  * PROGRAMMERS:     Based on a source code sample from Microsoft NT4 DDK
00007  */
00008 
00009 #include "precomp.h"
00010 
00011 //#define NDEBUG
00012 #include <debug.h>
00013 
00014 #define CDB12GENERIC_LENGTH 12
00015 
00016 typedef struct _XA_CONTEXT {
00017 
00018     //
00019     // Pointer to the device object.
00020     //
00021 
00022     PDEVICE_OBJECT DeviceObject;
00023 
00024     //
00025     // Pointer to the original request when
00026     // a mode select must be sent.
00027     //
00028 
00029     PIRP OriginalRequest;
00030 
00031     //
00032     // Pointer to the mode select srb.
00033     //
00034 
00035     PSCSI_REQUEST_BLOCK Srb;
00036 } XA_CONTEXT, *PXA_CONTEXT;
00037 
00038 typedef struct _ERROR_RECOVERY_DATA {
00039     MODE_PARAMETER_HEADER   Header;
00040     MODE_PARAMETER_BLOCK BlockDescriptor;
00041     MODE_READ_RECOVERY_PAGE ReadRecoveryPage;
00042 } ERROR_RECOVERY_DATA, *PERROR_RECOVERY_DATA;
00043 
00044 typedef struct _ERROR_RECOVERY_DATA10 {
00045     MODE_PARAMETER_HEADER10 Header10;
00046     MODE_PARAMETER_BLOCK BlockDescriptor10;
00047     MODE_READ_RECOVERY_PAGE ReadRecoveryPage10;
00048 } ERROR_RECOVERY_DATA10, *PERROR_RECOVERY_DATA10;
00049 
00050 //
00051 // CdRom specific addition to device extension.
00052 //
00053 
00054 typedef struct _CDROM_DATA {
00055 
00056     //
00057     // Indicates whether an audio play operation
00058     // is currently being performed.
00059     //
00060 
00061     BOOLEAN PlayActive;
00062 
00063     //
00064     // Indicates whether the blocksize used for user data
00065     // is 2048 or 2352.
00066     //
00067 
00068     BOOLEAN RawAccess;
00069 
00070     //
00071     // Indicates whether 6 or 10 byte mode sense/select
00072     // should be used.
00073     //
00074 
00075     USHORT XAFlags;
00076 
00077     //
00078     // Storage for the error recovery page. This is used
00079     // as an easy method to switch block sizes.
00080     //
00081 
00082     union {
00083         ERROR_RECOVERY_DATA u1;
00084         ERROR_RECOVERY_DATA10 u2;
00085     };
00086 
00087 
00088     //
00089     // Pointer to the original irp for the raw read.
00090     //
00091 
00092     PIRP SavedReadIrp;
00093 
00094     //
00095     // Used to protect accesses to the RawAccess flag.
00096     //
00097 
00098     KSPIN_LOCK FormSpinLock;
00099 
00100     //
00101     // Even if media change support is requested, there are some devices
00102     // that are not supported.  This flag will indicate that such a device
00103     // is present when it is FALSE.
00104     //
00105 
00106     BOOLEAN MediaChangeSupported;
00107 
00108     //
00109     // The media change event is being supported.  The media change timer
00110     // should be running whenever this is true.
00111     //
00112 
00113     BOOLEAN MediaChange;
00114 
00115     //
00116     // The timer value to support media change events.  This is a countdown
00117     // value used to determine when to poll the device for a media change.
00118     // The max value for the timer is 255 seconds.
00119     //
00120 
00121     UCHAR MediaChangeCountDown;
00122 
00123 #if DBG
00124     //
00125     // Second timer to keep track of how long the media change IRP has been
00126     // in use.  If this value exceeds the timeout (#defined) then we should
00127     // print out a message to the user and set the MediaChangeIrpLost flag
00128     //
00129 
00130     SHORT MediaChangeIrpTimeInUse;
00131 
00132     //
00133     // Set by CdRomTickHandler when we determine that the media change irp has
00134     // been lost
00135     //
00136 
00137     BOOLEAN MediaChangeIrpLost;
00138 #endif
00139 
00140     UCHAR PadReserve; // use this for new flags.
00141 
00142     //
00143     // An IRP is allocated and kept for the duration that media change
00144     // detection is in effect.  If this is NULL and MediaChange is TRUE,
00145     // the detection is in progress.  This should always be NULL when
00146     // MediaChange is FALSE.
00147     //
00148 
00149     PIRP MediaChangeIrp;
00150 
00151     //
00152     // The timer work list is a collection of IRPS that are prepared for
00153     // submission, but need to allow some time to pass before they are
00154     // run.
00155     //
00156 
00157     LIST_ENTRY TimerIrpList;
00158     KSPIN_LOCK TimerIrpSpinLock;
00159 
00160 } CDROM_DATA, *PCDROM_DATA;
00161 
00162 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA)
00163 #define SCSI_CDROM_TIMEOUT          10
00164 #define SCSI_CHANGER_BONUS_TIMEOUT  10
00165 #define HITACHI_MODE_DATA_SIZE      12
00166 #define MODE_DATA_SIZE              64
00167 #define RAW_SECTOR_SIZE           2352
00168 #define COOKED_SECTOR_SIZE        2048
00169 #define MEDIA_CHANGE_DEFAULT_TIME    4
00170 #define CDROM_SRB_LIST_SIZE          4
00171 
00172 
00173 #if DBG
00174 
00175 //
00176 // Used to detect the loss of the autorun irp.  The driver prints out a message
00177 // (debug level 0) if this timeout ever occurs
00178 //
00179 #define MEDIA_CHANGE_TIMEOUT_TIME  300
00180 
00181 #endif
00182 
00183 #define PLAY_ACTIVE(DeviceExtension) (((PCDROM_DATA)(DeviceExtension + 1))->PlayActive)
00184 
00185 #define MSF_TO_LBA(Minutes,Seconds,Frames) \
00186                 (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150))
00187 
00188 #define LBA_TO_MSF(Lba,Minutes,Seconds,Frames)               \
00189 {                                                            \
00190     (Minutes) = (UCHAR)(Lba  / (60 * 75));                   \
00191     (Seconds) = (UCHAR)((Lba % (60 * 75)) / 75);             \
00192     (Frames)  = (UCHAR)((Lba % (60 * 75)) % 75);             \
00193 }
00194 
00195 #define DEC_TO_BCD(x) (((x / 10) << 4) + (x % 10))
00196 
00197 //
00198 // Define flags for XA, CDDA, and Mode Select/Sense
00199 //
00200 
00201 #define XA_USE_6_BYTE             0x01
00202 #define XA_USE_10_BYTE            0x02
00203 #define XA_USE_READ_CD            0x04
00204 #define XA_NOT_SUPPORTED          0x08
00205 
00206 #define PLEXTOR_CDDA              0x10
00207 #define NEC_CDDA                  0x20
00208 
00209 //
00210 // Sector types for READ_CD
00211 //
00212 
00213 #define ANY_SECTOR                0
00214 #define CD_DA_SECTOR              1
00215 #define YELLOW_MODE1_SECTOR       2
00216 #define YELLOW_MODE2_SECTOR       3
00217 #define FORM2_MODE1_SECTOR        4
00218 #define FORM2_MODE2_SECTOR        5
00219 
00220 
00221 #ifdef POOL_TAGGING
00222 #ifdef ExAllocatePool
00223 #undef ExAllocatePool
00224 #endif
00225 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'CscS')
00226 #endif
00227 
00228 NTSTATUS
00229 NTAPI
00230 DriverEntry(
00231     IN PDRIVER_OBJECT DriverObject,
00232     IN PUNICODE_STRING RegistryPath
00233     );
00234 
00235 BOOLEAN
00236 NTAPI
00237 ScsiCdRomFindDevices(
00238     IN PDRIVER_OBJECT DriverObject,
00239     IN PUNICODE_STRING RegistryPath,
00240     IN PCLASS_INIT_DATA InitializationData,
00241     IN PDEVICE_OBJECT PortDeviceObject,
00242     IN ULONG PortNumber
00243     );
00244 
00245 NTSTATUS
00246 NTAPI
00247 ScsiCdRomOpenClose(
00248     IN PDEVICE_OBJECT DeviceObject,
00249     IN PIRP Irp
00250     );
00251 
00252 NTSTATUS
00253 NTAPI
00254 ScsiCdRomReadVerification(
00255     IN PDEVICE_OBJECT DeviceObject,
00256     IN PIRP Irp
00257     );
00258 
00259 NTSTATUS
00260 NTAPI
00261 ScsiCdRomSwitchMode(
00262     IN PDEVICE_OBJECT DeviceObject,
00263     IN ULONG SectorSize,
00264     IN PIRP  OriginalRequest
00265     );
00266 
00267 NTSTATUS
00268 NTAPI
00269 CdRomDeviceControl(
00270     IN PDEVICE_OBJECT DeviceObject,
00271     IN PIRP Irp
00272     );
00273 
00274 IO_COMPLETION_ROUTINE CdRomDeviceControlCompletion;
00275 NTSTATUS
00276 NTAPI
00277 CdRomDeviceControlCompletion(
00278     IN PDEVICE_OBJECT DeviceObject,
00279     IN PIRP Irp,
00280     IN PVOID Context
00281     );
00282 
00283 IO_COMPLETION_ROUTINE CdRomSetVolumeIntermediateCompletion;
00284 NTSTATUS
00285 NTAPI
00286 CdRomSetVolumeIntermediateCompletion(
00287     IN PDEVICE_OBJECT DeviceObject,
00288     IN PIRP Irp,
00289     IN PVOID Context
00290     );
00291 
00292 IO_COMPLETION_ROUTINE CdRomSwitchModeCompletion;
00293 NTSTATUS
00294 NTAPI
00295 CdRomSwitchModeCompletion(
00296     IN PDEVICE_OBJECT DeviceObject,
00297     IN PIRP Irp,
00298     IN PVOID Context
00299     );
00300 
00301 IO_COMPLETION_ROUTINE CdRomXACompletion;
00302 NTSTATUS
00303 NTAPI
00304 CdRomXACompletion(
00305     IN PDEVICE_OBJECT DeviceObject,
00306     IN PIRP Irp,
00307     IN PVOID Context
00308     );
00309 
00310 IO_COMPLETION_ROUTINE CdRomClassIoctlCompletion;
00311 NTSTATUS
00312 NTAPI
00313 CdRomClassIoctlCompletion(
00314     IN PDEVICE_OBJECT DeviceObject,
00315     IN PIRP Irp,
00316     IN PVOID Context
00317     );
00318 
00319 VOID
00320 NTAPI
00321 ScsiCdRomStartIo(
00322     IN PDEVICE_OBJECT DeviceObject,
00323     IN PIRP Irp
00324     );
00325 
00326 VOID
00327 NTAPI
00328 CdRomTickHandler(
00329     IN PDEVICE_OBJECT DeviceObject,
00330     IN PVOID Context
00331     );
00332 
00333 BOOLEAN
00334 NTAPI
00335 CdRomCheckRegistryForMediaChangeValue(
00336     IN PUNICODE_STRING RegistryPath,
00337     IN ULONG DeviceNumber
00338     );
00339 
00340 NTSTATUS
00341 NTAPI
00342 CdRomUpdateCapacity(
00343     IN PDEVICE_EXTENSION DeviceExtension,
00344     IN PIRP IrpToComplete,
00345     IN OPTIONAL PKEVENT IoctlEvent
00346     );
00347 
00348 NTSTATUS
00349 NTAPI
00350 CreateCdRomDeviceObject(
00351     IN PDRIVER_OBJECT DriverObject,
00352     IN PDEVICE_OBJECT PortDeviceObject,
00353     IN ULONG PortNumber,
00354     IN PULONG DeviceCount,
00355     PIO_SCSI_CAPABILITIES PortCapabilities,
00356     IN PSCSI_INQUIRY_DATA LunInfo,
00357     IN PCLASS_INIT_DATA   InitializationData,
00358     IN PUNICODE_STRING    RegistryPath
00359     );
00360 
00361 VOID
00362 NTAPI
00363 ScanForSpecial(
00364     PDEVICE_OBJECT DeviceObject,
00365     PINQUIRYDATA InquiryData,
00366     PIO_SCSI_CAPABILITIES PortCapabilities
00367     );
00368 
00369 BOOLEAN
00370 NTAPI
00371 CdRomIsPlayActive(
00372     IN PDEVICE_OBJECT DeviceObject
00373     );
00374 
00375 VOID
00376 NTAPI
00377 HitachProcessError(
00378     PDEVICE_OBJECT DeviceObject,
00379     PSCSI_REQUEST_BLOCK Srb,
00380     NTSTATUS *Status,
00381     BOOLEAN *Retry
00382     );
00383 
00384 IO_COMPLETION_ROUTINE ToshibaProcessErrorCompletion;
00385 VOID
00386 NTAPI
00387 ToshibaProcessError(
00388     PDEVICE_OBJECT DeviceObject,
00389     PSCSI_REQUEST_BLOCK Srb,
00390     NTSTATUS *Status,
00391     BOOLEAN *Retry
00392     );
00393 
00394 BOOLEAN
00395 NTAPI
00396 IsThisAnAtapiChanger(
00397     IN  PDEVICE_OBJECT DeviceObject,
00398     OUT PULONG         DiscsPresent
00399     );
00400 
00401 BOOLEAN
00402 NTAPI
00403 IsThisASanyo(
00404     IN  PDEVICE_OBJECT DeviceObject,
00405     IN  UCHAR          PathId,
00406     IN  UCHAR          TargetId
00407     );
00408 
00409 BOOLEAN
00410 NTAPI
00411 IsThisAMultiLunDevice(
00412     IN PDEVICE_OBJECT DeviceObject,
00413     IN PDEVICE_OBJECT PortDeviceObject
00414     );
00415 
00416 VOID
00417 NTAPI
00418 CdRomCreateNamedEvent(
00419     IN PDEVICE_EXTENSION DeviceExtension,
00420     IN ULONG DeviceNumber
00421     );
00422 
00423 #ifdef _PPC_
00424 NTSTATUS
00425 FindScsiAdapter (
00426     IN HANDLE KeyHandle,
00427     IN UNICODE_STRING ScsiUnicodeString[],
00428     OUT PUCHAR IntermediateController
00429     );
00430 #endif
00431 
00432 #ifdef ALLOC_PRAGMA
00433 #pragma alloc_text(PAGE, DriverEntry)
00434 #pragma alloc_text(PAGE, ScsiCdRomFindDevices)
00435 #pragma alloc_text(PAGE, CreateCdRomDeviceObject)
00436 #pragma alloc_text(PAGE, ScanForSpecial)
00437 //#pragma alloc_text(PAGE, CdRomDeviceControl)
00438 #pragma alloc_text(PAGE, HitachProcessError)
00439 #pragma alloc_text(PAGE, CdRomIsPlayActive)
00440 #pragma alloc_text(PAGE, ScsiCdRomReadVerification)
00441 #pragma alloc_text(INIT, CdRomCheckRegistryForMediaChangeValue)
00442 #pragma alloc_text(INIT, IsThisAnAtapiChanger)
00443 #pragma alloc_text(INIT, IsThisASanyo)
00444 #pragma alloc_text(INIT, IsThisAMultiLunDevice)
00445 #pragma alloc_text(INIT, CdRomCreateNamedEvent)
00446 #ifdef _PPC_
00447 #pragma alloc_text(PAGE, FindScsiAdapter)
00448 #endif
00449 #endif
00450 
00451 ULONG NoLoad = 0;
00452 
00453 NTSTATUS
00454 NTAPI
00455 DriverEntry(
00456     IN PDRIVER_OBJECT DriverObject,
00457     IN PUNICODE_STRING RegistryPath
00458     )
00459 
00460 /*++
00461 
00462 Routine Description:
00463 
00464     This routine initializes the cdrom class driver.
00465 
00466 Arguments:
00467 
00468     DriverObject - Pointer to driver object created by system.
00469 
00470     RegistryPath - Pointer to the name of the services node for this driver.
00471 
00472 Return Value:
00473 
00474     The function value is the final status from the initialization operation.
00475 
00476 --*/
00477 
00478 {
00479     CLASS_INIT_DATA InitializationData;
00480 
00481     if(NoLoad) {
00482         return STATUS_NO_SUCH_DEVICE;
00483     }
00484 
00485     //
00486     // Zero InitData
00487     //
00488 
00489     RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
00490 
00491     //
00492     // Set sizes
00493     //
00494 
00495     InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
00496     InitializationData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
00497 
00498     InitializationData.DeviceType = FILE_DEVICE_CD_ROM;
00499     InitializationData.DeviceCharacteristics = FILE_REMOVABLE_MEDIA | FILE_READ_ONLY_DEVICE;
00500 
00501     //
00502     // Set entry points
00503     //
00504 
00505     InitializationData.ClassReadWriteVerification = ScsiCdRomReadVerification;
00506     InitializationData.ClassDeviceControl = CdRomDeviceControl;
00507     InitializationData.ClassFindDevices = ScsiCdRomFindDevices;
00508     InitializationData.ClassShutdownFlush = NULL;
00509     InitializationData.ClassCreateClose = NULL;
00510     InitializationData.ClassStartIo = ScsiCdRomStartIo;
00511 
00512     //
00513     // Call the class init routine
00514     //
00515 
00516     return ScsiClassInitialize( DriverObject, RegistryPath, &InitializationData);
00517 
00518 } // end DriverEntry()
00519 
00520 BOOLEAN
00521 NTAPI
00522 ScsiCdRomFindDevices(
00523     IN PDRIVER_OBJECT DriverObject,
00524     IN PUNICODE_STRING RegistryPath,
00525     IN PCLASS_INIT_DATA InitializationData,
00526     IN PDEVICE_OBJECT PortDeviceObject,
00527     IN ULONG PortNumber
00528     )
00529 
00530 /*++
00531 
00532 Routine Description:
00533 
00534     Connect to SCSI port driver. Get adapter capabilities and
00535     SCSI bus configuration information. Search inquiry data
00536     for CDROM devices to process.
00537 
00538 Arguments:
00539 
00540     DriverObject - CDROM class driver object.
00541     PortDeviceObject - SCSI port driver device object.
00542     PortNumber - The system ordinal for this scsi adapter.
00543 
00544 Return Value:
00545 
00546     TRUE if CDROM device present on this SCSI adapter.
00547 
00548 --*/
00549 
00550 {
00551     PIO_SCSI_CAPABILITIES portCapabilities;
00552     PULONG cdRomCount;
00553     PCHAR buffer;
00554     PSCSI_INQUIRY_DATA lunInfo;
00555     PSCSI_ADAPTER_BUS_INFO  adapterInfo;
00556     PINQUIRYDATA inquiryData;
00557     ULONG scsiBus;
00558     NTSTATUS status;
00559     BOOLEAN foundDevice = FALSE;
00560 
00561     //
00562     // Call port driver to get adapter capabilities.
00563     //
00564 
00565     status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
00566 
00567     if (!NT_SUCCESS(status)) {
00568         DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
00569         return foundDevice;
00570     }
00571 
00572     //
00573     // Call port driver to get inquiry information to find cdroms.
00574     //
00575 
00576     status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
00577 
00578     if (!NT_SUCCESS(status)) {
00579         DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
00580         return foundDevice;
00581     }
00582 
00583     //
00584     // Get the address of the count of the number of cdroms already initialized.
00585     //
00586 
00587     cdRomCount = &IoGetConfigurationInformation()->CdRomCount;
00588     adapterInfo = (PVOID) buffer;
00589 
00590     //
00591     // For each SCSI bus this adapter supports ...
00592     //
00593 
00594     for (scsiBus=0; scsiBus < adapterInfo->NumberOfBuses; scsiBus++) {
00595 
00596         //
00597         // Get the SCSI bus scan data for this bus.
00598         //
00599 
00600         lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
00601 
00602         //
00603         // Search list for unclaimed disk devices.
00604         //
00605 
00606         while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
00607 
00608             inquiryData = (PVOID)lunInfo->InquiryData;
00609 
00610             if ((inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
00611                 (inquiryData->DeviceTypeQualifier == 0) &&
00612                 (!lunInfo->DeviceClaimed)) {
00613 
00614                 DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n",
00615                             inquiryData->VendorId));
00616 
00617                 //
00618                 // Create device objects for cdrom
00619                 //
00620 
00621                 status = CreateCdRomDeviceObject(DriverObject,
00622                                                  PortDeviceObject,
00623                                                  PortNumber,
00624                                                  cdRomCount,
00625                                                  portCapabilities,
00626                                                  lunInfo,
00627                                                  InitializationData,
00628                                                  RegistryPath);
00629 
00630                 if (NT_SUCCESS(status)) {
00631 
00632                     //
00633                     // Increment system cdrom device count.
00634                     //
00635 
00636                     (*cdRomCount)++;
00637 
00638                     //
00639                     // Indicate that a cdrom device was found.
00640                     //
00641 
00642                     foundDevice = TRUE;
00643                 }
00644             }
00645 
00646             //
00647             // Get next LunInfo.
00648             //
00649 
00650             if (lunInfo->NextInquiryDataOffset == 0) {
00651                 break;
00652             }
00653 
00654             lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
00655         }
00656     }
00657 
00658     ExFreePool(buffer);
00659 
00660 
00661     return foundDevice;
00662 
00663 } // end FindScsiCdRoms()
00664 
00665 VOID
00666 NTAPI
00667 CdRomCreateNamedEvent(
00668     IN PDEVICE_EXTENSION DeviceExtension,
00669     IN ULONG DeviceNumber
00670     )
00671 
00672 /*++
00673 
00674 Routine Description:
00675 
00676     Create the named synchronization event for notification of media change
00677     events to the system.  The event is reset before this function returns.
00678 
00679 Arguments:
00680 
00681     DeviceExtension - the device extension pointer for storage of the event pointer.
00682 
00683 Return Value:
00684 
00685     None.
00686 
00687 --*/
00688 
00689 {
00690     UNICODE_STRING    unicodeString;
00691     OBJECT_ATTRIBUTES objectAttributes;
00692     CCHAR             eventNameBuffer[MAXIMUM_FILENAME_LENGTH];
00693     STRING            eventNameString;
00694     HANDLE            handle;
00695     NTSTATUS          status;
00696 
00697 
00698     sprintf(eventNameBuffer,"\\Device\\MediaChangeEvent%ld",
00699             DeviceNumber);
00700 
00701     RtlInitString(&eventNameString,
00702                   eventNameBuffer);
00703 
00704     status = RtlAnsiStringToUnicodeString(&unicodeString,
00705                                           &eventNameString,
00706                                           TRUE);
00707 
00708     if (!NT_SUCCESS(status)) {
00709         return;
00710     }
00711 
00712     InitializeObjectAttributes(&objectAttributes,
00713                                &unicodeString,
00714                                OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
00715                                NULL,
00716                                NULL);
00717 
00718     DeviceExtension->MediaChangeEvent = IoCreateSynchronizationEvent(&unicodeString,
00719                                                                      &handle);
00720     DeviceExtension->MediaChangeEventHandle = handle;
00721 
00722     KeClearEvent(DeviceExtension->MediaChangeEvent);
00723 
00724     RtlFreeUnicodeString(&unicodeString);
00725 }
00726 
00727 NTSTATUS
00728 NTAPI
00729 CreateCdRomDeviceObject(
00730     IN PDRIVER_OBJECT DriverObject,
00731     IN PDEVICE_OBJECT PortDeviceObject,
00732     IN ULONG          PortNumber,
00733     IN PULONG         DeviceCount,
00734     IN PIO_SCSI_CAPABILITIES PortCapabilities,
00735     IN PSCSI_INQUIRY_DATA LunInfo,
00736     IN PCLASS_INIT_DATA   InitializationData,
00737     IN PUNICODE_STRING    RegistryPath
00738     )
00739 
00740 /*++
00741 
00742 Routine Description:
00743 
00744     This routine creates an object for the device and then calls the
00745     SCSI port driver for media capacity and sector size.
00746 
00747 Arguments:
00748 
00749     DriverObject - Pointer to driver object created by system.
00750     PortDeviceObject - to connect to SCSI port driver.
00751     DeviceCount - Number of previously installed CDROMs.
00752     PortCapabilities - Pointer to structure returned by SCSI port
00753         driver describing adapter capabilites (and limitations).
00754     LunInfo - Pointer to configuration information for this device.
00755 
00756 Return Value:
00757 
00758     NTSTATUS
00759 
00760 --*/
00761 {
00762     CHAR ntNameBuffer[64];
00763     NTSTATUS status;
00764     BOOLEAN changerDevice;
00765     SCSI_REQUEST_BLOCK srb;
00766     ULONG          length;
00767     PCDROM_DATA    cddata;
00768     PCDB           cdb;
00769     PVOID          senseData = NULL;
00770     PDEVICE_OBJECT deviceObject = NULL;
00771     PDEVICE_EXTENSION deviceExtension = NULL;
00772     PUCHAR         buffer;
00773     ULONG          bps;
00774     ULONG          lastBit;
00775     ULONG          timeOut;
00776     BOOLEAN        srbListInitialized = FALSE;
00777 
00778     //
00779     // Claim the device. Note that any errors after this
00780     // will goto the generic handler, where the device will
00781     // be released.
00782     //
00783 
00784     status = ScsiClassClaimDevice(PortDeviceObject,
00785                                   LunInfo,
00786                                   FALSE,
00787                                   &PortDeviceObject);
00788 
00789     if (!NT_SUCCESS(status)) {
00790         return(status);
00791     }
00792 
00793     //
00794     // Create device object for this device.
00795     //
00796 
00797     sprintf(ntNameBuffer,
00798             "\\Device\\CdRom%lu",
00799             *DeviceCount);
00800 
00801     status = ScsiClassCreateDeviceObject(DriverObject,
00802                                          ntNameBuffer,
00803                                          NULL,
00804                                          &deviceObject,
00805                                          InitializationData);
00806 
00807     if (!NT_SUCCESS(status)) {
00808         DebugPrint((1,"CreateCdRomDeviceObjects: Can not create device %s\n",
00809                     ntNameBuffer));
00810 
00811         goto CreateCdRomDeviceObjectExit;
00812     }
00813 
00814     //
00815     // Indicate that IRPs should include MDLs.
00816     //
00817 
00818     deviceObject->Flags |= DO_DIRECT_IO;
00819 
00820     //
00821     // Set up required stack size in device object.
00822     //
00823 
00824     deviceObject->StackSize = PortDeviceObject->StackSize + 2;
00825 
00826     deviceExtension = deviceObject->DeviceExtension;
00827 
00828     //
00829     // Allocate spinlock for split request completion.
00830     //
00831 
00832     KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
00833 
00834     //
00835     // This is the physical device.
00836     //
00837 
00838     deviceExtension->PhysicalDevice = deviceObject;
00839 
00840     //
00841     // Initialize lock count to zero. The lock count is used to
00842     // disable the ejection mechanism when media is mounted.
00843     //
00844 
00845     deviceExtension->LockCount = 0;
00846 
00847     //
00848     // Save system cdrom number
00849     //
00850 
00851     deviceExtension->DeviceNumber = *DeviceCount;
00852 
00853     //
00854     // Copy port device object to device extension.
00855     //
00856 
00857     deviceExtension->PortDeviceObject = PortDeviceObject;
00858 
00859     //
00860     // Set the alignment requirements for the device based on the
00861     // host adapter requirements
00862     //
00863 
00864     if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
00865         deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
00866     }
00867 
00868     //
00869     // Save address of port driver capabilities.
00870     //
00871 
00872     deviceExtension->PortCapabilities = PortCapabilities;
00873 
00874     //
00875     // Clear SRB flags.
00876     //
00877 
00878     deviceExtension->SrbFlags = 0;
00879     deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
00880 
00881     //
00882     // Allocate request sense buffer.
00883     //
00884 
00885     senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
00886 
00887     if (senseData == NULL) {
00888 
00889         //
00890         // The buffer cannot be allocated.
00891         //
00892 
00893         status = STATUS_INSUFFICIENT_RESOURCES;
00894         goto CreateCdRomDeviceObjectExit;
00895     }
00896 
00897     //
00898     // Set the sense data pointer in the device extension.
00899     //
00900 
00901     deviceExtension->SenseData = senseData;
00902 
00903     //
00904     // CDROMs are not partitionable so starting offset is 0.
00905     //
00906 
00907     deviceExtension->StartingOffset.LowPart = 0;
00908     deviceExtension->StartingOffset.HighPart = 0;
00909 
00910     //
00911     // Path/TargetId/LUN describes a device location on the SCSI bus.
00912     // This information comes from the LunInfo buffer.
00913     //
00914 
00915     deviceExtension->PortNumber = (UCHAR)PortNumber;
00916     deviceExtension->PathId = LunInfo->PathId;
00917     deviceExtension->TargetId = LunInfo->TargetId;
00918     deviceExtension->Lun = LunInfo->Lun;
00919 
00920     //
00921     // Set timeout value in seconds.
00922     //
00923 
00924     timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath);
00925     if (timeOut) {
00926         deviceExtension->TimeOutValue = timeOut;
00927     } else {
00928         deviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
00929     }
00930 
00931     //
00932     // Build the lookaside list for srb's for the physical disk. Should only
00933     // need a couple.
00934     //
00935 
00936     ScsiClassInitializeSrbLookasideList(deviceExtension,
00937                                         CDROM_SRB_LIST_SIZE);
00938 
00939     srbListInitialized = TRUE;
00940 
00941     //
00942     // Back pointer to device object.
00943     //
00944 
00945     deviceExtension->DeviceObject = deviceObject;
00946 
00947     //
00948     // Allocate buffer for drive geometry.
00949     //
00950 
00951     deviceExtension->DiskGeometry =
00952         ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY_EX));
00953 
00954     if (deviceExtension->DiskGeometry == NULL) {
00955 
00956         status = STATUS_INSUFFICIENT_RESOURCES;
00957         goto CreateCdRomDeviceObjectExit;
00958     }
00959 
00960     //
00961     // Set up media change support defaults.
00962     //
00963 
00964     cddata = (PCDROM_DATA)(deviceExtension + 1);
00965 
00966     KeInitializeSpinLock(&cddata->FormSpinLock);
00967     KeInitializeSpinLock(&cddata->TimerIrpSpinLock);
00968     InitializeListHead(&cddata->TimerIrpList);
00969 
00970     cddata->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
00971     cddata->MediaChangeSupported = FALSE;
00972     cddata->MediaChange = FALSE;
00973 
00974     //
00975     // Assume that there is initially no media in the device
00976     // only notify upper layers if there is something there
00977     //
00978 
00979     deviceExtension->MediaChangeNoMedia = TRUE;
00980     cddata->MediaChangeIrp = NULL;
00981 #if DBG
00982     cddata->MediaChangeIrpTimeInUse = 0;
00983     cddata->MediaChangeIrpLost = FALSE;
00984 #endif
00985 
00986     //
00987     // Scan for Scsi controllers that require special processing.
00988     //
00989 
00990     ScanForSpecial(deviceObject,
00991                    (PINQUIRYDATA) LunInfo->InquiryData,
00992                    PortCapabilities);
00993 
00994     //
00995     // Do READ CAPACITY. This SCSI command
00996     // returns the last sector address on the device
00997     // and the bytes per sector.
00998     // These are used to calculate the drive capacity
00999     // in bytes.
01000     //
01001 
01002     status = ScsiClassReadDriveCapacity(deviceObject);
01003     bps = deviceExtension->DiskGeometry->Geometry.BytesPerSector;
01004 
01005     if (!NT_SUCCESS(status) || !bps) {
01006 
01007         DebugPrint((1,
01008                 "CreateCdRomDeviceObjects: Can't read capacity for device %s\n",
01009                 ntNameBuffer));
01010 
01011         //
01012         // Set disk geometry to default values (per ISO 9660).
01013         //
01014 
01015         bps = 2048;
01016         deviceExtension->SectorShift = 11;
01017         deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
01018     } else {
01019 
01020         //
01021         // Insure that bytes per sector is a power of 2
01022         // This corrects a problem with the HP 4020i CDR where it
01023         // returns an incorrect number for bytes per sector.
01024         //
01025 
01026         lastBit = (ULONG) -1;
01027         while (bps) {
01028             lastBit++;
01029             bps = bps >> 1;
01030         }
01031 
01032         bps = 1 << lastBit;
01033     }
01034     deviceExtension->DiskGeometry->Geometry.BytesPerSector = bps;
01035     DebugPrint((2, "CreateCdRomDeviceObject: Calc'd bps = %x\n", bps));
01036 
01037     //
01038     // Check to see if this is some sort of changer device
01039     //
01040 
01041     changerDevice = FALSE;
01042 
01043     //
01044     // Search for devices that have special requirements for media
01045     // change support.
01046     //
01047 
01048     if (deviceExtension->Lun > 0) {
01049         changerDevice = TRUE;
01050     }
01051 
01052     if (!changerDevice) {
01053         changerDevice = IsThisASanyo(deviceObject, deviceExtension->PathId,
01054                                      deviceExtension->TargetId);
01055     }
01056 
01057     if (!changerDevice) {
01058         ULONG tmp;
01059         changerDevice = IsThisAnAtapiChanger(deviceObject, &tmp);
01060     }
01061 
01062     if (!changerDevice) {
01063         changerDevice = IsThisAMultiLunDevice(deviceObject, PortDeviceObject);
01064     }
01065 
01066     //
01067     // If it is a changer device, increment the timeout to take platter-swapping
01068     // time into account
01069     //
01070 
01071     if(changerDevice) {
01072         deviceExtension->TimeOutValue += SCSI_CHANGER_BONUS_TIMEOUT;
01073     }
01074 
01075     //
01076     // Create the media change named event.  If this succeeds then continue
01077     // initializing the media change support data items.
01078     //
01079 
01080     CdRomCreateNamedEvent(deviceExtension,*DeviceCount);
01081     if (deviceExtension->MediaChangeEvent) {
01082 
01083         //
01084         // If this is not a changer, get an IRP for the timer request
01085         // and initialize the timer.
01086         //
01087 
01088         if (!changerDevice) {
01089 
01090             //
01091             // Not a changer device - continue with media change initialization.
01092             // Determine if the user actually wants media change events.
01093             //
01094 
01095             if (CdRomCheckRegistryForMediaChangeValue(RegistryPath, *DeviceCount)) {
01096                 PIO_STACK_LOCATION irpStack;
01097                 PSCSI_REQUEST_BLOCK srb;
01098                 PIRP irp;
01099 
01100                 //
01101                 // User wants it - preallocate IRP and SRB.
01102                 //
01103 
01104                 irp = IoAllocateIrp((CCHAR)(deviceObject->StackSize+1),
01105                                     FALSE);
01106                 if (irp) {
01107                     PVOID buffer;
01108 
01109                     srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
01110                     buffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
01111 
01112                     if (srb && buffer) {
01113                         PCDB cdb;
01114 
01115                         //
01116                         // All resources have been allocated set up the IRP.
01117                         //
01118 
01119                         IoSetNextIrpStackLocation(irp);
01120                         irpStack = IoGetCurrentIrpStackLocation(irp);
01121                         irpStack->DeviceObject = deviceObject;
01122                         irpStack = IoGetNextIrpStackLocation(irp);
01123                         cddata->MediaChangeIrp = irp;
01124                         irpStack->Parameters.Scsi.Srb = srb;
01125 
01126                         //
01127                         // Initialize the SRB
01128                         //
01129 
01130                         RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
01131 
01132                         srb->CdbLength = 6;
01133                         srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
01134                         srb->QueueTag = SP_UNTAGGED;
01135                         srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
01136                         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
01137                         srb->PathId = deviceExtension->PathId;
01138                         srb->TargetId = deviceExtension->TargetId;
01139                         srb->Lun = deviceExtension->Lun;
01140                         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
01141 
01142                         //
01143                         // Initialize and set up the sense information buffer
01144                         //
01145 
01146                         RtlZeroMemory(buffer, SENSE_BUFFER_SIZE);
01147                         srb->SenseInfoBuffer = buffer;
01148                         srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
01149 
01150                         //
01151                         // Initialize the CDB
01152                         //
01153 
01154                         cdb = (PCDB)&srb->Cdb[0];
01155                         cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
01156                         cdb->CDB6GENERIC.LogicalUnitNumber = deviceExtension->Lun;
01157 
01158                         //
01159                         // It is ok to support media change events on this device.
01160                         //
01161 
01162                         cddata->MediaChangeSupported = TRUE;
01163                         cddata->MediaChange = TRUE;
01164 
01165                     } else {
01166 
01167                         if (srb) {
01168                             ExFreePool(srb);
01169                         }
01170                         if (buffer) {
01171                             ExFreePool(buffer);
01172                         }
01173                         IoFreeIrp(irp);
01174                     }
01175                 }
01176             } else {
01177                 deviceExtension->MediaChangeEvent = NULL;
01178             }
01179         } else {
01180             deviceExtension->MediaChangeEvent = NULL;
01181         }
01182     }
01183 
01184     //
01185     // Assume use of 6-byte mode sense/select for now.
01186     //
01187 
01188     cddata->XAFlags |= XA_USE_6_BYTE;
01189 
01190     //
01191     // Build and issue mode sense with Read error recovery page. This will be used to change
01192     // block size in case of any raw reads (Mode 2, Form 2).
01193     //
01194 
01195     length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH);
01196 
01197     RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
01198 
01199     srb.CdbLength = 6;
01200     cdb = (PCDB)srb.Cdb;
01201 
01202     //
01203     // Set timeout value from device extension.
01204     //
01205 
01206     srb.TimeOutValue = deviceExtension->TimeOutValue;
01207 
01208     //
01209     // Build the MODE SENSE CDB. The data returned will be kept in the device extension
01210     // and used to set block size.
01211     //
01212 
01213     cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
01214     cdb->MODE_SENSE.PageCode = 0x1;
01215     cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
01216 
01217     buffer = ExAllocatePool(NonPagedPoolCacheAligned, (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH10));
01218     if (!buffer) {
01219         status = STATUS_INSUFFICIENT_RESOURCES;
01220         goto CreateCdRomDeviceObjectExit;
01221     }
01222 
01223     status = ScsiClassSendSrbSynchronous(deviceObject,
01224                                          &srb,
01225                                          buffer,
01226                                          length,
01227                                          FALSE);
01228     if (!NT_SUCCESS(status)) {
01229 
01230         //
01231         // May be Atapi, try 10-byte.
01232         //
01233 
01234         length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH10);
01235 
01236         RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
01237 
01238         //
01239         // Build the MODE SENSE CDB.
01240         //
01241 
01242         srb.CdbLength = 10;
01243         cdb = (PCDB)srb.Cdb;
01244 
01245         //
01246         // Set timeout value from device extension.
01247         //
01248 
01249         srb.TimeOutValue = deviceExtension->TimeOutValue;
01250 
01251         cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
01252         cdb->MODE_SENSE10.PageCode = 0x1;
01253 
01254         cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(length >> 8);
01255         cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(length & 0xFF);
01256 
01257         status = ScsiClassSendSrbSynchronous(deviceObject,
01258                                              &srb,
01259                                              buffer,
01260                                              length,
01261                                              FALSE);
01262         if (status == STATUS_DATA_OVERRUN) {
01263 
01264             //
01265             // Build and issue the ReadCd command to ensure that this device supports it.
01266             //
01267 
01268             RtlZeroMemory(cdb, 12);
01269 
01270             cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
01271 
01272             status = ScsiClassSendSrbSynchronous(deviceObject,
01273                                                  &srb,
01274                                                  NULL,
01275                                                  0,
01276                                                  FALSE);
01277 
01278             //
01279             // If the command wasn't rejected then support the READ_CD.
01280             //
01281 
01282             if (NT_SUCCESS(status) || (status == STATUS_NO_MEDIA_IN_DEVICE)) {
01283 
01284                 //
01285                 // Using Read CD precludes issueing a mode select to
01286                 // set the user data size. So, no buffer copy is
01287                 // necessary.
01288                 //
01289 
01290                 cddata->XAFlags &= ~XA_USE_6_BYTE;
01291                 cddata->XAFlags = XA_USE_READ_CD | XA_USE_10_BYTE;
01292             } else {
01293 
01294                 RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA10));
01295                 cddata->u1.Header.ModeDataLength = 0;
01296 
01297                 cddata->XAFlags &= ~XA_USE_6_BYTE;
01298                 cddata->XAFlags |= XA_USE_10_BYTE;
01299             }
01300 
01301         } else if (NT_SUCCESS(status)) {
01302 
01303             RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA10));
01304             cddata->u1.Header.ModeDataLength = 0;
01305 
01306             cddata->XAFlags &= ~XA_USE_6_BYTE;
01307             cddata->XAFlags |= XA_USE_10_BYTE;
01308 
01309         } else {
01310             cddata->XAFlags |= XA_NOT_SUPPORTED;
01311         }
01312     } else {
01313         RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA));
01314         cddata->u1.Header.ModeDataLength = 0;
01315     }
01316 
01317     ExFreePool(buffer);
01318 
01319     //
01320     // Start the timer now regardless of if Autorun is enabled.
01321     // The timer must run forever since IoStopTimer faults.
01322     //
01323 
01324     IoInitializeTimer(deviceObject, CdRomTickHandler, NULL);
01325     IoStartTimer(deviceObject);
01326 
01327     return(STATUS_SUCCESS);
01328 
01329 CreateCdRomDeviceObjectExit:
01330 
01331     //
01332     // Release the device since an error occured.
01333     //
01334 
01335     ScsiClassClaimDevice(PortDeviceObject,
01336                          LunInfo,
01337                          TRUE,
01338                          NULL);
01339 
01340     if (senseData != NULL) {
01341         ExFreePool(senseData);
01342     }
01343 
01344     if (deviceExtension->DiskGeometry != NULL) {
01345         ExFreePool(deviceExtension->DiskGeometry);
01346     }
01347 
01348     if (deviceObject != NULL) {
01349         if (srbListInitialized) {
01350             ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
01351         }
01352         IoDeleteDevice(deviceObject);
01353     }
01354 
01355 
01356     return status;
01357 
01358 } // end CreateCdRomDeviceObject()
01359 
01360 VOID
01361 NTAPI
01362 ScsiCdRomStartIo(
01363     IN PDEVICE_OBJECT DeviceObject,
01364     IN PIRP Irp
01365     )
01366 {
01367 
01368     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
01369     PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
01370     PIO_STACK_LOCATION  nextIrpStack = IoGetNextIrpStackLocation(Irp);
01371     PIO_STACK_LOCATION  irpStack;
01372     PIRP                irp2 = NULL;
01373     ULONG               transferPages;
01374     ULONG               transferByteCount = currentIrpStack->Parameters.Read.Length;
01375     ULONG               maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
01376     PCDROM_DATA         cdData;
01377     PSCSI_REQUEST_BLOCK srb = NULL;
01378     PCDB                cdb;
01379     PUCHAR              senseBuffer = NULL;
01380     PVOID               dataBuffer;
01381     NTSTATUS            status;
01382     BOOLEAN             use6Byte;
01383 
01384     //
01385     // Mark IRP with status pending.
01386     //
01387 
01388     IoMarkIrpPending(Irp);
01389 
01390     //
01391     // If the flag is set in the device object, force a verify.
01392     //
01393 
01394     if (DeviceObject->Flags & DO_VERIFY_VOLUME) {
01395         DebugPrint((2, "ScsiCdRomStartIo: [%lx] Volume needs verified\n", Irp));
01396         if (!(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
01397 
01398             if (Irp->Tail.Overlay.Thread) {
01399                 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
01400             }
01401 
01402             Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
01403 
01404             DebugPrint((2, "ScsiCdRomStartIo: [%lx] Calling UpdateCapcity - "
01405                            "ioctl event = %lx\n",
01406                         Irp,
01407                         nextIrpStack->Parameters.Others.Argument1
01408                       ));
01409 
01410             //
01411             // our device control dispatch routine stores an event in the next
01412             // stack location to signal when startio has completed.  We need to
01413             // pass this in so that the update capacity completion routine can
01414             // set it rather than completing the Irp.
01415             //
01416 
01417             status = CdRomUpdateCapacity(deviceExtension,
01418                                          Irp,
01419                                          nextIrpStack->Parameters.Others.Argument1
01420                                          );
01421 
01422             DebugPrint((2, "ScsiCdRomStartIo: [%lx] UpdateCapacity returned %lx\n", Irp, status));
01423             ASSERT(status == STATUS_PENDING);
01424             return;
01425         }
01426     }
01427 
01428     cdData = (PCDROM_DATA)(deviceExtension + 1);
01429     use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
01430 
01431     if (currentIrpStack->MajorFunction == IRP_MJ_READ) {
01432 
01433         //
01434         // Add partition byte offset to make starting byte relative to
01435         // beginning of disk. In addition, add in skew for DM Driver, if any.
01436         //
01437 
01438         currentIrpStack->Parameters.Read.ByteOffset.QuadPart += (deviceExtension->StartingOffset.QuadPart);
01439 
01440         //
01441         // Calculate number of pages in this transfer.
01442         //
01443 
01444         transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
01445                                                        currentIrpStack->Parameters.Read.Length);
01446 
01447         //
01448         // Check if request length is greater than the maximum number of
01449         // bytes that the hardware can transfer.
01450         //
01451 
01452         if (cdData->RawAccess) {
01453 
01454             ASSERT(!(cdData->XAFlags & XA_USE_READ_CD));
01455 
01456             //
01457             // Fire off a mode select to switch back to cooked sectors.
01458             //
01459 
01460             irp2 = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1),
01461                                   FALSE);
01462 
01463             if (!irp2) {
01464                 Irp->IoStatus.Information = 0;
01465                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01466                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
01467                 IoStartNextPacket(DeviceObject, FALSE);
01468                 return;
01469             }
01470 
01471             srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
01472             if (!srb) {
01473                 Irp->IoStatus.Information = 0;
01474                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01475                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
01476                 IoFreeIrp(irp2);
01477                 IoStartNextPacket(DeviceObject, FALSE);
01478                 return;
01479             }
01480 
01481             RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
01482 
01483             cdb = (PCDB)srb->Cdb;
01484 
01485             //
01486             // Allocate sense buffer.
01487             //
01488 
01489             senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
01490 
01491             if (!senseBuffer) {
01492                 Irp->IoStatus.Information = 0;
01493                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01494                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
01495                 ExFreePool(srb);
01496                 IoFreeIrp(irp2);
01497                 IoStartNextPacket(DeviceObject, FALSE);
01498                 return;
01499             }
01500 
01501             //
01502             // Set up the irp.
01503             //
01504 
01505             IoSetNextIrpStackLocation(irp2);
01506             irp2->IoStatus.Status = STATUS_SUCCESS;
01507             irp2->IoStatus.Information = 0;
01508             irp2->Flags = 0;
01509             irp2->UserBuffer = NULL;
01510 
01511             //
01512             // Save the device object and irp in a private stack location.
01513             //
01514 
01515             irpStack = IoGetCurrentIrpStackLocation(irp2);
01516             irpStack->DeviceObject = deviceExtension->DeviceObject;
01517             irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
01518 
01519             //
01520             // The retry count will be in the real Irp, as the retry logic will
01521             // recreate our private irp.
01522             //
01523 
01524             if (!(nextIrpStack->Parameters.Others.Argument1)) {
01525 
01526                 //
01527                 // Only jam this in if it doesn't exist. The completion routines can
01528                 // call StartIo directly in the case of retries and resetting it will
01529                 // cause infinite loops.
01530                 //
01531 
01532                 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
01533             }
01534 
01535             //
01536             // Construct the IRP stack for the lower level driver.
01537             //
01538 
01539             irpStack = IoGetNextIrpStackLocation(irp2);
01540             irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
01541             irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
01542             irpStack->Parameters.Scsi.Srb = srb;
01543 
01544             srb->Length = SCSI_REQUEST_BLOCK_SIZE;
01545             srb->PathId = deviceExtension->PathId;
01546             srb->TargetId = deviceExtension->TargetId;
01547             srb->Lun = deviceExtension->Lun;
01548             srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
01549             srb->Cdb[1] |= deviceExtension->Lun << 5;
01550             srb->SrbStatus = srb->ScsiStatus = 0;
01551             srb->NextSrb = 0;
01552             srb->OriginalRequest = irp2;
01553             srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
01554             srb->SenseInfoBuffer = senseBuffer;
01555 
01556             transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
01557             dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount );
01558             if (!dataBuffer) {
01559                 Irp->IoStatus.Information = 0;
01560                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01561                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
01562                 ExFreePool(senseBuffer);
01563                 ExFreePool(srb);
01564                 IoFreeIrp(irp2);
01565                 IoStartNextPacket(DeviceObject, FALSE);
01566                 return;
01567 
01568             }
01569 
01570             irp2->MdlAddress = IoAllocateMdl(dataBuffer,
01571                                             transferByteCount,
01572                                             FALSE,
01573                                             FALSE,
01574                                             (PIRP) NULL);
01575 
01576             if (!irp2->MdlAddress) {
01577                 Irp->IoStatus.Information = 0;
01578                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01579                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
01580                 ExFreePool(senseBuffer);
01581                 ExFreePool(srb);
01582                 ExFreePool(dataBuffer);
01583                 IoFreeIrp(irp2);
01584                 IoStartNextPacket(DeviceObject, FALSE);
01585                 return;
01586             }
01587 
01588             //
01589             // Prepare the MDL
01590             //
01591 
01592             MmBuildMdlForNonPagedPool(irp2->MdlAddress);
01593 
01594             srb->DataBuffer = dataBuffer;
01595 
01596             //
01597             // Set the new block size in the descriptor.
01598             //
01599 
01600             cdData->u1.BlockDescriptor.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
01601             cdData->u1.BlockDescriptor.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >>  8) & 0xFF;
01602             cdData->u1.BlockDescriptor.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
01603 
01604             //
01605             // Move error page into dataBuffer.
01606             //
01607 
01608             RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, transferByteCount);
01609 
01610             //
01611             // Build and send a mode select to switch into raw mode.
01612             //
01613 
01614             srb->SrbFlags = deviceExtension->SrbFlags;
01615             srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
01616             srb->DataTransferLength = transferByteCount;
01617             srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
01618 
01619             if (use6Byte) {
01620                 srb->CdbLength = 6;
01621                 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
01622                 cdb->MODE_SELECT.PFBit = 1;
01623                 cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
01624             } else {
01625 
01626                 srb->CdbLength = 10;
01627                 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
01628                 cdb->MODE_SELECT10.PFBit = 1;
01629                 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
01630                 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
01631             }
01632 
01633             //
01634             // Update completion routine.
01635             //
01636 
01637             IoSetCompletionRoutine(irp2,
01638                                    CdRomSwitchModeCompletion,
01639                                    srb,
01640                                    TRUE,
01641                                    TRUE,
01642                                    TRUE);
01643 
01644             IoCallDriver(deviceExtension->PortDeviceObject, irp2);
01645             return;
01646         }
01647 
01648         if ((currentIrpStack->Parameters.Read.Length > maximumTransferLength) ||
01649             (transferPages >
01650                 deviceExtension->PortCapabilities->MaximumPhysicalPages)) {
01651 
01652             //
01653             // Request needs to be split. Completion of each portion of the
01654             // request will fire off the next portion. The final request will
01655             // signal Io to send a new request.
01656             //
01657 
01658             transferPages =
01659                 deviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
01660 
01661             if(maximumTransferLength > transferPages << PAGE_SHIFT) {
01662                 maximumTransferLength = transferPages << PAGE_SHIFT;
01663             }
01664 
01665             //
01666             // Check that the maximum transfer size is not zero
01667             //
01668 
01669             if(maximumTransferLength == 0) {
01670                 maximumTransferLength = PAGE_SIZE;
01671             }
01672 
01673             ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength);
01674             return;
01675 
01676         } else {
01677 
01678             //
01679             // Build SRB and CDB for this IRP.
01680             //
01681 
01682             ScsiClassBuildRequest(DeviceObject, Irp);
01683 
01684         }
01685 
01686 
01687     } else if (currentIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
01688 
01689         //
01690         // Allocate an irp, srb and associated structures.
01691         //
01692 
01693         irp2 = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1),
01694                               FALSE);
01695 
01696         if (!irp2) {
01697             Irp->IoStatus.Information = 0;
01698             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01699             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
01700             IoStartNextPacket(DeviceObject, FALSE);
01701             DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
01702             return;
01703         }
01704 
01705         srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
01706         if (!srb) {
01707             Irp->IoStatus.Information = 0;
01708             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01709             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
01710             IoFreeIrp(irp2);
01711             IoStartNextPacket(DeviceObject, FALSE);
01712             DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
01713             return;
01714         }
01715 
01716         RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
01717 
01718         cdb = (PCDB)srb->Cdb;
01719 
01720         //
01721         // Allocate sense buffer.
01722         //
01723 
01724         senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
01725 
01726         if (!senseBuffer) {
01727             Irp->IoStatus.Information = 0;
01728             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01729             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
01730             ExFreePool(srb);
01731             IoFreeIrp(irp2);
01732             IoStartNextPacket(DeviceObject, FALSE);
01733             DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
01734             return;
01735         }
01736 
01737         //
01738         // Set up the irp.
01739         //
01740 
01741         IoSetNextIrpStackLocation(irp2);
01742         irp2->IoStatus.Status = STATUS_SUCCESS;
01743         irp2->IoStatus.Information = 0;
01744         irp2->Flags = 0;
01745         irp2->UserBuffer = NULL;
01746 
01747         //
01748         // Save the device object and irp in a private stack location.
01749         //
01750 
01751         irpStack = IoGetCurrentIrpStackLocation(irp2);
01752         irpStack->DeviceObject = deviceExtension->DeviceObject;
01753         irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
01754 
01755         //
01756         // The retry count will be in the real Irp, as the retry logic will
01757         // recreate our private irp.
01758         //
01759 
01760         if (!(nextIrpStack->Parameters.Others.Argument1)) {
01761 
01762             //
01763             // Only jam this in if it doesn't exist. The completion routines can
01764             // call StartIo directly in the case of retries and resetting it will
01765             // cause infinite loops.
01766             //
01767 
01768             nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
01769         }
01770 
01771         //
01772         // Construct the IRP stack for the lower level driver.
01773         //
01774 
01775         irpStack = IoGetNextIrpStackLocation(irp2);
01776         irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
01777         irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
01778         irpStack->Parameters.Scsi.Srb = srb;
01779 
01780         IoSetCompletionRoutine(irp2,
01781                                CdRomDeviceControlCompletion,
01782                                srb,
01783                                TRUE,
01784                                TRUE,
01785                                TRUE);
01786         //
01787         // Setup those fields that are generic to all requests.
01788         //
01789 
01790         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
01791         srb->PathId = deviceExtension->PathId;
01792         srb->TargetId = deviceExtension->TargetId;
01793         srb->Lun = deviceExtension->Lun;
01794         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
01795         srb->Cdb[1] |= deviceExtension->Lun << 5;
01796         srb->SrbStatus = srb->ScsiStatus = 0;
01797         srb->NextSrb = 0;
01798         srb->OriginalRequest = irp2;
01799         srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
01800         srb->SenseInfoBuffer = senseBuffer;
01801 
01802         switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
01803 
01804         case IOCTL_CDROM_RAW_READ: {
01805 
01806             //
01807             // Determine whether the drive is currently in raw or cooked mode,
01808             // and which command to use to read the data.
01809             //
01810 
01811             if (!(cdData->XAFlags & XA_USE_READ_CD)) {
01812 
01813                 PRAW_READ_INFO rawReadInfo =
01814                                    (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
01815                 ULONG          maximumTransferLength;
01816                 ULONG          transferPages;
01817 
01818                 if (cdData->RawAccess) {
01819 
01820                     ULONG  startingSector;
01821 
01822                     //
01823                     // Free the recently allocated irp, as we don't need it.
01824                     //
01825 
01826                     IoFreeIrp(irp2);
01827 
01828                     cdb = (PCDB)srb->Cdb;
01829                     RtlZeroMemory(cdb, 12);
01830 
01831                     //
01832                     // Calculate starting offset.
01833                     //
01834 
01835                     startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
01836                     transferByteCount  = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
01837                     maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
01838                     transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
01839                                                                    transferByteCount);
01840 
01841                     //
01842                     // Determine if request is within limits imposed by miniport.
01843                     //
01844 
01845                     if (transferByteCount > maximumTransferLength ||
01846                         transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
01847 
01848                         //
01849                         // The claim is that this won't happen, and is backed up by
01850                         // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
01851                         // we get only 4 sector requests.
01852                         //
01853 
01854 
01855                         Irp->IoStatus.Information = 0;
01856                         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
01857                         IoCompleteRequest(Irp, IO_DISK_INCREMENT);
01858                         ExFreePool(senseBuffer);
01859                         ExFreePool(srb);
01860                         IoStartNextPacket(DeviceObject, FALSE);
01861                         return;
01862 
01863                     }
01864 
01865                     srb->OriginalRequest = Irp;
01866                     srb->SrbFlags = deviceExtension->SrbFlags;
01867                     srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
01868                     srb->DataTransferLength = transferByteCount;
01869                     srb->TimeOutValue = deviceExtension->TimeOutValue;
01870                     srb->CdbLength = 10;
01871                     srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
01872 
01873                     if (rawReadInfo->TrackMode == CDDA) {
01874                         if (cdData->XAFlags & PLEXTOR_CDDA) {
01875 
01876                             srb->CdbLength = 12;
01877 
01878                             cdb->PLXTR_READ_CDDA.LogicalUnitNumber = deviceExtension->Lun;
01879                             cdb->PLXTR_READ_CDDA.LogicalBlockByte3  = (UCHAR) (startingSector & 0xFF);
01880                             cdb->PLXTR_READ_CDDA.LogicalBlockByte2  = (UCHAR) ((startingSector >>  8) & 0xFF);
01881                             cdb->PLXTR_READ_CDDA.LogicalBlockByte1  = (UCHAR) ((startingSector >> 16) & 0xFF);
01882                             cdb->PLXTR_READ_CDDA.LogicalBlockByte0  = (UCHAR) ((startingSector >> 24) & 0xFF);
01883 
01884                             cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
01885                             cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
01886                             cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
01887                             cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
01888 
01889                             cdb->PLXTR_READ_CDDA.SubCode = 0;
01890                             cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
01891 
01892                         } else if (cdData->XAFlags & NEC_CDDA) {
01893 
01894                             cdb->NEC_READ_CDDA.LogicalBlockByte3  = (UCHAR) (startingSector & 0xFF);
01895                             cdb->NEC_READ_CDDA.LogicalBlockByte2  = (UCHAR) ((startingSector >>  8) & 0xFF);
01896                             cdb->NEC_READ_CDDA.LogicalBlockByte1  = (UCHAR) ((startingSector >> 16) & 0xFF);
01897                             cdb->NEC_READ_CDDA.LogicalBlockByte0  = (UCHAR) ((startingSector >> 24) & 0xFF);
01898 
01899                             cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
01900                             cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
01901 
01902                             cdb->NEC_READ_CDDA.OperationCode = 0xD4;
01903                         }
01904                     } else {
01905 
01906                         cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
01907 
01908                         cdb->CDB10.TransferBlocksMsb  = (UCHAR) (rawReadInfo->SectorCount >> 8);
01909                         cdb->CDB10.TransferBlocksLsb  = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
01910 
01911                         cdb->CDB10.LogicalBlockByte3  = (UCHAR) (startingSector & 0xFF);
01912                         cdb->CDB10.LogicalBlockByte2  = (UCHAR) ((startingSector >>  8) & 0xFF);
01913                         cdb->CDB10.LogicalBlockByte1  = (UCHAR) ((startingSector >> 16) & 0xFF);
01914                         cdb->CDB10.LogicalBlockByte0  = (UCHAR) ((startingSector >> 24) & 0xFF);
01915 
01916                         cdb->CDB10.OperationCode = SCSIOP_READ;
01917                     }
01918 
01919                     srb->SrbStatus = srb->ScsiStatus = 0;
01920 
01921                     nextIrpStack->MajorFunction = IRP_MJ_SCSI;
01922                     nextIrpStack->Parameters.Scsi.Srb = srb;
01923 
01924                     if (!(nextIrpStack->Parameters.Others.Argument1)) {
01925 
01926                         //
01927                         // Only jam this in if it doesn't exist. The completion routines can
01928                         // call StartIo directly in the case of retries and resetting it will
01929                         // cause infinite loops.
01930                         //
01931 
01932                         nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
01933                     }
01934 
01935                     //
01936                     // Set up IoCompletion routine address.
01937                     //
01938 
01939                     IoSetCompletionRoutine(Irp,
01940                                            CdRomXACompletion,
01941                                            srb,
01942                                            TRUE,
01943                                            TRUE,
01944                                            TRUE);
01945 
01946                     IoCallDriver(deviceExtension->PortDeviceObject, Irp);
01947                     return;
01948 
01949                 } else {
01950 
01951                     transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
01952                     dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount );
01953                     if (!dataBuffer) {
01954                         Irp->IoStatus.Information = 0;
01955                         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01956                         IoCompleteRequest(Irp, IO_DISK_INCREMENT);
01957                         ExFreePool(senseBuffer);
01958                         ExFreePool(srb);
01959                         IoFreeIrp(irp2);
01960                         IoStartNextPacket(DeviceObject, FALSE);
01961                         return;
01962 
01963                     }
01964 
01965                     irp2->MdlAddress = IoAllocateMdl(dataBuffer,
01966                                                     transferByteCount,
01967                                                     FALSE,
01968                                                     FALSE,
01969                                                     (PIRP) NULL);
01970 
01971                     if (!irp2->MdlAddress) {
01972                         Irp->IoStatus.Information = 0;
01973                         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01974                         IoCompleteRequest(Irp, IO_DISK_INCREMENT);
01975                         ExFreePool(senseBuffer);
01976                         ExFreePool(srb);
01977                         ExFreePool(dataBuffer);
01978                         IoFreeIrp(irp2);
01979                         IoStartNextPacket(DeviceObject, FALSE);
01980                         return;
01981                     }
01982 
01983                     //
01984                     // Prepare the MDL
01985                     //
01986 
01987                     MmBuildMdlForNonPagedPool(irp2->MdlAddress);
01988 
01989                     srb->DataBuffer = dataBuffer;
01990 
01991                     //
01992                     // Set the new block size in the descriptor.
01993                     //
01994 
01995                     cdData->u1.BlockDescriptor.BlockLength[0] = (UCHAR)(RAW_SECTOR_SIZE >> 16) & 0xFF;
01996                     cdData->u1.BlockDescriptor.BlockLength[1] = (UCHAR)(RAW_SECTOR_SIZE >>  8) & 0xFF;
01997                     cdData->u1.BlockDescriptor.BlockLength[2] = (UCHAR)(RAW_SECTOR_SIZE & 0xFF);
01998 
01999 
02000                     //
02001                     // TODO: Set density code, based on operation
02002                     //
02003 
02004                     cdData->u1.BlockDescriptor.DensityCode = 0;
02005 
02006 
02007                     //
02008                     // Move error page into dataBuffer.
02009                     //
02010 
02011                     RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, transferByteCount);
02012 
02013 
02014                     //
02015                     // Build and send a mode select to switch into raw mode.
02016                     //
02017 
02018                     srb->SrbFlags = deviceExtension->SrbFlags;
02019                     srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
02020                     srb->DataTransferLength = transferByteCount;
02021                     srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
02022 
02023                     if (use6Byte) {
02024                         srb->CdbLength = 6;
02025                         cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
02026                         cdb->MODE_SELECT.PFBit = 1;
02027                         cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
02028                     } else {
02029 
02030                         srb->CdbLength = 10;
02031                         cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
02032                         cdb->MODE_SELECT10.PFBit = 1;
02033                         cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
02034                         cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
02035                     }
02036 
02037                     //
02038                     // Update completion routine.
02039                     //
02040 
02041                     IoSetCompletionRoutine(irp2,
02042                                            CdRomSwitchModeCompletion,
02043                                            srb,
02044                                            TRUE,
02045                                            TRUE,
02046                                            TRUE);
02047 
02048                 }
02049 
02050             } else {
02051 
02052                 PRAW_READ_INFO rawReadInfo =
02053                                    (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
02054                 ULONG  startingSector;
02055 
02056                 //
02057                 // Free the recently allocated irp, as we don't need it.
02058                 //
02059 
02060                 IoFreeIrp(irp2);
02061 
02062                 cdb = (PCDB)srb->Cdb;
02063                 RtlZeroMemory(cdb, 12);
02064 
02065 
02066                 //
02067                 // Calculate starting offset.
02068                 //
02069 
02070                 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
02071                 transferByteCount  = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
02072 
02073 
02074                 srb->OriginalRequest = Irp;
02075                 srb->SrbFlags = deviceExtension->SrbFlags;
02076                 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
02077                 srb->DataTransferLength = transferByteCount;
02078                 srb->TimeOutValue = deviceExtension->TimeOutValue;
02079                 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
02080                 srb->CdbLength = 12;
02081                 srb->SrbStatus = srb->ScsiStatus = 0;
02082 
02083                 //
02084                 // Fill in CDB fields.
02085                 //
02086 
02087                 cdb = (PCDB)srb->Cdb;
02088 
02089 
02090                 cdb->READ_CD.TransferBlocks[2]  = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
02091                 cdb->READ_CD.TransferBlocks[1]  = (UCHAR) (rawReadInfo->SectorCount >> 8 );
02092                 cdb->READ_CD.TransferBlocks[0]  = (UCHAR) (rawReadInfo->SectorCount >> 16);
02093 
02094 
02095                 cdb->READ_CD.StartingLBA[3]  = (UCHAR) (startingSector & 0xFF);
02096                 cdb->READ_CD.StartingLBA[2]  = (UCHAR) ((startingSector >>  8));
02097                 cdb->READ_CD.StartingLBA[1]  = (UCHAR) ((startingSector >> 16));
02098                 cdb->READ_CD.StartingLBA[0]  = (UCHAR) ((startingSector >> 24));
02099 
02100                 //
02101                 // Setup cdb depending upon the sector type we want.
02102                 //
02103 
02104                 switch (rawReadInfo->TrackMode) {
02105                 case CDDA:
02106 
02107                     cdb->READ_CD.ExpectedSectorType = CD_DA_SECTOR;
02108                     cdb->READ_CD.IncludeUserData = 1;
02109                     cdb->READ_CD.HeaderCode = 3;
02110                     cdb->READ_CD.IncludeSyncData = 1;
02111                     break;
02112 
02113                 case YellowMode2:
02114 
02115                     cdb->READ_CD.ExpectedSectorType = YELLOW_MODE2_SECTOR;
02116                     cdb->READ_CD.IncludeUserData = 1;
02117                     cdb->READ_CD.HeaderCode = 1;
02118                     cdb->READ_CD.IncludeSyncData = 1;
02119                     break;
02120 
02121                 case XAForm2:
02122 
02123                     cdb->READ_CD.ExpectedSectorType = FORM2_MODE2_SECTOR;
02124                     cdb->READ_CD.IncludeUserData = 1;
02125                     cdb->READ_CD.HeaderCode = 3;
02126                     cdb->READ_CD.IncludeSyncData = 1;
02127                     break;
02128 
02129                 default:
02130                     Irp->IoStatus.Information = 0;
02131                     Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
02132                     IoCompleteRequest(Irp, IO_DISK_INCREMENT);
02133                     ExFreePool(senseBuffer);
02134                     ExFreePool(srb);
02135                     IoFreeIrp(irp2);
02136                     IoStartNextPacket(DeviceObject, FALSE);
02137                     DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
02138                     return;
02139                 }
02140 
02141                 cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
02142 
02143                 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
02144                 nextIrpStack->Parameters.Scsi.Srb = srb;
02145 
02146                 if (!(nextIrpStack->Parameters.Others.Argument1)) {
02147 
02148                     //
02149                     // Only jam this in if it doesn't exist. The completion routines can
02150                     // call StartIo directly in the case of retries and resetting it will
02151                     // cause infinite loops.
02152                     //
02153 
02154                     nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
02155                 }
02156 
02157                 //
02158                 // Set up IoCompletion routine address.
02159                 //
02160 
02161                 IoSetCompletionRoutine(Irp,
02162                                        CdRomXACompletion,
02163                                        srb,
02164                                        TRUE,
02165                                        TRUE,
02166                                        TRUE);
02167 
02168                 IoCallDriver(deviceExtension->PortDeviceObject, Irp);
02169                 return;
02170 
02171             }
02172 
02173             IoCallDriver(deviceExtension->PortDeviceObject, irp2);
02174             return;
02175         }
02176 
02177         case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
02178 
02179             //
02180             // Issue ReadCapacity to update device extension
02181             // with information for current media.
02182             //
02183 
02184             DebugPrint((3,
02185                         "CdRomStartIo: Get drive capacity\n"));
02186 
02187             //
02188             // setup remaining srb and cdb parameters.
02189             //
02190 
02191             srb->SrbFlags = deviceExtension->SrbFlags;
02192             srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
02193             srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
02194             srb->CdbLength = 10;
02195             srb->TimeOutValue = deviceExtension->TimeOutValue;
02196 
02197             dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(READ_CAPACITY_DATA));
02198             if (!dataBuffer) {
02199                 Irp->IoStatus.Information = 0;
02200                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02201                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
02202                 ExFreePool(senseBuffer);
02203                 ExFreePool(srb);
02204                 IoFreeIrp(irp2);
02205                 IoStartNextPacket(DeviceObject, FALSE);
02206                 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
02207                 return;
02208 
02209             }
02210 
02211             irp2->MdlAddress = IoAllocateMdl(dataBuffer,
02212                                             sizeof(READ_CAPACITY_DATA),
02213                                             FALSE,
02214                                             FALSE,
02215                                             (PIRP) NULL);
02216 
02217             if (!irp2->MdlAddress) {
02218                 Irp->IoStatus.Information = 0;
02219                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02220                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
02221                 ExFreePool(senseBuffer);
02222                 ExFreePool(srb);
02223                 ExFreePool(dataBuffer);
02224                 IoFreeIrp(irp2);
02225                 IoStartNextPacket(DeviceObject, FALSE);
02226                 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
02227                 return;
02228             }
02229 
02230             //
02231             // Prepare the MDL
02232             //
02233 
02234             MmBuildMdlForNonPagedPool(irp2->MdlAddress);
02235 
02236             srb->DataBuffer = dataBuffer;
02237             cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
02238 
02239             IoCallDriver(deviceExtension->PortDeviceObject, irp2);
02240             return;
02241         }
02242 
02243         case IOCTL_CDROM_CHECK_VERIFY: {
02244 
02245             //
02246             // Since a test unit ready is about to be performed, reset the timer
02247             // value to decrease the opportunities for it to race with this code.
02248             //
02249 
02250             cdData->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
02251 
02252             //
02253             // Set up the SRB/CDB
02254             //
02255 
02256             srb->CdbLength = 6;
02257             cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
02258             srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
02259             srb->SrbFlags = deviceExtension->SrbFlags;
02260             srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
02261 
02262             DebugPrint((2, "ScsiCdRomStartIo: [%lx] Sending CHECK_VERIFY irp %lx\n", Irp, irp2));
02263             IoCallDriver(deviceExtension->PortDeviceObject, irp2);
02264             return;
02265         }
02266 
02267         case IOCTL_CDROM_GET_LAST_SESSION:
02268 
02269             //
02270             // Set format to return first and last session numbers.
02271             //
02272 
02273             cdb->READ_TOC.Format = GET_LAST_SESSION;
02274 
02275             //
02276             // Fall through to READ TOC code.
02277             //
02278 
02279         case IOCTL_CDROM_READ_TOC: {
02280 
02281 
02282             if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) {
02283 
02284                 //
02285                 // Use MSF addressing if not request for session information.
02286                 //
02287 
02288                 cdb->READ_TOC.Msf = CDB_USE_MSF;
02289             }
02290 
02291             //
02292             // Set size of TOC structure.
02293             //
02294 
02295             transferByteCount =
02296                 currentIrpStack->Parameters.Read.Length >
02297                     sizeof(CDROM_TOC) ? sizeof(CDROM_TOC):
02298                     currentIrpStack->Parameters.Read.Length;
02299 
02300             cdb->READ_TOC.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
02301             cdb->READ_TOC.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
02302 
02303             cdb->READ_TOC.Control = 0;
02304 
02305             //
02306             // Start at beginning of disc.
02307             //
02308 
02309             cdb->READ_TOC.StartingTrack = 0;
02310 
02311             //
02312             // setup remaining srb and cdb parameters.
02313             //
02314 
02315             srb->SrbFlags = deviceExtension->SrbFlags;
02316             srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
02317             srb->DataTransferLength = transferByteCount;
02318             srb->CdbLength = 10;
02319             srb->TimeOutValue = deviceExtension->TimeOutValue;
02320 
02321             dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount);
02322             if (!dataBuffer) {
02323                 Irp->IoStatus.Information = 0;
02324                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02325                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
02326                 ExFreePool(senseBuffer);
02327                 ExFreePool(srb);
02328                 IoFreeIrp(irp2);
02329                 IoStartNextPacket(DeviceObject, FALSE);
02330                 return;
02331 
02332             }
02333 
02334             irp2->MdlAddress = IoAllocateMdl(dataBuffer,
02335                                             transferByteCount,
02336                                             FALSE,
02337                                             FALSE,
02338                                             (PIRP) NULL);
02339 
02340             if (!irp2->MdlAddress) {
02341                 Irp->IoStatus.Information = 0;
02342                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02343                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
02344                 ExFreePool(senseBuffer);
02345                 ExFreePool(srb);
02346                 ExFreePool(dataBuffer);
02347                 IoFreeIrp(irp2);
02348                 IoStartNextPacket(DeviceObject, FALSE);
02349                 return;
02350             }
02351 
02352             //
02353             // Prepare the MDL
02354             //
02355 
02356             MmBuildMdlForNonPagedPool(irp2->MdlAddress);
02357 
02358             srb->DataBuffer = dataBuffer;
02359             cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
02360 
02361             IoCallDriver(deviceExtension->PortDeviceObject, irp2);
02362             return;
02363 
02364         }
02365 
02366         case IOCTL_CDROM_PLAY_AUDIO_MSF: {
02367 
02368             PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
02369 
02370             //
02371             // Set up the SRB/CDB
02372             //
02373 
02374             srb->CdbLength = 10;
02375             cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
02376 
02377             cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
02378             cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
02379             cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
02380 
02381             cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
02382             cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
02383             cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
02384 
02385             srb->TimeOutValue = deviceExtension->TimeOutValue;
02386             srb->SrbFlags = deviceExtension->SrbFlags;
02387             srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
02388 
02389             IoCallDriver(deviceExtension->PortDeviceObject, irp2);
02390             return;
02391 
02392         }
02393 
02394         case IOCTL_CDROM_READ_Q_CHANNEL: {
02395 
02396             PCDROM_SUB_Q_DATA_FORMAT inputBuffer =
02397                              Irp->AssociatedIrp.SystemBuffer;
02398 
02399             //
02400             // Allocate buffer for subq channel information.
02401             //
02402 
02403             dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
02404                                      sizeof(SUB_Q_CHANNEL_DATA));
02405 
02406             if (!dataBuffer) {
02407                 Irp->IoStatus.Information = 0;
02408                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02409                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
02410                 ExFreePool(senseBuffer);
02411                 ExFreePool(srb);
02412                 IoFreeIrp(irp2);
02413                 IoStartNextPacket(DeviceObject, FALSE);
02414                 return;
02415 
02416             }
02417 
02418             irp2->MdlAddress = IoAllocateMdl(dataBuffer,
02419                                             transferByteCount,
02420                                             FALSE,
02421                                             FALSE,
02422                                             (PIRP) NULL);
02423 
02424             if (!irp2->MdlAddress) {
02425                 Irp->IoStatus.Information = 0;
02426                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02427                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
02428                 ExFreePool(senseBuffer);
02429                 ExFreePool(srb);
02430                 ExFreePool(dataBuffer);
02431                 IoFreeIrp(irp2);
02432                 IoStartNextPacket(DeviceObject, FALSE);
02433                 return;
02434             }
02435 
02436             //
02437             // Prepare the MDL
02438             //
02439 
02440             MmBuildMdlForNonPagedPool(irp2->MdlAddress);
02441 
02442             srb->DataBuffer = dataBuffer;
02443 
02444             //
02445             // Always logical unit 0, but only use MSF addressing
02446             // for IOCTL_CDROM_CURRENT_POSITION
02447             //
02448 
02449             if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION)
02450                 cdb->SUBCHANNEL.Msf = CDB_USE_MSF;
02451 
02452             //
02453             // Return subchannel data
02454             //
02455 
02456             cdb->SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK;
02457 
02458             //
02459             // Specify format of informatin to return
02460             //
02461 
02462             cdb->SUBCHANNEL.Format = inputBuffer->Format;
02463 
02464             //
02465             // Specify which track to access (only used by Track ISRC reads)
02466             //
02467 
02468             if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC) {
02469                 cdb->SUBCHANNEL.TrackNumber = inputBuffer->Track;
02470             }
02471 
02472             //
02473             // Set size of channel data -- however, this is dependent on
02474             // what information we are requesting (which Format)
02475             //
02476 
02477             switch( inputBuffer->Format ) {
02478 
02479                 case IOCTL_CDROM_CURRENT_POSITION:
02480                     transferByteCount = sizeof(SUB_Q_CURRENT_POSITION);
02481                     break;
02482 
02483                 case IOCTL_CDROM_MEDIA_CATALOG:
02484                     transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
02485                     break;
02486 
02487                 case IOCTL_CDROM_TRACK_ISRC:
02488                     transferByteCount = sizeof(SUB_Q_TRACK_ISRC);
02489                     break;
02490             }
02491 
02492             cdb->SUBCHANNEL.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
02493             cdb->SUBCHANNEL.AllocationLength[1] = (UCHAR) (transferByteCount &  0xFF);
02494             cdb->SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL;
02495             srb->SrbFlags = deviceExtension->SrbFlags;
02496             srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
02497             srb->DataTransferLength = transferByteCount;
02498             srb->CdbLength = 10;
02499             srb->TimeOutValue = deviceExtension->TimeOutValue;
02500 
02501             IoCallDriver(deviceExtension->PortDeviceObject, irp2);
02502             return;
02503 
02504         }
02505 
02506         case IOCTL_CDROM_PAUSE_AUDIO: {
02507 
02508             cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
02509             cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE;
02510 
02511             srb->CdbLength = 10;
02512             srb->TimeOutValue = deviceExtension->TimeOutValue;
02513             srb->SrbFlags = deviceExtension->SrbFlags;
02514             srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
02515 
02516             IoCallDriver(deviceExtension->PortDeviceObject, irp2);
02517             return;
02518         }
02519 
02520         case IOCTL_CDROM_RESUME_AUDIO: {
02521 
02522             cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
02523             cdb->PAUSE_RESUME.Action = CDB_AUDIO_RESUME;
02524 
02525             srb->CdbLength = 10;
02526             srb->TimeOutValue = deviceExtension->TimeOutValue;
02527             srb->SrbFlags = deviceExtension->SrbFlags;
02528             srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
02529 
02530             IoCallDriver(deviceExtension->PortDeviceObject, irp2);
02531             return;
02532         }
02533 
02534         case IOCTL_CDROM_SEEK_AUDIO_MSF: {
02535 
02536             PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
02537             ULONG                 logicalBlockAddress;
02538 
02539             logicalBlockAddress = MSF_TO_LBA(inputBuffer->M, inputBuffer->S, inputBuffer->F);
02540 
02541             cdb->SEEK.OperationCode      = SCSIOP_SEEK;
02542             cdb->SEEK.LogicalBlockAddress[0] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
02543             cdb->SEEK.LogicalBlockAddress[1] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
02544             cdb->SEEK.LogicalBlockAddress[2] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
02545             cdb->SEEK.LogicalBlockAddress[3] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
02546 
02547             srb->CdbLength                = 10;
02548             srb->TimeOutValue             = deviceExtension->TimeOutValue;
02549             srb->SrbFlags = deviceExtension->SrbFlags;
02550             srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
02551 
02552             IoCallDriver(deviceExtension->PortDeviceObject, irp2);
02553             return;
02554 
02555         }
02556 
02557         case IOCTL_CDROM_STOP_AUDIO: {
02558 
02559             cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
02560             cdb->START_STOP.Immediate = 1;
02561             cdb->START_STOP.Start = 0;
02562             cdb->START_STOP.LoadEject = 0;
02563 
02564             srb->CdbLength = 6;
02565             srb->TimeOutValue = deviceExtension->TimeOutValue;
02566 
02567             srb->SrbFlags = deviceExtension->SrbFlags;
02568             srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
02569 
02570             IoCallDriver(deviceExtension->PortDeviceObject, irp2);
02571             return;
02572         }
02573 
02574         case IOCTL_CDROM_GET_CONTROL: {
02575             //
02576             // Allocate buffer for volume control information.
02577             //
02578 
02579             dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
02580                                          MODE_DATA_SIZE);
02581 
02582             if (!dataBuffer) {
02583                 Irp->IoStatus.Information = 0;
02584                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02585                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
02586                 ExFreePool(senseBuffer);
02587                 ExFreePool(srb);
02588                 IoFreeIrp(irp2);
02589                 IoStartNextPacket(DeviceObject, FALSE);
02590                 return;
02591 
02592             }
02593 
02594             irp2->MdlAddress = IoAllocateMdl(dataBuffer,
02595                                             MODE_DATA_SIZE,
02596                                             FALSE,
02597                                             FALSE,
02598                                             (PIRP) NULL);
02599 
02600             if (!irp2->MdlAddress) {
02601                 Irp->IoStatus.Information = 0;
02602                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02603                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
02604                 ExFreePool(senseBuffer);
02605                 ExFreePool(srb);
02606                 ExFreePool(dataBuffer);
02607                 IoFreeIrp(irp2);
02608                 IoStartNextPacket(DeviceObject, FALSE);
02609                 return;
02610             }
02611 
02612             //
02613             // Prepare the MDL
02614             //
02615 
02616             MmBuildMdlForNonPagedPool(irp2->MdlAddress);
02617             srb->DataBuffer = dataBuffer;
02618 
02619             RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
02620 
02621             //
02622             // Setup for either 6 or 10 byte CDBs.
02623             //
02624 
02625             if (use6Byte) {
02626 
02627                 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
02628                 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
02629                 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
02630 
02631                 //
02632                 // Disable block descriptors.
02633                 //
02634 
02635                 cdb->MODE_SENSE.Dbd = TRUE;
02636 
02637                 srb->CdbLength = 6;
02638             } else {
02639 
02640                 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
02641                 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
02642                 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
02643                 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
02644 
02645                 //
02646                 // Disable block descriptors.
02647                 //
02648 
02649                 cdb->MODE_SENSE10.Dbd = TRUE;
02650 
02651                 srb->CdbLength = 10;
02652             }
02653 
02654             srb->TimeOutValue = deviceExtension->TimeOutValue;
02655             srb->DataTransferLength = MODE_DATA_SIZE;
02656             srb->SrbFlags = deviceExtension->SrbFlags;
02657             srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
02658 
02659             IoCallDriver(deviceExtension->PortDeviceObject, irp2);
02660             return;
02661 
02662         }
02663 
02664         case IOCTL_CDROM_GET_VOLUME:
02665         case IOCTL_CDROM_SET_VOLUME: {
02666 
02667             dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
02668                                          MODE_DATA_SIZE);
02669 
02670             if (!dataBuffer) {
02671                 Irp->IoStatus.Information = 0;
02672                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02673                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
02674                 ExFreePool(senseBuffer);
02675                 ExFreePool(srb);
02676                 IoFreeIrp(irp2);
02677                 IoStartNextPacket(DeviceObject, FALSE);
02678                 return;
02679             }
02680 
02681             irp2->MdlAddress = IoAllocateMdl(dataBuffer,
02682                                             MODE_DATA_SIZE,
02683                                             FALSE,
02684                                             FALSE,
02685                                             (PIRP) NULL);
02686 
02687             if (!irp2->MdlAddress) {
02688                 Irp->IoStatus.Information = 0;
02689                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02690                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
02691                 ExFreePool(senseBuffer);
02692                 ExFreePool(srb);
02693                 ExFreePool(dataBuffer);
02694                 IoFreeIrp(irp2);
02695                 IoStartNextPacket(DeviceObject, FALSE);
02696                 return;
02697             }
02698 
02699             //
02700             // Prepare the MDL
02701             //
02702 
02703             MmBuildMdlForNonPagedPool(irp2->MdlAddress);
02704             srb->DataBuffer = dataBuffer;
02705 
02706             RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
02707 
02708 
02709             if (use6Byte) {
02710                 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
02711                 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
02712                 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
02713 
02714                 srb->CdbLength = 6;
02715 
02716             } else {
02717 
02718                 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
02719                 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
02720                 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
02721                 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
02722 
02723                 srb->CdbLength = 10;
02724             }
02725 
02726             srb->TimeOutValue = deviceExtension->TimeOutValue;
02727             srb->DataTransferLength = MODE_DATA_SIZE;
02728             srb->SrbFlags = deviceExtension->SrbFlags;
02729             srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
02730 
02731             if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_SET_VOLUME) {
02732 
02733                 //
02734                 // Setup a different completion routine as the mode sense data is needed in order
02735                 // to send the mode select.
02736                 //
02737 
02738                 IoSetCompletionRoutine(irp2,
02739                                        CdRomSetVolumeIntermediateCompletion,
02740                                        srb,
02741                                        TRUE,
02742                                        TRUE,
02743                                        TRUE);
02744 
02745             }
02746 
02747             IoCallDriver(deviceExtension->PortDeviceObject, irp2);
02748             return;
02749 
02750         }
02751 
02752         default:
02753 
02754             //
02755             // Just complete the request - CdRomClassIoctlCompletion will take
02756             // care of it for us
02757             //
02758 
02759             IoCompleteRequest(Irp, IO_NO_INCREMENT);
02760             return;
02761 
02762         } // end switch()
02763     }
02764 
02765     //
02766     // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
02767     // are expected and composed of AutoRun Irps, at present.
02768     //
02769 
02770     IoCallDriver(deviceExtension->PortDeviceObject, Irp);
02771     return;
02772 }
02773 
02774 
02775 NTSTATUS
02776 NTAPI
02777 ScsiCdRomReadVerification(
02778     IN PDEVICE_OBJECT DeviceObject,
02779     IN PIRP Irp
02780     )
02781 
02782 /*++
02783 
02784 Routine Description:
02785 
02786     This is the entry called by the I/O system for read requests.
02787     It builds the SRB and sends it to the port driver.
02788 
02789 Arguments:
02790 
02791     DeviceObject - the system object for the device.
02792     Irp - IRP involved.
02793 
02794 Return Value:
02795 
02796     NT Status
02797 
02798 --*/
02799 
02800 {
02801     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
02802     PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
02803     ULONG               transferByteCount = currentIrpStack->Parameters.Read.Length;
02804     LARGE_INTEGER       startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
02805 
02806     //
02807     // If the cd is playing music then reject this request.
02808     //
02809 
02810     if (PLAY_ACTIVE(deviceExtension)) {
02811         Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
02812         return STATUS_DEVICE_BUSY;
02813     }
02814 
02815     //
02816     // Verify parameters of this request.
02817     // Check that ending sector is on disc and
02818     // that number of bytes to transfer is a multiple of
02819     // the sector size.
02820     //
02821 
02822     startingOffset.QuadPart = currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
02823                               transferByteCount;
02824 
02825     if (!deviceExtension->DiskGeometry->Geometry.BytesPerSector) {
02826         deviceExtension->DiskGeometry->Geometry.BytesPerSector = 2048;
02827     }
02828 
02829     if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) ||
02830         (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1))) {
02831 
02832         DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n"));
02833         DebugPrint((1, "\toffset %x:%x, Length %x:%x\n",
02834                     startingOffset.u.HighPart,
02835                     startingOffset.u.LowPart,
02836                     deviceExtension->PartitionLength.u.HighPart,
02837                     deviceExtension->PartitionLength.u.LowPart));
02838         DebugPrint((1, "\tbps %x\n", deviceExtension->DiskGeometry->Geometry.BytesPerSector));
02839 
02840         //
02841         // Fail request with status of invalid parameters.
02842         //
02843 
02844         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
02845 
02846         return STATUS_INVALID_PARAMETER;
02847     }
02848 
02849 
02850     return STATUS_SUCCESS;
02851 
02852 } // end ScsiCdRomReadVerification()
02853 
02854 
02855 NTSTATUS
02856 NTAPI
02857 CdRomDeviceControlCompletion(
02858     IN PDEVICE_OBJECT DeviceObject,
02859     IN PIRP Irp,
02860     IN PVOID Context
02861     )
02862 {
02863     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
02864     PDEVICE_EXTENSION   physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension;
02865     PIO_STACK_LOCATION  irpStack        = IoGetCurrentIrpStackLocation(Irp);
02866     PCDROM_DATA         cdData = (PCDROM_DATA)(deviceExtension + 1);
02867     BOOLEAN             use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
02868     PIO_STACK_LOCATION  realIrpStack;
02869     PIO_STACK_LOCATION  realIrpNextStack;
02870     PSCSI_REQUEST_BLOCK srb     = Context;
02871     PIRP                realIrp = NULL;
02872     NTSTATUS            status;
02873     BOOLEAN             retry;
02874 
02875     //
02876     // Extract the 'real' irp from the irpstack.
02877     //
02878 
02879     realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
02880     realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
02881     realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
02882 
02883     //
02884     // Check SRB status for success of completing request.
02885     //
02886 
02887     if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
02888 
02889         DebugPrint((2,
02890                     "CdRomDeviceControlCompletion: Irp %lx, Srb %lx Real Irp %lx Status %lx\n",
02891                     Irp,
02892                     srb,
02893                     realIrp,
02894                     srb->SrbStatus));
02895 
02896         //
02897         // Release the queue if it is frozen.
02898         //
02899 
02900         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
02901             DebugPrint((2, "CdRomDeviceControlCompletion: Releasing Queue\n"));
02902             ScsiClassReleaseQueue(DeviceObject);
02903         }
02904 
02905 
02906         retry = ScsiClassInterpretSenseInfo(DeviceObject,
02907                                             srb,
02908                                             irpStack->MajorFunction,
02909                                             irpStack->Parameters.DeviceIoControl.IoControlCode,
02910                                             MAXIMUM_RETRIES - ((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
02911                                             &status);
02912 
02913         DebugPrint((2, "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
02914                     (retry ? "" : "not ")));
02915 
02916         //
02917         // Some of the Device Controls need special cases on non-Success status's.
02918         //
02919 
02920         if (realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
02921             if ((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) ||
02922                 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC)         ||
02923                 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_CONTROL)      ||
02924                 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_VOLUME)) {
02925 
02926                 if (status == STATUS_DATA_OVERRUN) {
02927                     status = STATUS_SUCCESS;
02928                     retry = FALSE;
02929                 }
02930             }
02931 
02932             if (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_Q_CHANNEL) {
02933                 PLAY_ACTIVE(deviceExtension) = FALSE;
02934             }
02935         }
02936 
02937         //
02938         // If the status is verified required and the this request
02939         // should bypass verify required then retry the request.
02940         //
02941 
02942         if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
02943             status == STATUS_VERIFY_REQUIRED) {
02944 
02945             if (((realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) ||
02946                 (realIrpStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)) &&
02947                 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY)) {
02948 
02949                 //
02950                 // Update the geometry information, as the media could have changed.
02951                 // The completion routine for this will complete the real irp and start
02952                 // the next packet.
02953                 //
02954 
02955                 status = CdRomUpdateCapacity(deviceExtension,realIrp, NULL);
02956                 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] CdRomUpdateCapacity completed with status %lx\n", realIrp, status));
02957                 ASSERT(status == STATUS_PENDING);
02958 
02959                 return STATUS_MORE_PROCESSING_REQUIRED;
02960 
02961             } else {
02962 
02963                 status = STATUS_IO_DEVICE_ERROR;
02964                 retry = TRUE;
02965             }
02966 
02967         }
02968 
02969         if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1-1))) {
02970 
02971 
02972             if (((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
02973 
02974                 //
02975                 // Retry request.
02976                 //
02977 
02978                 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp));
02979 
02980 
02981                 ExFreePool(srb->SenseInfoBuffer);
02982                 if (srb->DataBuffer) {
02983                     ExFreePool(srb->DataBuffer);
02984                 }
02985                 ExFreePool(srb);
02986                 if (Irp->MdlAddress) {
02987                     IoFreeMdl(Irp->MdlAddress);
02988                 }
02989 
02990                 IoFreeIrp(Irp);
02991 
02992                 //
02993                 // Call StartIo directly since IoStartNextPacket hasn't been called,
02994                 // the serialisation is still intact.
02995                 //
02996 
02997                 ScsiCdRomStartIo(DeviceObject, realIrp);
02998                 return STATUS_MORE_PROCESSING_REQUIRED;
02999 
03000             }
03001 
03002             //
03003             // Exhausted retries. Fall through and complete the request with the appropriate status.
03004             //
03005 
03006         }
03007     } else {
03008 
03009         //
03010         // Set status for successful request.
03011         //
03012 
03013         status = STATUS_SUCCESS;
03014     }
03015 
03016     if (NT_SUCCESS(status)) {
03017 
03018         switch (realIrpStack->Parameters.DeviceIoControl.IoControlCode) {
03019 
03020         case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
03021 
03022             PREAD_CAPACITY_DATA readCapacityBuffer = srb->DataBuffer;
03023             ULONG               lastSector;
03024             ULONG               bps;
03025             ULONG               lastBit;
03026             ULONG               tmp;
03027 
03028             //
03029             // Swizzle bytes from Read Capacity and translate into
03030             // the necessary geometry information in the device extension.
03031             //
03032 
03033             tmp = readCapacityBuffer->BytesPerBlock;
03034             ((PFOUR_BYTE)&bps)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
03035             ((PFOUR_BYTE)&bps)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
03036             ((PFOUR_BYTE)&bps)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
03037             ((PFOUR_BYTE)&bps)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
03038 
03039             //
03040             // Insure that bps is a power of 2.
03041             // This corrects a problem with the HP 4020i CDR where it
03042             // returns an incorrect number for bytes per sector.
03043             //
03044 
03045             if (!bps) {
03046                 bps = 2048;
03047             } else {
03048                 lastBit = (ULONG) -1;
03049                 while (bps) {
03050                     lastBit++;
03051                     bps = bps >> 1;
03052                 }
03053 
03054                 bps = 1 << lastBit;
03055             }
03056             deviceExtension->DiskGeometry->Geometry.BytesPerSector = bps;
03057 
03058             DebugPrint((2,
03059                         "CdRomDeviceControlCompletion: Calculated bps %#x\n",
03060                         deviceExtension->DiskGeometry->Geometry.BytesPerSector));
03061 
03062             //
03063             // Copy last sector in reverse byte order.
03064             //
03065 
03066             tmp = readCapacityBuffer->LogicalBlockAddress;
03067             ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
03068             ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
03069             ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
03070             ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
03071 
03072             //
03073             // Calculate sector to byte shift.
03074             //
03075 
03076             WHICH_BIT(bps, deviceExtension->SectorShift);
03077 
03078             DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
03079                 deviceExtension->DiskGeometry->Geometry.BytesPerSector));
03080 
03081             DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
03082                 lastSector + 1));
03083 
03084             //
03085             // Calculate media capacity in bytes.
03086             //
03087 
03088             deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
03089 
03090             //
03091             // Calculate number of cylinders.
03092             //
03093 
03094             deviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64));
03095 
03096             deviceExtension->PartitionLength.QuadPart =
03097                 (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
03098 
03099             if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
03100 
03101                 //
03102                 // This device supports removable media.
03103                 //
03104 
03105                 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia;
03106 
03107             } else {
03108 
03109                 //
03110                 // Assume media type is fixed disk.
03111                 //
03112 
03113                 deviceExtension->DiskGeometry->Geometry.MediaType = FixedMedia;
03114             }
03115 
03116             //
03117             // Assume sectors per track are 32;
03118             //
03119 
03120             deviceExtension->DiskGeometry->Geometry.SectorsPerTrack = 32;
03121 
03122             //
03123             // Assume tracks per cylinder (number of heads) is 64.
03124             //
03125 
03126             deviceExtension->DiskGeometry->Geometry.TracksPerCylinder = 64;
03127 
03128             //
03129             // Copy the device extension's geometry info into the user buffer.
03130             //
03131 
03132             RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
03133                           deviceExtension->DiskGeometry,
03134                           sizeof(DISK_GEOMETRY));
03135 
03136             //
03137             // update information field.
03138             //
03139 
03140             realIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
03141             break;
03142         }
03143 
03144         case IOCTL_CDROM_CHECK_VERIFY:
03145 
03146             if((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY) &&
03147                (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength)) {
03148 
03149                 *((PULONG)realIrp->AssociatedIrp.SystemBuffer) =
03150                     physicalExtension->MediaChangeCount;
03151                 realIrp->IoStatus.Information = sizeof(ULONG);
03152             } else {
03153                 realIrp->IoStatus.Information = 0;
03154             }
03155 
03156             DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] completing CHECK_VERIFY buddy irp %lx\n", realIrp, Irp));
03157             break;
03158 
03159         case IOCTL_CDROM_GET_LAST_SESSION:
03160         case IOCTL_CDROM_READ_TOC: {
03161 
03162                 PCDROM_TOC toc = srb->DataBuffer;
03163 
03164                 //
03165                 // Copy the device extension's geometry info into the user buffer.
03166                 //
03167 
03168                 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
03169                               toc,
03170                               srb->DataTransferLength);
03171 
03172                 //
03173                 // update information field.
03174                 //
03175 
03176                 realIrp->IoStatus.Information = srb->DataTransferLength;
03177                 break;
03178             }
03179 
03180         case IOCTL_CDROM_PLAY_AUDIO_MSF:
03181 
03182             PLAY_ACTIVE(deviceExtension) = TRUE;
03183 
03184             break;
03185 
03186         case IOCTL_CDROM_READ_Q_CHANNEL: {
03187 
03188             PSUB_Q_CHANNEL_DATA userChannelData = realIrp->AssociatedIrp.SystemBuffer;
03189 #if DBG
03190             PCDROM_SUB_Q_DATA_FORMAT inputBuffer = realIrp->AssociatedIrp.SystemBuffer;
03191 #endif
03192             PSUB_Q_CHANNEL_DATA subQPtr = srb->DataBuffer;
03193 
03194 #if DBG
03195             switch( inputBuffer->Format ) {
03196 
03197             case IOCTL_CDROM_CURRENT_POSITION:
03198                 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->CurrentPosition.Header.AudioStatus ));
03199                 DebugPrint((2,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr->CurrentPosition.ADR ));
03200                 DebugPrint((2,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr->CurrentPosition.Control ));
03201                 DebugPrint((2,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr->CurrentPosition.TrackNumber ));
03202                 DebugPrint((2,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr->CurrentPosition.IndexNumber ));
03203                 DebugPrint((2,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG)subQPtr->CurrentPosition.AbsoluteAddress) ));
03204                 DebugPrint((2,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG)subQPtr->CurrentPosition.TrackRelativeAddress) ));
03205                 break;
03206 
03207             case IOCTL_CDROM_MEDIA_CATALOG:
03208                 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->MediaCatalog.Header.AudioStatus ));
03209                 DebugPrint((2,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr->MediaCatalog.Mcval ));
03210                 break;
03211 
03212             case IOCTL_CDROM_TRACK_ISRC:
03213                 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->TrackIsrc.Header.AudioStatus ));
03214                 DebugPrint((2,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr->TrackIsrc.Tcval ));
03215                 break;
03216 
03217             }
03218 #endif
03219 
03220             //
03221             // Update the play active status.
03222             //
03223 
03224             if (subQPtr->CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
03225 
03226                 PLAY_ACTIVE(deviceExtension) = TRUE;
03227 
03228             } else {
03229 
03230                 PLAY_ACTIVE(deviceExtension) = FALSE;
03231 
03232             }
03233 
03234             //
03235             // Check if output buffer is large enough to contain
03236             // the data.
03237             //
03238 
03239             if (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
03240                 srb->DataTransferLength) {
03241 
03242                 srb->DataTransferLength =
03243                     realIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
03244             }
03245 
03246             //
03247             // Copy our buffer into users.
03248             //
03249 
03250             RtlMoveMemory(userChannelData,
03251                           subQPtr,
03252                           srb->DataTransferLength);
03253 
03254             realIrp->IoStatus.Information = srb->DataTransferLength;
03255             break;
03256         }
03257 
03258         case IOCTL_CDROM_PAUSE_AUDIO:
03259 
03260             PLAY_ACTIVE(deviceExtension) = FALSE;
03261             realIrp->IoStatus.Information = 0;
03262             break;
03263 
03264         case IOCTL_CDROM_RESUME_AUDIO:
03265 
03266             realIrp->IoStatus.Information = 0;
03267             break;
03268 
03269         case IOCTL_CDROM_SEEK_AUDIO_MSF:
03270 
03271             realIrp->IoStatus.Information = 0;
03272             break;
03273 
03274         case IOCTL_CDROM_STOP_AUDIO:
03275 
03276             PLAY_ACTIVE(deviceExtension) = FALSE;
03277 
03278             realIrp->IoStatus.Information = 0;
03279             break;
03280 
03281         case IOCTL_CDROM_GET_CONTROL: {
03282 
03283             PCDROM_AUDIO_CONTROL audioControl = srb->DataBuffer;
03284             PAUDIO_OUTPUT        audioOutput;
03285             ULONG                bytesTransferred;
03286 
03287             audioOutput = ScsiClassFindModePage((PCHAR)audioControl,
03288                                                 srb->DataTransferLength,
03289                                                 CDROM_AUDIO_CONTROL_PAGE,
03290                                                 use6Byte);
03291             //
03292             // Verify the page is as big as expected.
03293             //
03294 
03295             bytesTransferred = (PCHAR) audioOutput - (PCHAR) audioControl +
03296                                sizeof(AUDIO_OUTPUT);
03297 
03298             if (audioOutput != NULL &&
03299                 srb->DataTransferLength >= bytesTransferred) {
03300 
03301                 audioControl->LbaFormat = audioOutput->LbaFormat;
03302 
03303                 audioControl->LogicalBlocksPerSecond =
03304                     (audioOutput->LogicalBlocksPerSecond[0] << (UCHAR)8) |
03305                     audioOutput->LogicalBlocksPerSecond[1];
03306 
03307                 realIrp->IoStatus.Information = sizeof(CDROM_AUDIO_CONTROL);
03308 
03309             } else {
03310                 realIrp->IoStatus.Information = 0;
03311                 status = STATUS_INVALID_DEVICE_REQUEST;
03312             }
03313             break;
03314         }
03315 
03316         case IOCTL_CDROM_GET_VOLUME: {
03317 
03318             PAUDIO_OUTPUT audioOutput;
03319             PVOLUME_CONTROL volumeControl = srb->DataBuffer;
03320             ULONG i,bytesTransferred;
03321 
03322             audioOutput = ScsiClassFindModePage((PCHAR)volumeControl,
03323                                                  srb->DataTransferLength,
03324                                                  CDROM_AUDIO_CONTROL_PAGE,
03325                                                  use6Byte);
03326 
03327             //
03328             // Verify the page is as big as expected.
03329             //
03330 
03331             bytesTransferred = (PCHAR) audioOutput - (PCHAR) volumeControl +
03332                                sizeof(AUDIO_OUTPUT);
03333 
03334             if (audioOutput != NULL &&
03335                 srb->DataTransferLength >= bytesTransferred) {
03336 
03337                 for (i=0; i<4; i++) {
03338                     volumeControl->PortVolume[i] =
03339                         audioOutput->PortOutput[i].Volume;
03340                 }
03341 
03342                 //
03343                 // Set bytes transferred in IRP.
03344                 //
03345 
03346                 realIrp->IoStatus.Information = sizeof(VOLUME_CONTROL);
03347 
03348             } else {
03349                 realIrp->IoStatus.Information = 0;
03350                 status = STATUS_INVALID_DEVICE_REQUEST;
03351             }
03352 
03353             break;
03354         }
03355 
03356         case IOCTL_CDROM_SET_VOLUME:
03357 
03358             realIrp->IoStatus.Information = sizeof(VOLUME_CONTROL);
03359             break;
03360 
03361         default:
03362 
03363             ASSERT(FALSE);
03364             realIrp->IoStatus.Information = 0;
03365             status = STATUS_INVALID_DEVICE_REQUEST;
03366 
03367         } // end switch()
03368     }
03369 
03370     //
03371     // Deallocate srb and sense buffer.
03372     //
03373 
03374     if (srb) {
03375         if (srb->DataBuffer) {
03376             ExFreePool(srb->DataBuffer);
03377         }
03378         if (srb->SenseInfoBuffer) {
03379             ExFreePool(srb->SenseInfoBuffer);
03380         }
03381         ExFreePool(srb);
03382     }
03383 
03384     if (realIrp->PendingReturned) {
03385         IoMarkIrpPending(realIrp);
03386     }
03387 
03388     if (Irp->MdlAddress) {
03389         IoFreeMdl(Irp->MdlAddress);
03390     }
03391 
03392     IoFreeIrp(Irp);
03393 
03394     //
03395     // Set status in completing IRP.
03396     //
03397 
03398     realIrp->IoStatus.Status = status;
03399 
03400     //
03401     // Set the hard error if necessary.
03402     //
03403 
03404     if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
03405 
03406         //
03407         // Store DeviceObject for filesystem, and clear
03408         // in IoStatus.Information field.
03409         //
03410 
03411         DebugPrint((1, "CdRomDeviceCompletion - Setting Hard Error on realIrp %lx\n",
03412                     realIrp));
03413         IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
03414         realIrp->IoStatus.Information = 0;
03415     }
03416 
03417     IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
03418 
03419     IoStartNextPacket(DeviceObject, FALSE);
03420 
03421     return STATUS_MORE_PROCESSING_REQUIRED;
03422 }
03423 
03424 NTSTATUS
03425 NTAPI
03426 CdRomSetVolumeIntermediateCompletion(
03427     IN PDEVICE_OBJECT DeviceObject,
03428     IN PIRP Irp,
03429     IN PVOID Context
03430     )
03431 {
03432     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
03433     PIO_STACK_LOCATION  irpStack        = IoGetCurrentIrpStackLocation(Irp);
03434     PCDROM_DATA         cdData = (PCDROM_DATA)(deviceExtension + 1);
03435     BOOLEAN             use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
03436     PIO_STACK_LOCATION  realIrpStack;
03437     PIO_STACK_LOCATION  realIrpNextStack;
03438     PSCSI_REQUEST_BLOCK srb     = Context;
03439     PIRP                realIrp = NULL;
03440     NTSTATUS            status;
03441     BOOLEAN             retry;
03442 
03443     //
03444     // Extract the 'real' irp from the irpstack.
03445     //
03446 
03447     realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
03448     realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
03449     realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
03450 
03451     //
03452     // Check SRB status for success of completing request.
03453     //
03454 
03455     if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
03456 
03457         DebugPrint((2,
03458                     "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
03459                     Irp,
03460                     srb,
03461                     realIrp));
03462 
03463         //
03464         // Release the queue if it is frozen.
03465         //
03466 
03467         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
03468             ScsiClassReleaseQueue(DeviceObject);
03469         }
03470 
03471 
03472         retry = ScsiClassInterpretSenseInfo(DeviceObject,
03473                                             srb,
03474                                             irpStack->MajorFunction,
03475                                             irpStack->Parameters.DeviceIoControl.IoControlCode,
03476                                             MAXIMUM_RETRIES - ((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
03477                                             &status);
03478 
03479         if (status == STATUS_DATA_OVERRUN) {
03480             status = STATUS_SUCCESS;
03481             retry = FALSE;
03482         }
03483 
03484         //
03485         // If the status is verified required and the this request
03486         // should bypass verify required then retry the request.
03487         //
03488 
03489         if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
03490             status == STATUS_VERIFY_REQUIRED) {
03491 
03492             status = STATUS_IO_DEVICE_ERROR;
03493             retry = TRUE;
03494         }
03495 
03496         if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1-1))) {
03497 
03498             if (((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
03499 
03500                 //
03501                 // Retry request.
03502                 //
03503 
03504                 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp));
03505 
03506 
03507                 ExFreePool(srb->SenseInfoBuffer);
03508                 ExFreePool(srb->DataBuffer);
03509                 ExFreePool(srb);
03510                 if (Irp->MdlAddress) {
03511                     IoFreeMdl(Irp->MdlAddress);
03512                 }
03513 
03514                 IoFreeIrp(Irp);
03515 
03516                 //
03517                 // Call StartIo directly since IoStartNextPacket hasn't been called,
03518                 // the serialisation is still intact.
03519                 //
03520                 ScsiCdRomStartIo(DeviceObject, realIrp);
03521                 return STATUS_MORE_PROCESSING_REQUIRED;
03522 
03523             }
03524 
03525             //
03526             // Exhausted retries. Fall through and complete the request with the appropriate status.
03527             //
03528 
03529         }
03530     } else {
03531 
03532         //
03533         // Set status for successful request.
03534         //
03535 
03536         status = STATUS_SUCCESS;
03537     }
03538 
03539     if (NT_SUCCESS(status)) {
03540 
03541         PAUDIO_OUTPUT   audioInput = NULL;
03542         PAUDIO_OUTPUT   audioOutput;
03543         PVOLUME_CONTROL volumeControl = realIrp->AssociatedIrp.SystemBuffer;
03544         ULONG           i,bytesTransferred,headerLength;
03545         PVOID           dataBuffer;
03546         PCDB            cdb;
03547 
03548         audioInput = ScsiClassFindModePage((PCHAR)srb->DataBuffer,
03549                                              srb->DataTransferLength,
03550                                              CDROM_AUDIO_CONTROL_PAGE,
03551                                              use6Byte);
03552 
03553         //
03554         // Check to make sure the mode sense data is valid before we go on
03555         //
03556 
03557         if(audioInput == NULL) {
03558 
03559             DebugPrint((1, "Mode Sense Page %d not found\n",
03560                         CDROM_AUDIO_CONTROL_PAGE));
03561 
03562             realIrp->IoStatus.Information = 0;
03563             realIrp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
03564             IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
03565             ExFreePool(srb->SenseInfoBuffer);
03566             ExFreePool(srb);
03567             IoFreeMdl(Irp->MdlAddress);
03568             IoFreeIrp(Irp);
03569             return STATUS_MORE_PROCESSING_REQUIRED;
03570         }
03571 
03572         if (use6Byte) {
03573             headerLength = sizeof(MODE_PARAMETER_HEADER);
03574         } else {
03575             headerLength = sizeof(MODE_PARAMETER_HEADER10);
03576         }
03577 
03578         bytesTransferred = sizeof(AUDIO_OUTPUT) + headerLength;
03579 
03580         //
03581         // Allocate a new buffer for the mode select.
03582         //
03583 
03584         dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, bytesTransferred);
03585 
03586         if (!dataBuffer) {
03587             realIrp->IoStatus.Information = 0;
03588             realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
03589             IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
03590             ExFreePool(srb->SenseInfoBuffer);
03591             ExFreePool(srb);
03592             IoFreeMdl(Irp->MdlAddress);
03593             IoFreeIrp(Irp);
03594             return STATUS_MORE_PROCESSING_REQUIRED;
03595         }
03596 
03597         RtlZeroMemory(dataBuffer, bytesTransferred);
03598 
03599         //
03600         // Rebuild the data buffer to include the user requested values.
03601         //
03602 
03603         audioOutput = (PAUDIO_OUTPUT) ((PCHAR) dataBuffer + headerLength);
03604 
03605         for (i=0; i<4; i++) {
03606             audioOutput->PortOutput[i].Volume =
03607                 volumeControl->PortVolume[i];
03608             audioOutput->PortOutput[i].ChannelSelection =
03609                 audioInput->PortOutput[i].ChannelSelection;
03610         }
03611 
03612         audioOutput->CodePage = CDROM_AUDIO_CONTROL_PAGE;
03613         audioOutput->ParameterLength = sizeof(AUDIO_OUTPUT) - 2;
03614         audioOutput->Immediate = MODE_SELECT_IMMEDIATE;
03615 
03616         //
03617         // Free the old data buffer, mdl.
03618         //
03619 
03620         ExFreePool(srb->DataBuffer);
03621         IoFreeMdl(Irp->MdlAddress);
03622 
03623         //
03624         // rebuild the srb.
03625         //
03626 
03627         cdb = (PCDB)srb->Cdb;
03628         RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
03629 
03630         srb->SrbStatus = srb->ScsiStatus = 0;
03631         srb->SrbFlags = deviceExtension->SrbFlags;
03632         srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
03633         srb->DataTransferLength = bytesTransferred;
03634 
03635         if (use6Byte) {
03636 
03637             cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
03638             cdb->MODE_SELECT.ParameterListLength = (UCHAR) bytesTransferred;
03639             cdb->MODE_SELECT.PFBit = 1;
03640             srb->CdbLength = 6;
03641         } else {
03642 
03643             cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
03644             cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR) (bytesTransferred >> 8);
03645             cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR) (bytesTransferred & 0xFF);
03646             cdb->MODE_SELECT10.PFBit = 1;
03647             srb->CdbLength = 10;
03648         }
03649 
03650         //
03651         // Prepare the MDL
03652         //
03653 
03654         Irp->MdlAddress = IoAllocateMdl(dataBuffer,
03655                                         bytesTransferred,
03656                                         FALSE,
03657                                         FALSE,
03658                                         (PIRP) NULL);
03659 
03660         if (!Irp->MdlAddress) {
03661             realIrp->IoStatus.Information = 0;
03662             realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
03663             IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
03664             ExFreePool(srb->SenseInfoBuffer);
03665             ExFreePool(srb);
03666             ExFreePool(dataBuffer);
03667             IoFreeIrp(Irp);
03668             return STATUS_MORE_PROCESSING_REQUIRED;
03669 
03670         }
03671 
03672         MmBuildMdlForNonPagedPool(Irp->MdlAddress);
03673         srb->DataBuffer = dataBuffer;
03674 
03675         irpStack = IoGetNextIrpStackLocation(Irp);
03676         irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
03677         irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
03678         irpStack->Parameters.Scsi.Srb = srb;
03679 
03680         //
03681         // reset the irp completion.
03682         //
03683 
03684         IoSetCompletionRoutine(Irp,
03685                                CdRomDeviceControlCompletion,
03686                                srb,
03687                                TRUE,
03688                                TRUE,
03689                                TRUE);
03690         //
03691         // Call the port driver.
03692         //
03693 
03694         IoCallDriver(deviceExtension->PortDeviceObject, Irp);
03695 
03696         return STATUS_MORE_PROCESSING_REQUIRED;
03697     }
03698 
03699     //
03700     // Deallocate srb and sense buffer.
03701     //
03702 
03703     if (srb) {
03704         if (srb->DataBuffer) {
03705             ExFreePool(srb->DataBuffer);
03706         }
03707         if (srb->SenseInfoBuffer) {
03708             ExFreePool(srb->SenseInfoBuffer);
03709         }
03710         ExFreePool(srb);
03711     }
03712 
03713     if (Irp->PendingReturned) {
03714       IoMarkIrpPending(Irp);
03715     }
03716 
03717     if (realIrp->PendingReturned) {
03718         IoMarkIrpPending(realIrp);
03719     }
03720 
03721     if (Irp->MdlAddress) {
03722         IoFreeMdl(Irp->MdlAddress);
03723     }
03724 
03725     IoFreeIrp(Irp);
03726 
03727     //
03728     // Set status in completing IRP.
03729     //
03730 
03731     realIrp->IoStatus.Status = status;
03732 
03733     //
03734     // Set the hard error if necessary.
03735     //
03736 
03737     if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
03738 
03739         //
03740         // Store DeviceObject for filesystem, and clear
03741         // in IoStatus.Information field.
03742         //
03743 
03744         IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
03745         realIrp->IoStatus.Information = 0;
03746     }
03747 
03748     IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
03749 
03750     IoStartNextPacket(DeviceObject, FALSE);
03751 
03752     return STATUS_MORE_PROCESSING_REQUIRED;
03753 }
03754 
03755 
03756 NTSTATUS
03757 NTAPI
03758 CdRomSwitchModeCompletion(
03759     IN PDEVICE_OBJECT DeviceObject,
03760     IN PIRP Irp,
03761     IN PVOID Context
03762     )
03763 {
03764     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
03765     PIO_STACK_LOCATION  irpStack        = IoGetCurrentIrpStackLocation(Irp);
03766     PCDROM_DATA         cdData = (PCDROM_DATA)(deviceExtension + 1);
03767     PIO_STACK_LOCATION  realIrpStack;
03768     PIO_STACK_LOCATION  realIrpNextStack;
03769     PSCSI_REQUEST_BLOCK srb     = Context;
03770     PIRP                realIrp = NULL;
03771     NTSTATUS            status;
03772     BOOLEAN             retry;
03773 
03774     //
03775     // Extract the 'real' irp from the irpstack.
03776     //
03777 
03778     realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
03779     realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
03780     realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
03781 
03782     //
03783     // Check SRB status for success of completing request.
03784     //
03785 
03786     if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
03787 
03788         DebugPrint((2,
03789                     "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
03790                     Irp,
03791                     srb,
03792                     realIrp));
03793 
03794         //
03795         // Release the queue if it is frozen.
03796         //
03797 
03798         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
03799             ScsiClassReleaseQueue(DeviceObject);
03800         }
03801 
03802 
03803         retry = ScsiClassInterpretSenseInfo(DeviceObject,
03804                                             srb,
03805                                             irpStack->MajorFunction,
03806                                             irpStack->Parameters.DeviceIoControl.IoControlCode,
03807                                             MAXIMUM_RETRIES - ((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
03808                                             &status);
03809 
03810         //
03811         // If the status is verified required and the this request
03812         // should bypass verify required then retry the request.
03813         //
03814 
03815         if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
03816             status == STATUS_VERIFY_REQUIRED) {
03817 
03818             status = STATUS_IO_DEVICE_ERROR;
03819             retry = TRUE;
03820         }
03821 
03822         if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1-1))) {
03823 
03824             if (((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
03825 
03826                 //
03827                 // Retry request.
03828                 //
03829 
03830                 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp));
03831 
03832 
03833                 ExFreePool(srb->SenseInfoBuffer);
03834                 ExFreePool(srb->DataBuffer);
03835                 ExFreePool(srb);
03836                 if (Irp->MdlAddress) {
03837                     IoFreeMdl(Irp->MdlAddress);
03838                 }
03839 
03840                 IoFreeIrp(Irp);
03841 
03842                 //
03843                 // Call StartIo directly since IoStartNextPacket hasn't been called,
03844                 // the serialisation is still intact.
03845                 //
03846 
03847                 ScsiCdRomStartIo(DeviceObject, realIrp);
03848                 return STATUS_MORE_PROCESSING_REQUIRED;
03849 
03850             }
03851 
03852             //
03853             // Exhausted retries. Fall through and complete the request with the appropriate status.
03854             //
03855         }
03856     } else {
03857 
03858         //
03859         // Set status for successful request.
03860         //
03861 
03862         status = STATUS_SUCCESS;
03863     }
03864 
03865     if (NT_SUCCESS(status)) {
03866 
03867         ULONG sectorSize, startingSector, transferByteCount;
03868         PCDB cdb;
03869 
03870         //
03871         // Update device ext. to show which mode we are currently using.
03872         //
03873 
03874         sectorSize =  cdData->u1.BlockDescriptor.BlockLength[0] << 16;
03875         sectorSize |= (cdData->u1.BlockDescriptor.BlockLength[1] << 8);
03876         sectorSize |= (cdData->u1.BlockDescriptor.BlockLength[2]);
03877 
03878         cdData->RawAccess = (sectorSize == RAW_SECTOR_SIZE) ? TRUE : FALSE;
03879 
03880         //
03881         // Free the old data buffer, mdl.
03882         //
03883 
03884         ExFreePool(srb->DataBuffer);
03885         IoFreeMdl(Irp->MdlAddress);
03886         IoFreeIrp(Irp);
03887 
03888         //
03889         // rebuild the srb.
03890         //
03891 
03892         cdb = (PCDB)srb->Cdb;
03893         RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
03894 
03895 
03896         if (cdData->RawAccess) {
03897 
03898             PRAW_READ_INFO rawReadInfo =
03899                                (PRAW_READ_INFO)realIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
03900 
03901             ULONG maximumTransferLength;
03902             ULONG transferPages;
03903 
03904             //
03905             // Calculate starting offset.
03906             //
03907 
03908             startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
03909             transferByteCount  = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
03910             maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
03911             transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp->MdlAddress),
03912                                                            transferByteCount);
03913 
03914             //
03915             // Determine if request is within limits imposed by miniport.
03916             // If the request is larger than the miniport's capabilities, split it.
03917             //
03918 
03919             if (transferByteCount > maximumTransferLength ||
03920                 transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
03921 
03922                 realIrp->IoStatus.Information = 0;
03923                 realIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
03924                 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
03925 
03926                 ExFreePool(srb->SenseInfoBuffer);
03927                 ExFreePool(srb->DataBuffer);
03928                 ExFreePool(srb);
03929                 IoFreeMdl(Irp->MdlAddress);
03930                 IoFreeIrp(Irp);
03931 
03932                 IoStartNextPacket(DeviceObject, FALSE);
03933 
03934                 return STATUS_MORE_PROCESSING_REQUIRED;
03935             }
03936 
03937             srb->OriginalRequest = realIrp;
03938             srb->SrbFlags = deviceExtension->SrbFlags;
03939             srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
03940             srb->DataTransferLength = transferByteCount;
03941             srb->TimeOutValue = deviceExtension->TimeOutValue;
03942             srb->CdbLength = 10;
03943             srb->DataBuffer = MmGetMdlVirtualAddress(realIrp->MdlAddress);
03944 
03945             if (rawReadInfo->TrackMode == CDDA) {
03946                 if (cdData->XAFlags & PLEXTOR_CDDA) {
03947 
03948                     srb->CdbLength = 12;
03949 
03950                     cdb->PLXTR_READ_CDDA.LogicalUnitNumber = deviceExtension->Lun;
03951                     cdb->PLXTR_READ_CDDA.LogicalBlockByte3  = (UCHAR) (startingSector & 0xFF);
03952                     cdb->PLXTR_READ_CDDA.LogicalBlockByte2  = (UCHAR) ((startingSector >>  8) & 0xFF);
03953                     cdb->PLXTR_READ_CDDA.LogicalBlockByte1  = (UCHAR) ((startingSector >> 16) & 0xFF);
03954                     cdb->PLXTR_READ_CDDA.LogicalBlockByte0  = (UCHAR) ((startingSector >> 24) & 0xFF);
03955 
03956                     cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
03957                     cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
03958                     cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
03959                     cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
03960 
03961                     cdb->PLXTR_READ_CDDA.SubCode = 0;
03962                     cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
03963 
03964                 } else if (cdData->XAFlags & NEC_CDDA) {
03965 
03966                     cdb->NEC_READ_CDDA.LogicalBlockByte3  = (UCHAR) (startingSector & 0xFF);
03967                     cdb->NEC_READ_CDDA.LogicalBlockByte2  = (UCHAR) ((startingSector >>  8) & 0xFF);
03968                     cdb->NEC_READ_CDDA.LogicalBlockByte1  = (UCHAR) ((startingSector >> 16) & 0xFF);
03969                     cdb->NEC_READ_CDDA.LogicalBlockByte0  = (UCHAR) ((startingSector >> 24) & 0xFF);
03970 
03971                     cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
03972                     cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
03973 
03974                     cdb->NEC_READ_CDDA.OperationCode = 0xD4;
03975                 }
03976             } else {
03977                 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
03978 
03979                 cdb->CDB10.TransferBlocksMsb  = (UCHAR) (rawReadInfo->SectorCount >> 8);
03980                 cdb->CDB10.TransferBlocksLsb  = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
03981 
03982                 cdb->CDB10.LogicalBlockByte3  = (UCHAR) (startingSector & 0xFF);
03983                 cdb->CDB10.LogicalBlockByte2  = (UCHAR) ((startingSector >>  8) & 0xFF);
03984                 cdb->CDB10.LogicalBlockByte1  = (UCHAR) ((startingSector >> 16) & 0xFF);
03985                 cdb->CDB10.LogicalBlockByte0  = (UCHAR) ((startingSector >> 24) & 0xFF);
03986 
03987                 cdb->CDB10.OperationCode = SCSIOP_READ;
03988             }
03989 
03990             srb->SrbStatus = srb->ScsiStatus = 0;
03991 
03992 
03993             irpStack = IoGetNextIrpStackLocation(realIrp);
03994             irpStack->MajorFunction = IRP_MJ_SCSI;
03995             irpStack->Parameters.Scsi.Srb = srb;
03996 
03997             if (!(irpStack->Parameters.Others.Argument1)) {
03998 
03999                 //
04000                 // Only jam this in if it doesn't exist. The completion routines can
04001                 // call StartIo directly in the case of retries and resetting it will
04002                 // cause infinite loops.
04003                 //
04004 
04005                 irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
04006             }
04007 
04008             //
04009             // Set up IoCompletion routine address.
04010             //
04011 
04012             IoSetCompletionRoutine(realIrp,
04013                                    CdRomXACompletion,
04014                                    srb,
04015                                    TRUE,
04016                                    TRUE,
04017                                    TRUE);
04018         } else {
04019 
04020             ULONG maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
04021             ULONG transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp->MdlAddress),
04022                                                                  realIrpStack->Parameters.Read.Length);
04023             //
04024             // Back to cooked sectors. Build and send a normal read.
04025             // The real work for setting offsets and checking for splitrequests was
04026             // done in startio
04027             //
04028 
04029             if ((realIrpStack->Parameters.Read.Length > maximumTransferLength) ||
04030                 (transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages)) {
04031 
04032                 //
04033                 // Request needs to be split. Completion of each portion of the request will
04034                 // fire off the next portion. The final request will signal Io to send a new request.
04035                 //
04036 
04037                 ScsiClassSplitRequest(DeviceObject, realIrp, maximumTransferLength);
04038                 return STATUS_MORE_PROCESSING_REQUIRED;
04039 
04040             } else {
04041 
04042                 //
04043                 // Build SRB and CDB for this IRP.
04044                 //
04045 
04046                 ScsiClassBuildRequest(DeviceObject, realIrp);
04047 
04048             }
04049         }
04050 
04051         //
04052         // Call the port driver.
04053         //
04054 
04055         IoCallDriver(deviceExtension->PortDeviceObject, realIrp);
04056 
04057         return STATUS_MORE_PROCESSING_REQUIRED;
04058     }
04059 
04060     //
04061     // Update device Extension flags to indicate that XA isn't supported.
04062     //
04063 
04064     cdData->XAFlags |= XA_NOT_SUPPORTED;
04065 
04066     //
04067     // Deallocate srb and sense buffer.
04068     //
04069 
04070     if (srb) {
04071         if (srb->DataBuffer) {
04072             ExFreePool(srb->DataBuffer);
04073         }
04074         if (srb->SenseInfoBuffer) {
04075             ExFreePool(srb->SenseInfoBuffer);
04076         }
04077         ExFreePool(srb);
04078     }
04079 
04080     if (Irp->PendingReturned) {
04081       IoMarkIrpPending(Irp);
04082     }
04083 
04084     if (realIrp->PendingReturned) {
04085         IoMarkIrpPending(realIrp);
04086     }
04087 
04088     if (Irp->MdlAddress) {
04089         IoFreeMdl(Irp->MdlAddress);
04090     }
04091 
04092     IoFreeIrp(Irp);
04093 
04094     //
04095     // Set status in completing IRP.
04096     //
04097 
04098     realIrp->IoStatus.Status = status;
04099 
04100     //
04101     // Set the hard error if necessary.
04102     //
04103 
04104     if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
04105 
04106         //
04107         // Store DeviceObject for filesystem, and clear
04108         // in IoStatus.Information field.
04109         //
04110 
04111         IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
04112         realIrp->IoStatus.Information = 0;
04113     }
04114 
04115     IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
04116 
04117     IoStartNextPacket(DeviceObject, FALSE);
04118 
04119     return STATUS_MORE_PROCESSING_REQUIRED;
04120 }
04121 
04122 NTSTATUS
04123 NTAPI
04124 CdRomXACompletion(
04125     IN PDEVICE_OBJECT DeviceObject,
04126     IN PIRP Irp,
04127     IN PVOID Context
04128     )
04129 
04130 /*++
04131 
04132 Routine Description:
04133 
04134     This routine executes when the port driver has completed a request.
04135     It looks at the SRB status in the completing SRB and if not success
04136     it checks for valid request sense buffer information. If valid, the
04137     info is used to update status with more precise message of type of
04138     error. This routine deallocates the SRB.
04139 
04140 Arguments:
04141 
04142     DeviceObject - Supplies the device object which represents the logical
04143         unit.
04144 
04145     Irp - Supplies the Irp which has completed.
04146 
04147     Context - Supplies a pointer to the SRB.
04148 
04149 Return Value:
04150 
04151     NT status
04152 
04153 --*/
04154 
04155 {
04156     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
04157     PIO_STACK_LOCATION irpNextStack = IoGetNextIrpStackLocation(Irp);
04158     PSCSI_REQUEST_BLOCK srb = Context;
04159     NTSTATUS status;
04160     BOOLEAN retry;
04161 
04162     //
04163     // Check SRB status for success of completing request.
04164     //
04165 
04166     if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
04167 
04168         DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp, srb));
04169 
04170         //
04171         // Release the queue if it is frozen.
04172         //
04173 
04174         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
04175             ScsiClassReleaseQueue(DeviceObject);
04176         }
04177 
04178         retry = ScsiClassInterpretSenseInfo(
04179             DeviceObject,
04180             srb,
04181             irpStack->MajorFunction,
04182             irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
04183             MAXIMUM_RETRIES - ((ULONG_PTR)irpNextStack->Parameters.Others.Argument1),
04184             &status);
04185 
04186         //
04187         // If the status is verified required and the this request
04188         // should bypass verify required then retry the request.
04189         //
04190 
04191         if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
04192             status == STATUS_VERIFY_REQUIRED) {
04193 
04194             status = STATUS_IO_DEVICE_ERROR;
04195             retry = TRUE;
04196         }
04197 
04198         if (retry && (irpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)irpNextStack->Parameters.Others.Argument1-1))) {
04199 
04200             if (((ULONG_PTR)irpNextStack->Parameters.Others.Argument1)) {
04201 
04202                 //
04203                 // Retry request.
04204                 //
04205 
04206                 DebugPrint((1, "CdRomXACompletion: Retry request %lx - Calling StartIo\n", Irp));
04207 
04208 
04209                 ExFreePool(srb->SenseInfoBuffer);
04210                 ExFreePool(srb->DataBuffer);
04211                 ExFreePool(srb);
04212 
04213                 //
04214                 // Call StartIo directly since IoStartNextPacket hasn't been called,
04215                 // the serialisation is still intact.
04216                 //
04217 
04218                 ScsiCdRomStartIo(DeviceObject, Irp);
04219                 return STATUS_MORE_PROCESSING_REQUIRED;
04220 
04221             }
04222 
04223             //
04224             // Exhausted retries. Fall through and complete the request with the appropriate status.
04225             //
04226         }
04227     } else {
04228 
04229         //
04230         // Set status for successful request.
04231         //
04232 
04233         status = STATUS_SUCCESS;
04234 
04235     } // end if (SRB_STATUS(srb->SrbStatus) ...
04236 
04237     //
04238     // Return SRB to nonpaged pool.
04239     //
04240 
04241     ExFreePool(srb);
04242 
04243     //
04244     // Set status in completing IRP.
04245     //
04246 
04247     Irp->IoStatus.Status = status;
04248 
04249     //
04250     // Set the hard error if necessary.
04251     //
04252 
04253     if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
04254 
04255         //
04256         // Store DeviceObject for filesystem, and clear
04257         // in IoStatus.Information field.
04258         //
04259 
04260         IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
04261         Irp->IoStatus.Information = 0;
04262     }
04263 
04264     //
04265     // If pending has be returned for this irp then mark the current stack as
04266     // pending.
04267     //
04268 
04269     if (Irp->PendingReturned) {
04270       IoMarkIrpPending(Irp);
04271     }
04272 
04273     //IoCompleteRequest(Irp, IO_DISK_INCREMENT);
04274     IoStartNextPacket(DeviceObject, FALSE);
04275 
04276     return status;
04277 }
04278 
04279 NTSTATUS
04280 NTAPI
04281 CdRomDeviceControl(
04282     IN PDEVICE_OBJECT DeviceObject,
04283     IN PIRP Irp
04284     )
04285 
04286 /*++
04287 
04288 Routine Description:
04289 
04290     This is the NT device control handler for CDROMs.
04291 
04292 Arguments:
04293 
04294     DeviceObject - for this CDROM
04295 
04296     Irp - IO Request packet
04297 
04298 Return Value:
04299 
04300     NTSTATUS
04301 
04302 --*/
04303 
04304 {
04305     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
04306     PIO_STACK_LOCATION nextStack;
04307     PKEVENT            deviceControlEvent;
04308     PDEVICE_EXTENSION  deviceExtension = DeviceObject->DeviceExtension;
04309     PCDROM_DATA        cdData = (PCDROM_DATA)(deviceExtension+1);
04310     SCSI_REQUEST_BLOCK srb;
04311     NTSTATUS status;
04312     KIRQL    irql;
04313 
04314     ULONG ioctlCode;
04315     ULONG baseCode;
04316     ULONG functionCode;
04317 
04318 RetryControl:
04319 
04320     //
04321     // Zero the SRB on stack.
04322     //
04323 
04324     RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
04325 
04326     Irp->IoStatus.Information = 0;
04327 
04328     //
04329     // if this is a class driver ioctl then we need to change the base code
04330     // to IOCTL_CDROM_BASE so that the switch statement can handle it.
04331     //
04332     // WARNING - currently the scsi class ioctl function codes are between
04333     // 0x200 & 0x300.  this routine depends on that fact
04334     //
04335 
04336     ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
04337     baseCode = ioctlCode >> 16;
04338     functionCode = (ioctlCode & (~0xffffc003)) >> 2;
04339 
04340     DebugPrint((1, "CdRomDeviceControl: Ioctl Code = %#08lx, Base Code = %#lx,"
04341                    " Function Code = %#lx\n",
04342                 ioctlCode,
04343                 baseCode,
04344                 functionCode
04345               ));
04346 
04347     if((functionCode >= 0x200) && (functionCode <= 0x300)) {
04348 
04349         ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE, 0, 0, 0);
04350 
04351         DebugPrint((1, "CdRomDeviceControl: Class Code - new ioctl code is %#08lx\n",
04352                     ioctlCode));
04353 
04354         irpStack->Parameters.DeviceIoControl.IoControlCode = ioctlCode;
04355 
04356     }
04357 
04358     switch (ioctlCode) {
04359 
04360     case IOCTL_CDROM_RAW_READ: {
04361 
04362         LARGE_INTEGER  startingOffset;
04363         ULONG          transferBytes;
04364         PRAW_READ_INFO rawReadInfo = (PRAW_READ_INFO)irpStack->Parameters.DeviceIoControl.Type3InputBuffer;
04365         PUCHAR         userData = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
04366 
04367         //
04368         // Ensure that XA reads are supported.
04369         //
04370 
04371         if (cdData->XAFlags & XA_NOT_SUPPORTED) {
04372 
04373             DebugPrint((1,
04374                         "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
04375                         cdData->XAFlags));
04376 
04377             status = STATUS_INVALID_DEVICE_REQUEST;
04378             break;
04379         }
04380 
04381         //
04382         // Check that ending sector is on disc and buffers are there and of
04383         // correct size.
04384         //
04385 
04386         if (rawReadInfo == NULL) {
04387 
04388             //
04389             //  Called from user space. Validate the buffers.
04390             //
04391 
04392             rawReadInfo = (PRAW_READ_INFO)userData;
04393             irpStack->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID)userData;
04394 
04395             if (rawReadInfo == NULL) {
04396 
04397                 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (No extent info\n"));
04398 
04399                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
04400 
04401                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
04402                 return STATUS_INVALID_PARAMETER;
04403             }
04404 
04405             if (irpStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(RAW_READ_INFO)) {
04406 
04407                 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Invalid info buffer\n"));
04408 
04409                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
04410 
04411                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
04412                 return STATUS_INVALID_PARAMETER;
04413             }
04414         }
04415 
04416         startingOffset.QuadPart = rawReadInfo->DiskOffset.QuadPart;
04417         transferBytes = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
04418 
04419         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < transferBytes) {
04420 
04421             DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Bad buffer size)\n"));
04422 
04423             //
04424             // Fail request with status of invalid parameters.
04425             //
04426 
04427             Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
04428 
04429             IoCompleteRequest(Irp, IO_NO_INCREMENT);
04430             return STATUS_INVALID_PARAMETER;
04431         }
04432 
04433         if ((startingOffset.QuadPart + transferBytes) > deviceExtension->PartitionLength.QuadPart) {
04434 
04435             DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Request Out of Bounds)\n"));
04436 
04437             //
04438             // Fail request with status of invalid parameters.
04439             //
04440 
04441             status = STATUS_INVALID_PARAMETER;
04442             break;
04443         }
04444 
04445         IoMarkIrpPending(Irp);
04446         IoStartPacket(DeviceObject, Irp, NULL, NULL);
04447 
04448         return STATUS_PENDING;
04449     }
04450 
04451     case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
04452 
04453         DebugPrint((2,"CdRomDeviceControl: Get drive geometry\n"));
04454 
04455         if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
04456             sizeof( DISK_GEOMETRY ) ) {
04457 
04458             status = STATUS_INFO_LENGTH_MISMATCH;
04459             break;
04460         }
04461 
04462         IoMarkIrpPending(Irp);
04463         IoStartPacket(DeviceObject,Irp, NULL,NULL);
04464 
04465         return STATUS_PENDING;
04466     }
04467 
04468     case IOCTL_CDROM_GET_LAST_SESSION:
04469     case IOCTL_CDROM_READ_TOC:  {
04470 
04471         //
04472         // If the cd is playing music then reject this request.
04473         //
04474 
04475         if (CdRomIsPlayActive(DeviceObject)) {
04476             Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
04477             IoCompleteRequest(Irp, IO_NO_INCREMENT);
04478             return STATUS_DEVICE_BUSY;
04479         }
04480 
04481         IoMarkIrpPending(Irp);
04482         IoStartPacket(DeviceObject, Irp, NULL, NULL);
04483 
04484         return STATUS_PENDING;
04485     }
04486 
04487     case IOCTL_CDROM_PLAY_AUDIO_MSF: {
04488 
04489         //
04490         // Play Audio MSF
04491         //
04492 
04493         DebugPrint((2,"CdRomDeviceControl: Play audio MSF\n"));
04494 
04495         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
04496             sizeof(CDROM_PLAY_AUDIO_MSF)) {
04497 
04498             //
04499             // Indicate unsuccessful status.
04500             //
04501 
04502             status = STATUS_BUFFER_TOO_SMALL;
04503             break;
04504         }
04505 
04506         IoMarkIrpPending(Irp);
04507         IoStartPacket(DeviceObject, Irp, NULL, NULL);
04508 
04509         return STATUS_PENDING;
04510     }
04511 
04512     case IOCTL_CDROM_SEEK_AUDIO_MSF: {
04513 
04514 
04515         //
04516         // Seek Audio MSF
04517         //
04518 
04519         DebugPrint((2,"CdRomDeviceControl: Seek audio MSF\n"));
04520 
04521         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
04522             sizeof(CDROM_SEEK_AUDIO_MSF)) {
04523 
04524             //
04525             // Indicate unsuccessful status.
04526             //
04527 
04528             status = STATUS_BUFFER_TOO_SMALL;
04529             break;
04530         } else {
04531             IoMarkIrpPending(Irp);
04532             IoStartPacket(DeviceObject, Irp, NULL, NULL);
04533 
04534             return STATUS_PENDING;
04535 
04536         }
04537     }
04538 
04539     case IOCTL_CDROM_PAUSE_AUDIO: {
04540 
04541         //
04542         // Pause audio
04543         //
04544 
04545         DebugPrint((2, "CdRomDeviceControl: Pause audio\n"));
04546 
04547         IoMarkIrpPending(Irp);
04548         IoStartPacket(DeviceObject, Irp, NULL, NULL);
04549 
04550         return STATUS_PENDING;
04551 
04552         break;
04553     }
04554 
04555     case IOCTL_CDROM_RESUME_AUDIO: {
04556 
04557         //
04558         // Resume audio
04559         //
04560 
04561         DebugPrint((2, "CdRomDeviceControl: Resume audio\n"));
04562 
04563         IoMarkIrpPending(Irp);
04564         IoStartPacket(DeviceObject, Irp, NULL, NULL);
04565 
04566         return STATUS_PENDING;
04567     }
04568 
04569     case IOCTL_CDROM_READ_Q_CHANNEL: {
04570 
04571         if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
04572             sizeof(CDROM_SUB_Q_DATA_FORMAT)) {
04573 
04574             status = STATUS_BUFFER_TOO_SMALL;
04575             Irp->IoStatus.Information = 0;
04576             break;
04577         }
04578 
04579         IoMarkIrpPending(Irp);
04580         IoStartPacket(DeviceObject, Irp, NULL, NULL);
04581 
04582         return STATUS_PENDING;
04583     }
04584 
04585     case IOCTL_CDROM_GET_CONTROL: {
04586 
04587         DebugPrint((2, "CdRomDeviceControl: Get audio control\n"));
04588 
04589         //
04590         // Verify user buffer is large enough for the data.
04591         //
04592 
04593         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
04594             sizeof(CDROM_AUDIO_CONTROL)) {
04595 
04596             //
04597             // Indicate unsuccessful status and no data transferred.
04598             //
04599 
04600             status = STATUS_BUFFER_TOO_SMALL;
04601             Irp->IoStatus.Information = 0;
04602             break;
04603 
04604         } else {
04605 
04606             IoMarkIrpPending(Irp);
04607             IoStartPacket(DeviceObject, Irp, NULL, NULL);
04608 
04609             return STATUS_PENDING;
04610         }
04611     }
04612 
04613     case IOCTL_CDROM_GET_VOLUME: {
04614 
04615         DebugPrint((2, "CdRomDeviceControl: Get volume control\n"));
04616 
04617         //
04618         // Verify user buffer is large enough for data.
04619         //
04620 
04621         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
04622             sizeof(VOLUME_CONTROL)) {
04623 
04624             //
04625             // Indicate unsuccessful status and no data transferred.
04626             //
04627 
04628             status = STATUS_BUFFER_TOO_SMALL;
04629             Irp->IoStatus.Information = 0;
04630             break;
04631 
04632         } else {
04633             IoMarkIrpPending(Irp);
04634             IoStartPacket(DeviceObject, Irp, NULL, NULL);
04635 
04636             return STATUS_PENDING;
04637         }
04638     }
04639 
04640     case IOCTL_CDROM_SET_VOLUME: {
04641 
04642         DebugPrint((2, "CdRomDeviceControl: Set volume control\n"));
04643 
04644         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
04645             sizeof(VOLUME_CONTROL)) {
04646 
04647             //
04648             // Indicate unsuccessful status.
04649             //
04650 
04651             status = STATUS_BUFFER_TOO_SMALL;
04652             break;
04653         } else {
04654 
04655             IoMarkIrpPending(Irp);
04656             IoStartPacket(DeviceObject, Irp, NULL, NULL);
04657 
04658             return STATUS_PENDING;
04659         }
04660     }
04661 
04662     case IOCTL_CDROM_STOP_AUDIO: {
04663 
04664         //
04665         // Stop play.
04666         //
04667 
04668         DebugPrint((2, "CdRomDeviceControl: Stop audio\n"));
04669 
04670         IoMarkIrpPending(Irp);
04671         IoStartPacket(DeviceObject,Irp, NULL,NULL);
04672 
04673         return STATUS_PENDING;
04674     }
04675 
04676     case IOCTL_CDROM_CHECK_VERIFY: {
04677         DebugPrint((1, "CdRomDeviceControl: [%lx] Check Verify\n", Irp));
04678         IoMarkIrpPending(Irp);
04679 
04680         if((irpStack->Parameters.DeviceIoControl.OutputBufferLength) &&
04681            (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))) {
04682 
04683            DebugPrint((1, "CdRomDeviceControl: Check Verify: media count "
04684                           "buffer too small\n"));
04685 
04686            status = STATUS_BUFFER_TOO_SMALL;
04687            break;
04688         }
04689 
04690         IoStartPacket(DeviceObject,Irp, NULL,NULL);
04691 
04692         return STATUS_PENDING;
04693     }
04694 
04695     default: {
04696 
04697         //
04698         // allocate an event and stuff it into our stack location.
04699         //
04700 
04701         deviceControlEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
04702 
04703         if(!deviceControlEvent) {
04704 
04705             status = STATUS_INSUFFICIENT_RESOURCES;
04706 
04707         } else {
04708 
04709             PIO_STACK_LOCATION currentStack;
04710 
04711             KeInitializeEvent(deviceControlEvent, NotificationEvent, FALSE);
04712 
04713             currentStack = IoGetCurrentIrpStackLocation(Irp);
04714             nextStack = IoGetNextIrpStackLocation(Irp);
04715 
04716             //
04717             // Copy the stack down a notch
04718             //
04719 
04720             *nextStack = *currentStack;
04721 
04722             IoSetCompletionRoutine(
04723                 Irp,
04724                 CdRomClassIoctlCompletion,
04725                 deviceControlEvent,
04726                 TRUE,
04727                 TRUE,
04728                 TRUE
04729                 );
04730 
04731             IoSetNextIrpStackLocation(Irp);
04732 
04733             Irp->IoStatus.Status = STATUS_SUCCESS;
04734             Irp->IoStatus.Information = 0;
04735 
04736             //
04737             // Override volume verifies on this stack location so that we
04738             // will be forced through the synchronization.  Once this location
04739             // goes away we get the old value back
04740             //
04741 
04742             nextStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
04743 
04744             IoMarkIrpPending(Irp);
04745 
04746             IoStartPacket(DeviceObject, Irp, NULL, NULL);
04747 
04748             //
04749             // Wait for CdRomClassIoctlCompletion to set the event. This
04750             // ensures serialization remains intact for these unhandled device
04751             // controls.
04752             //
04753 
04754             KeWaitForSingleObject(
04755                 deviceControlEvent,
04756                 Suspended,
04757                 KernelMode,
04758                 FALSE,
04759                 NULL);
04760 
04761             ExFreePool(deviceControlEvent);
04762 
04763             DebugPrint((2, "CdRomDeviceControl: irp %#08lx synchronized\n", Irp));
04764 
04765             //
04766             // If an error occured then propagate that back up - we are no longer
04767             // guaranteed synchronization and the upper layers will have to
04768             // retry.
04769             //
04770             // If no error occured, call down to the class driver directly
04771             // then start up the next request.
04772             //
04773 
04774             if(Irp->IoStatus.Status == STATUS_SUCCESS) {
04775 
04776                 status = ScsiClassDeviceControl(DeviceObject, Irp);
04777 
04778                 KeRaiseIrql(DISPATCH_LEVEL, &irql);
04779 
04780                 IoStartNextPacket(DeviceObject, FALSE);
04781 
04782                 KeLowerIrql(irql);
04783             }
04784         }
04785 
04786         return status;
04787     }
04788 
04789     } // end switch()
04790 
04791     if (status == STATUS_VERIFY_REQUIRED) {
04792 
04793         //
04794         // If the status is verified required and this request
04795         // should bypass verify required then retry the request.
04796         //
04797 
04798         if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
04799 
04800             status = STATUS_IO_DEVICE_ERROR;
04801             goto RetryControl;
04802 
04803         }
04804     }
04805 
04806     if (IoIsErrorUserInduced(status)) {
04807 
04808         IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
04809 
04810     }
04811 
04812     //
04813     // Update IRP with completion status.
04814     //
04815 
04816     Irp->IoStatus.Status = status;
04817 
04818     //
04819     // Complete the request.
04820     //
04821 
04822     IoCompleteRequest(Irp, IO_DISK_INCREMENT);
04823     DebugPrint((2, "CdRomDeviceControl: Status is %lx\n", status));
04824     return status;
04825 
04826 } // end ScsiCdRomDeviceControl()
04827 
04828 VOID
04829 NTAPI
04830 ScanForSpecial(
04831     PDEVICE_OBJECT DeviceObject,
04832     PINQUIRYDATA InquiryData,
04833     PIO_SCSI_CAPABILITIES PortCapabilities
04834     )
04835 
04836 /*++
04837 
04838 Routine Description:
04839 
04840     This function checks to see if an SCSI logical unit requires an special
04841     initialization or error processing.
04842 
04843 Arguments:
04844 
04845     DeviceObject - Supplies the device object to be tested.
04846 
04847     InquiryData - Supplies the inquiry data returned by the device of interest.
04848 
04849     PortCapabilities - Supplies the capabilities of the device object.
04850 
04851 Return Value:
04852 
04853     None.
04854 
04855 --*/
04856 
04857 {
04858     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
04859     PCDROM_DATA       cdData = (PCDROM_DATA)(deviceExtension+1);
04860 
04861     //
04862     // Look for a Hitachi CDR-1750. Read-ahead must be disabled in order
04863     // to get this cdrom drive to work on scsi adapters that use PIO.
04864     //
04865 
04866     if ((strncmp((PCHAR)InquiryData->VendorId, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
04867         strncmp((PCHAR)InquiryData->VendorId, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0)
04868         && PortCapabilities->AdapterUsesPio) {
04869 
04870         DebugPrint((1, "CdRom ScanForSpecial:  Found Hitachi CDR-1750S.\n"));
04871 
04872         //
04873         // Setup an error handler to reinitialize the cd rom after it is reset.
04874         //
04875 
04876         deviceExtension->ClassError = HitachProcessError;
04877 
04878     } else if (( RtlCompareMemory( InquiryData->VendorId,"FUJITSU", 7 ) == 7 ) &&
04879               (( RtlCompareMemory( InquiryData->ProductId,"FMCD-101", 8 ) == 8 ) ||
04880                ( RtlCompareMemory( InquiryData->ProductId,"FMCD-102", 8 ) == 8 ))) {
04881 
04882         //
04883         // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
04884         // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
04885         // error status.
04886         //
04887 
04888         deviceExtension->TimeOutValue = 20;
04889 
04890     } else if (( RtlCompareMemory( InquiryData->VendorId,"TOSHIBA", 7) == 7) &&
04891               (( RtlCompareMemory( InquiryData->ProductId,"CD-ROM XM-34", 12) == 12))) {
04892 
04893         SCSI_REQUEST_BLOCK srb;
04894         PCDB               cdb;
04895         ULONG              length;
04896         PUCHAR             buffer;
04897         NTSTATUS           status;
04898 
04899         //
04900         // Set the density code and the error handler.
04901         //
04902 
04903         length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH);
04904 
04905         RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
04906 
04907         //
04908         // Build the MODE SENSE CDB.
04909         //
04910 
04911         srb.CdbLength = 6;
04912         cdb = (PCDB)srb.Cdb;
04913 
04914         //
04915         // Set timeout value from device extension.
04916         //
04917 
04918         srb.TimeOutValue = deviceExtension->TimeOutValue;
04919 
04920         cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
04921         cdb->MODE_SENSE.PageCode = 0x1;
04922         cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
04923 
04924         buffer = ExAllocatePool(NonPagedPoolCacheAligned, (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH));
04925         if (!buffer) {
04926             return;
04927         }
04928 
04929         status = ScsiClassSendSrbSynchronous(DeviceObject,
04930                                              &srb,
04931                                              buffer,
04932                                              length,
04933                                              FALSE);
04934 
04935         ((PERROR_RECOVERY_DATA)buffer)->BlockDescriptor.DensityCode = 0x83;
04936         ((PERROR_RECOVERY_DATA)buffer)->Header.ModeDataLength = 0x0;
04937 
04938         RtlCopyMemory(&cdData->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA));
04939 
04940         RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
04941 
04942         //
04943         // Build the MODE SENSE CDB.
04944         //
04945 
04946         srb.CdbLength = 6;
04947         cdb = (PCDB)srb.Cdb;
04948 
04949         //
04950         // Set timeout value from device extension.
04951         //
04952 
04953         srb.TimeOutValue = deviceExtension->TimeOutValue;
04954 
04955         cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
04956         cdb->MODE_SELECT.PFBit = 1;
04957         cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
04958 
04959         status = ScsiClassSendSrbSynchronous(DeviceObject,
04960                                              &srb,
04961                                              buffer,
04962                                              length,
04963                                              TRUE);
04964 
04965         if (!NT_SUCCESS(status)) {
04966             DebugPrint((1,
04967                         "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
04968                         status));
04969         }
04970 
04971         deviceExtension->ClassError = ToshibaProcessError;
04972 
04973         ExFreePool(buffer);
04974 
04975     }
04976 
04977     //
04978     // Determine special CD-DA requirements.
04979     //
04980 
04981     if (RtlCompareMemory( InquiryData->VendorId,"PLEXTOR",7) == 7) {
04982         cdData->XAFlags |= PLEXTOR_CDDA;
04983     } else if (RtlCompareMemory ( InquiryData->VendorId,"NEC",3) == 3) {
04984         cdData->XAFlags |= NEC_CDDA;
04985     }
04986 
04987     return;
04988 }
04989 
04990 VOID
04991 NTAPI
04992 HitachProcessError(
04993     PDEVICE_OBJECT DeviceObject,
04994     PSCSI_REQUEST_BLOCK Srb,
04995     NTSTATUS *Status,
04996     BOOLEAN *Retry
04997     )
04998 /*++
04999 
05000 Routine Description:
05001 
05002    This routine checks the type of error.  If the error indicates CD-ROM the
05003    CD-ROM needs to be reinitialized then a Mode sense command is sent to the
05004    device.  This command disables read-ahead for the device.
05005 
05006 Arguments:
05007 
05008     DeviceObject - Supplies a pointer to the device object.
05009 
05010     Srb - Supplies a pointer to the failing Srb.
05011 
05012     Status - Not used.
05013 
05014     Retry - Not used.
05015 
05016 Return Value:
05017 
05018     None.
05019 
05020 --*/
05021 
05022 {
05023     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
05024     PSENSE_DATA         senseBuffer = Srb->SenseInfoBuffer;
05025     LARGE_INTEGER       largeInt;
05026     PUCHAR              modePage;
05027     PIO_STACK_LOCATION  irpStack;
05028     PIRP                irp;
05029     PSCSI_REQUEST_BLOCK srb;
05030     PCOMPLETION_CONTEXT context;
05031     PCDB                cdb;
05032     ULONG               alignment;
05033 
05034     UNREFERENCED_PARAMETER(Status);
05035     UNREFERENCED_PARAMETER(Retry);
05036 
05037     largeInt.QuadPart = (LONGLONG) 1;
05038 
05039     //
05040     // Check the status.  The initialization command only needs to be sent
05041     // if UNIT ATTENTION is returned.
05042     //
05043 
05044     if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
05045 
05046         //
05047         // The drive does not require reinitialization.
05048         //
05049 
05050         return;
05051     }
05052 
05053     //
05054     // Found a bad HITACHI cd-rom.  These devices do not work with PIO
05055     // adapters when read-ahead is enabled.  Read-ahead is disabled by
05056     // a mode select command.  The mode select page code is zero and the
05057     // length is 6 bytes.  All of the other bytes should be zero.
05058     //
05059 
05060 
05061     if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
05062 
05063         DebugPrint((1, "HitachiProcessError: Reinitializing the CD-ROM.\n"));
05064 
05065         //
05066         // Send the special mode select command to disable read-ahead
05067         // on the CD-ROM reader.
05068         //
05069 
05070         alignment = DeviceObject->AlignmentRequirement ?
05071             DeviceObject->AlignmentRequirement : 1;
05072 
05073         context = ExAllocatePool(
05074             NonPagedPool,
05075             sizeof(COMPLETION_CONTEXT) +  HITACHI_MODE_DATA_SIZE + alignment
05076             );
05077 
05078         if (context == NULL) {
05079 
05080             //
05081             // If there is not enough memory to fulfill this request,
05082             // simply return. A subsequent retry will fail and another
05083             // chance to start the unit.
05084             //
05085 
05086             return;
05087         }
05088 
05089         context->DeviceObject = DeviceObject;
05090         srb = &context->Srb;
05091 
05092         RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
05093 
05094         //
05095         // Write length to SRB.
05096         //
05097 
05098         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
05099 
05100         //
05101         // Set up SCSI bus address.
05102         //
05103 
05104         srb->PathId = deviceExtension->PathId;
05105         srb->TargetId = deviceExtension->TargetId;
05106         srb->Lun = deviceExtension->Lun;
05107 
05108         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
05109         srb->TimeOutValue = deviceExtension->TimeOutValue;
05110 
05111         //
05112         // Set the transfer length.
05113         //
05114 
05115         srb->DataTransferLength = HITACHI_MODE_DATA_SIZE;
05116         srb->SrbFlags = SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
05117 
05118         //
05119         // The data buffer must be aligned.
05120         //
05121 
05122         srb->DataBuffer = (PVOID) (((ULONG_PTR) (context + 1) + (alignment - 1)) &
05123             ~(alignment - 1));
05124 
05125 
05126         //
05127         // Build the HITACHI read-ahead mode select CDB.
05128         //
05129 
05130         srb->CdbLength = 6;
05131         cdb = (PCDB)srb->Cdb;
05132         cdb->MODE_SENSE.LogicalUnitNumber = srb->Lun;
05133         cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SELECT;
05134         cdb->MODE_SENSE.AllocationLength = HITACHI_MODE_DATA_SIZE;
05135 
05136         //
05137         // Initialize the mode sense data.
05138         //
05139 
05140         modePage = srb->DataBuffer;
05141 
05142         RtlZeroMemory(modePage, HITACHI_MODE_DATA_SIZE);
05143 
05144         //
05145         // Set the page length field to 6.
05146         //
05147 
05148         modePage[5] = 6;
05149 
05150         //
05151         // Build the asynchronous request to be sent to the port driver.
05152         //
05153 
05154         irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE,
05155                                            DeviceObject,
05156                                            srb->DataBuffer,
05157                                            srb->DataTransferLength,
05158                                            &largeInt,
05159                                            NULL);
05160 
05161         IoSetCompletionRoutine(irp,
05162                    (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
05163                    context,
05164                    TRUE,
05165                    TRUE,
05166                    TRUE);
05167 
05168         irpStack = IoGetNextIrpStackLocation(irp);
05169 
05170         irpStack->MajorFunction = IRP_MJ_SCSI;
05171 
05172         srb->OriginalRequest = irp;
05173 
05174         //
05175         // Save SRB address in next stack for port driver.
05176         //
05177 
05178         irpStack->Parameters.Scsi.Srb = (PVOID)srb;
05179 
05180         //
05181         // Set up IRP Address.
05182         //
05183 
05184         (VOID)IoCallDriver(deviceExtension->PortDeviceObject, irp);
05185 
05186     }
05187 }
05188 
05189 NTSTATUS
05190 NTAPI
05191 ToshibaProcessErrorCompletion(
05192     PDEVICE_OBJECT DeviceObject,
05193     PIRP Irp,
05194     PVOID Context
05195     )
05196 
05197 /*++
05198 
05199 Routine Description:
05200 
05201     Completion routine for the ClassError routine to handle older Toshiba units
05202     that require setting the density code.
05203 
05204 Arguments:
05205 
05206     DeviceObject - Supplies a pointer to the device object.
05207 
05208     Irp - Pointer to irp created to set the density code.
05209 
05210     Context - Supplies a pointer to the Mode Select Srb.
05211 
05212 
05213 Return Value:
05214 
05215     STATUS_MORE_PROCESSING_REQUIRED
05216 
05217 --*/
05218 
05219 {
05220 
05221     PSCSI_REQUEST_BLOCK srb = Context;
05222 
05223     //
05224     // Check for a frozen queue.
05225     //
05226 
05227     if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
05228 
05229         //
05230         // Unfreeze the queue getting the device object from the context.
05231         //
05232 
05233         ScsiClassReleaseQueue(DeviceObject);
05234     }
05235 
05236     //
05237     // Free all of the allocations.
05238     //
05239 
05240     ExFreePool(srb->DataBuffer);
05241     ExFreePool(srb);
05242     IoFreeMdl(Irp->MdlAddress);
05243     IoFreeIrp(Irp);
05244 
05245     //
05246     // Indicate the I/O system should stop processing the Irp completion.
05247     //
05248 
05249     return STATUS_MORE_PROCESSING_REQUIRED;
05250 }
05251 
05252 VOID
05253 NTAPI
05254 ToshibaProcessError(
05255     PDEVICE_OBJECT DeviceObject,
05256     PSCSI_REQUEST_BLOCK Srb,
05257     NTSTATUS *Status,
05258     BOOLEAN *Retry
05259     )
05260 
05261 /*++
05262 
05263 Routine Description:
05264 
05265    This routine checks the type of error.  If the error indicates a unit attention,
05266    the density code needs to be set via a Mode select command.
05267 
05268 Arguments:
05269 
05270     DeviceObject - Supplies a pointer to the device object.
05271 
05272     Srb - Supplies a pointer to the failing Srb.
05273 
05274     Status - Not used.
05275 
05276     Retry - Not used.
05277 
05278 Return Value:
05279 
05280     None.
05281 
05282 --*/
05283 
05284 {
05285     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
05286     PCDROM_DATA         cdData = (PCDROM_DATA)(deviceExtension+1);
05287     PSENSE_DATA         senseBuffer = Srb->SenseInfoBuffer;
05288     PIO_STACK_LOCATION  irpStack;
05289     PIRP                irp;
05290     PSCSI_REQUEST_BLOCK srb;
05291     ULONG               length;
05292     PCDB                cdb;
05293     PUCHAR              dataBuffer;
05294 
05295 
05296     if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
05297         return;
05298     }
05299 
05300     //
05301     // The Toshiba's require the density code to be set on power up and media changes.
05302     //
05303 
05304     if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
05305 
05306 
05307         irp = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1),
05308                               FALSE);
05309 
05310         if (!irp) {
05311             return;
05312         }
05313 
05314         srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
05315         if (!srb) {
05316             IoFreeIrp(irp);
05317             return;
05318         }
05319 
05320 
05321         length = sizeof(ERROR_RECOVERY_DATA);
05322         dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, length);
05323         if (!dataBuffer) {
05324             ExFreePool(srb);
05325             IoFreeIrp(irp);
05326             return;
05327         }
05328 
05329         irp->MdlAddress = IoAllocateMdl(dataBuffer,
05330                                         length,
05331                                         FALSE,
05332                                         FALSE,
05333                                         (PIRP) NULL);
05334 
05335         if (!irp->MdlAddress) {
05336             ExFreePool(srb);
05337             ExFreePool(dataBuffer);
05338             IoFreeIrp(irp);
05339             return;
05340         }
05341 
05342         //
05343         // Prepare the MDL
05344         //
05345 
05346         MmBuildMdlForNonPagedPool(irp->MdlAddress);
05347 
05348         RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
05349 
05350         srb->DataBuffer = dataBuffer;
05351         cdb = (PCDB)srb->Cdb;
05352 
05353         //
05354         // Set up the irp.
05355         //
05356 
05357         IoSetNextIrpStackLocation(irp);
05358         irp->IoStatus.Status = STATUS_SUCCESS;
05359         irp->IoStatus.Information = 0;
05360         irp->Flags = 0;
05361         irp->UserBuffer = NULL;
05362 
05363         //
05364         // Save the device object and irp in a private stack location.
05365         //
05366 
05367         irpStack = IoGetCurrentIrpStackLocation(irp);
05368         irpStack->DeviceObject = deviceExtension->DeviceObject;
05369 
05370         //
05371         // Construct the IRP stack for the lower level driver.
05372         //
05373 
05374         irpStack = IoGetNextIrpStackLocation(irp);
05375         irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
05376         irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_OUT;
05377         irpStack->Parameters.Scsi.Srb = srb;
05378 
05379         IoSetCompletionRoutine(irp,
05380                                ToshibaProcessErrorCompletion,
05381                                srb,
05382                                TRUE,
05383                                TRUE,
05384                                TRUE);
05385 
05386         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
05387         srb->PathId = deviceExtension->PathId;
05388         srb->TargetId = deviceExtension->TargetId;
05389         srb->Lun = deviceExtension->Lun;
05390         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
05391         srb->Cdb[1] |= deviceExtension->Lun << 5;
05392         srb->SrbStatus = srb->ScsiStatus = 0;
05393         srb->NextSrb = 0;
05394         srb->OriginalRequest = irp;
05395         srb->SenseInfoBufferLength = 0;
05396 
05397         //
05398         // Set the transfer length.
05399         //
05400 
05401         srb->DataTransferLength = length;
05402         srb->SrbFlags = SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
05403 
05404 
05405         srb->CdbLength = 6;
05406         cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
05407         cdb->MODE_SELECT.PFBit = 1;
05408         cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
05409 
05410         //
05411         // Copy the Mode page into the databuffer.
05412         //
05413 
05414         RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, length);
05415 
05416         //
05417         // Set the density code.
05418         //
05419 
05420         ((PERROR_RECOVERY_DATA)srb->DataBuffer)->BlockDescriptor.DensityCode = 0x83;
05421 
05422         IoCallDriver(deviceExtension->PortDeviceObject, irp);
05423     }
05424 }
05425 
05426 BOOLEAN
05427 NTAPI
05428 CdRomIsPlayActive(
05429     IN PDEVICE_OBJECT DeviceObject
05430     )
05431 
05432 /*++
05433 
05434 Routine Description:
05435 
05436     This routine determines if the cd is currently playing music.
05437 
05438 Arguments:
05439 
05440     DeviceObject - Device object to test.
05441 
05442 Return Value:
05443 
05444     TRUE if the device is playing music.
05445 
05446 --*/
05447 {
05448     PDEVICE_EXTENSION  deviceExtension = DeviceObject->DeviceExtension;
05449     PIRP irp;
05450     IO_STATUS_BLOCK ioStatus;
05451     KEVENT event;
05452     NTSTATUS status;
05453     PSUB_Q_CURRENT_POSITION currentBuffer;
05454 
05455     if (!PLAY_ACTIVE(deviceExtension)) {
05456         return(FALSE);
05457     }
05458 
05459     currentBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(SUB_Q_CURRENT_POSITION));
05460 
05461     if (currentBuffer == NULL) {
05462         return(FALSE);
05463     }
05464 
05465     ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION;
05466     ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0;
05467 
05468     //
05469     // Create notification event object to be used to signal the
05470     // request completion.
05471     //
05472 
05473     KeInitializeEvent(&event, NotificationEvent, FALSE);
05474 
05475     //
05476     // Build the synchronous request  to be sent to the port driver
05477     // to perform the request.
05478     //
05479 
05480     irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL,
05481                                         deviceExtension->DeviceObject,
05482                                         currentBuffer,
05483                                         sizeof(CDROM_SUB_Q_DATA_FORMAT),
05484                                         currentBuffer,
05485                                         sizeof(SUB_Q_CURRENT_POSITION),
05486                                         FALSE,
05487                                         &event,
05488                                         &ioStatus);
05489 
05490     if (irp == NULL) {
05491         ExFreePool(currentBuffer);
05492         return FALSE;
05493     }
05494 
05495     //
05496     // Pass request to port driver and wait for request to complete.
05497     //
05498 
05499     status = IoCallDriver(deviceExtension->DeviceObject, irp);
05500 
05501     if (status == STATUS_PENDING) {
05502         KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
05503         status = ioStatus.Status;
05504     }
05505 
05506     if (!NT_SUCCESS(status)) {
05507         ExFreePool(currentBuffer);
05508         return FALSE;
05509     }
05510 
05511     ExFreePool(currentBuffer);
05512 
05513     return(PLAY_ACTIVE(deviceExtension));
05514 
05515 }
05516 
05517 IO_COMPLETION_ROUTINE CdRomMediaChangeCompletion;
05518 NTSTATUS
05519 NTAPI
05520 CdRomMediaChangeCompletion(
05521     PDEVICE_OBJECT DeviceObject,
05522     PIRP Irp,
05523     PVOID Context
05524     )
05525 
05526 /*++
05527 
05528 Routine Description:
05529 
05530     This routine handles the completion of the test unit ready irps
05531     used to determine if the media has changed.  If the media has
05532     changed, this code signals the named event to wake up other
05533     system services that react to media change (aka AutoPlay).
05534 
05535 Arguments:
05536 
05537     DeviceObject - the object for the completion
05538     Irp - the IRP being completed
05539     Context - the SRB from the IRP
05540 
05541 Return Value:
05542 
05543     NTSTATUS
05544 
05545 --*/
05546 
05547 {
05548     PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK) Context;
05549     PIO_STACK_LOCATION  cdStack = IoGetCurrentIrpStackLocation(Irp);
05550     PIO_STACK_LOCATION  irpNextStack = IoGetNextIrpStackLocation(Irp);
05551     PDEVICE_EXTENSION   deviceExtension;
05552     PDEVICE_EXTENSION   physicalExtension;
05553     PSENSE_DATA         senseBuffer;
05554     PCDROM_DATA         cddata;
05555 
05556     ASSERT(Irp);
05557     ASSERT(cdStack);
05558     DeviceObject = cdStack->DeviceObject;
05559     ASSERT(DeviceObject);
05560 
05561     deviceExtension = DeviceObject->DeviceExtension;
05562     physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension;
05563     cddata = (PCDROM_DATA)(deviceExtension + 1);
05564 
05565     ASSERT(cddata->MediaChangeIrp == NULL);
05566 
05567     //
05568     // If the sense data field is valid, look for a media change.
05569     // otherwise this iteration of the polling will just assume nothing
05570     // changed.
05571     //
05572 
05573     DebugPrint((3, "CdRomMediaChangeHandler: Completing Autorun Irp 0x%lx "
05574                    "for device %d\n",
05575                    Irp, deviceExtension->DeviceNumber));
05576 
05577     if (srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
05578         if (srb->SenseInfoBufferLength >= FIELD_OFFSET(SENSE_DATA, CommandSpecificInformation)) {
05579 
05580             //
05581             // See if this is a media change.
05582             //
05583 
05584             senseBuffer = srb->SenseInfoBuffer;
05585             if ((senseBuffer->SenseKey & 0x0f) == SCSI_SENSE_UNIT_ATTENTION)  {
05586                 if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_MEDIUM_CHANGED) {
05587 
05588                     DebugPrint((1, "CdRomMediaChangeCompletion: New media inserted "
05589                                    "into CdRom%d [irp = 0x%lx]\n",
05590                                 deviceExtension->DeviceNumber, Irp));
05591 
05592                     //
05593                     // Media change event occurred - signal the named event.
05594                     //
05595 
05596                     KeSetEvent(deviceExtension->MediaChangeEvent,
05597                                (KPRIORITY) 0,
05598                                FALSE);
05599 
05600                     deviceExtension->MediaChangeNoMedia = FALSE;
05601 
05602                 }
05603 
05604                 if (DeviceObject->Vpb->Flags & VPB_MOUNTED) {
05605 
05606                     //
05607                     // Must remember the media changed and force the
05608                     // file system to verify on next access
05609                     //
05610 
05611                     DeviceObject->Flags |= DO_VERIFY_VOLUME;
05612                 }
05613 
05614                 physicalExtension->MediaChangeCount++;
05615 
05616             } else if(((senseBuffer->SenseKey & 0x0f) == SCSI_SENSE_NOT_READY)&&
05617                       (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE)&&
05618                       (!deviceExtension->MediaChangeNoMedia)){
05619 
05620                 //
05621                 // If there was no media in the device then signal the waiters if
05622                 // we haven't already done so before.
05623                 //
05624 
05625                 DebugPrint((1, "CdRomMediaChangeCompletion: No media in device"
05626                                "CdRom%d [irp = 0x%lx]\n",
05627                             deviceExtension->DeviceNumber, Irp));
05628 
05629                 KeSetEvent(deviceExtension->MediaChangeEvent,
05630                            (KPRIORITY) 0,
05631                            FALSE);
05632 
05633                 deviceExtension->MediaChangeNoMedia = TRUE;
05634 
05635             }
05636         }
05637     } else if((srb->SrbStatus == SRB_STATUS_SUCCESS)&&
05638               (deviceExtension->MediaChangeNoMedia)) {
05639         //
05640         // We didn't have any media before and now the requests are succeeding
05641         // we probably missed the Media change somehow.  Signal the change
05642         // anyway
05643         //
05644 
05645         DebugPrint((1, "CdRomMediaChangeCompletion: Request completed normally"
05646                        "for CdRom%d which was marked w/NoMedia [irp = 0x%lx]\n",
05647                     deviceExtension->DeviceNumber, Irp));
05648 
05649         KeSetEvent(deviceExtension->MediaChangeEvent,
05650                    (KPRIORITY) 0,
05651                    FALSE);
05652 
05653         deviceExtension->MediaChangeNoMedia = FALSE;
05654 
05655     }
05656 
05657     if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
05658         ScsiClassReleaseQueue(deviceExtension->DeviceObject);
05659     }
05660 
05661     //
05662     // Remember the IRP and SRB for use the next time.
05663     //
05664 
05665     irpNextStack->Parameters.Scsi.Srb = srb;
05666     cddata->MediaChangeIrp = Irp;
05667 
05668     if (deviceExtension->ClassError) {
05669 
05670         NTSTATUS status;
05671         BOOLEAN  retry;
05672 
05673         //
05674         // Throw away the status and retry values. Just give the error routine a chance
05675         // to do what it needs to.
05676         //
05677 
05678         deviceExtension->ClassError(DeviceObject,
05679                                     srb,
05680                                     &status,
05681                                     &retry);
05682     }
05683 
05684     IoStartNextPacket(DeviceObject, FALSE);
05685 
05686     return STATUS_MORE_PROCESSING_REQUIRED;
05687 }
05688 
05689 VOID
05690 NTAPI
05691 CdRomTickHandler(
05692     IN PDEVICE_OBJECT DeviceObject,
05693     IN PVOID Context
05694     )
05695 
05696 /*++
05697 
05698 Routine Description:
05699 
05700     This routine handles the once per second timer provided by the
05701     Io subsystem.  It is only used when the cdrom device itself is
05702     a candidate for autoplay support.  It should never be called if
05703     the cdrom device is a changer device.
05704 
05705 Arguments:
05706 
05707     DeviceObject - what to check.
05708     Context - not used.
05709 
05710 Return Value:
05711 
05712     None.
05713 
05714 --*/
05715 
05716 {
05717     PIRP              irp;
05718     PIRP              heldIrpList;
05719     PIRP              nextIrp;
05720     PLIST_ENTRY       listEntry;
05721     PCDROM_DATA       cddata;
05722     PIO_STACK_LOCATION irpStack;
05723     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
05724 
05725     cddata = (PCDROM_DATA)(deviceExtension + 1);
05726 
05727     if (cddata->MediaChange) {
05728         if (cddata->MediaChangeIrp != NULL) {
05729 
05730             //
05731             // Media change support is active and the IRP is waiting.
05732             // Decrement the timer.
05733             // There is no MP protection on the timer counter.  This
05734             // code is the only code that will manipulate the timer
05735             // and only one instance of it should be running at any
05736             // given time.
05737             //
05738 
05739             cddata->MediaChangeCountDown--;
05740 
05741 #if DBG
05742             cddata->MediaChangeIrpTimeInUse = 0;
05743             cddata->MediaChangeIrpLost = FALSE;
05744 #endif
05745 
05746             if (!cddata->MediaChangeCountDown) {
05747                 PSCSI_REQUEST_BLOCK srb;
05748                 PIO_STACK_LOCATION  irpNextStack;
05749                 PCDB cdb;
05750 
05751                 //
05752                 // Reset the timer.
05753                 //
05754 
05755                 cddata->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
05756 
05757                 //
05758                 // Prepare the IRP for the test unit ready
05759                 //
05760 
05761                 irp = cddata->MediaChangeIrp;
05762                 cddata->MediaChangeIrp = NULL;
05763 
05764                 irp->IoStatus.Status = STATUS_SUCCESS;
05765                 irp->IoStatus.Information = 0;
05766                 irp->Flags = 0;
05767                 irp->UserBuffer = NULL;
05768 
05769                 //
05770                 // If the irp is sent down when the volume needs to be
05771                 // verified, CdRomUpdateGeometryCompletion won't complete
05772                 // it since it's not associated with a thread.  Marking
05773                 // it to override the verify causes it always be sent
05774                 // to the port driver
05775                 //
05776 
05777                 irpStack = IoGetCurrentIrpStackLocation(irp);
05778                 irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
05779 
05780                 irpNextStack = IoGetNextIrpStackLocation(irp);
05781                 irpNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
05782                 irpNextStack->Parameters.DeviceIoControl.IoControlCode =
05783                     IOCTL_SCSI_EXECUTE_NONE;
05784 
05785                 //
05786                 // Prepare the SRB for execution.
05787                 //
05788 
05789                 srb = irpNextStack->Parameters.Scsi.Srb;
05790                 srb->SrbStatus = srb->ScsiStatus = 0;
05791                 srb->NextSrb = 0;
05792                 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
05793                 srb->PathId = deviceExtension->PathId;
05794                 srb->TargetId = deviceExtension->TargetId;
05795                 srb->Lun = deviceExtension->Lun;
05796                 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
05797                 srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
05798                                 SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
05799                 srb->DataTransferLength = 0;
05800                 srb->OriginalRequest = irp;
05801 
05802                 RtlZeroMemory(srb->SenseInfoBuffer, SENSE_BUFFER_SIZE);
05803                 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
05804 
05805                 cdb = (PCDB) &srb->Cdb[0];
05806                 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
05807                 cdb->CDB6GENERIC.LogicalUnitNumber = srb->Lun;
05808 
05809                 //
05810                 // Setup the IRP to perform a test unit ready.
05811                 //
05812 
05813                 IoSetCompletionRoutine(irp,
05814                                        CdRomMediaChangeCompletion,
05815                                        srb,
05816                                        TRUE,
05817                                        TRUE,
05818                                        TRUE);
05819 
05820                 //
05821                 // Issue the request.
05822                 //
05823 
05824                 IoStartPacket(DeviceObject, irp, NULL, NULL);
05825             }
05826         } else {
05827 
05828 #if DBG
05829             if(cddata->MediaChangeIrpLost == FALSE) {
05830                 if(cddata->MediaChangeIrpTimeInUse++ >
05831                    MEDIA_CHANGE_TIMEOUT_TIME) {
05832 
05833                     DebugPrint((0, "CdRom%d: AutoPlay has lost it's irp and "
05834                                    "doesn't know where to find it.  Leave it "
05835                                    "alone and it'll come home dragging it's "
05836                                    "stack behind it.\n",
05837                                    deviceExtension->DeviceNumber));
05838                     cddata->MediaChangeIrpLost = TRUE;
05839                 }
05840             }
05841 
05842 #endif
05843         }
05844     }
05845 
05846     //
05847     // Process all generic timer IRPS in the timer list.  As IRPs are pulled
05848     // off of the TimerIrpList they must be remembered in the first loop
05849     // if they are not sent to the lower driver.  After all items have
05850     // been pulled off the list, it is possible to put the held IRPs back
05851     // into the TimerIrpList.
05852     //
05853 
05854     heldIrpList = NULL;
05855     if (IsListEmpty(&cddata->TimerIrpList)) {
05856         listEntry = NULL;
05857     } else {
05858         listEntry = ExInterlockedRemoveHeadList(&cddata->TimerIrpList,
05859                                                 &cddata->TimerIrpSpinLock);
05860     }
05861     while (listEntry) {
05862 
05863         //
05864         // There is something in the timer list.  Pick up the IRP and
05865         // see if it is ready to be submitted.
05866         //
05867 
05868         irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
05869         irpStack = IoGetCurrentIrpStackLocation(irp);
05870 
05871         if (irpStack->Parameters.Others.Argument3) {
05872             ULONG_PTR count;
05873 
05874             //
05875             // Decrement the countdown timer and put the IRP back in the list.
05876             //
05877 
05878             count = (ULONG_PTR) irpStack->Parameters.Others.Argument3;
05879             count--;
05880             irpStack->Parameters.Others.Argument3 = (PVOID) count;
05881 
05882             ASSERT(irp->AssociatedIrp.MasterIrp == NULL);
05883             if (heldIrpList) {
05884                 irp->AssociatedIrp.MasterIrp = (PVOID) heldIrpList;
05885             }
05886             heldIrpList = irp;
05887 
05888         } else {
05889 
05890             //
05891             // Submit this IRP to the lower driver.  This IRP does not
05892             // need to be remembered here.  It will be handled again when
05893             // it completes.
05894             //
05895 
05896             DebugPrint((1, "CdRomTickHandler: Reissuing request %lx (thread = %lx)\n", irp, irp->Tail.Overlay.Thread));
05897 
05898             //
05899             // feed this to the appropriate port driver
05900             //
05901 
05902             IoCallDriver (deviceExtension->PortDeviceObject, irp);
05903 
05904         }
05905 
05906         //
05907         // Pick up the next IRP from the timer list.
05908         //
05909 
05910         listEntry = ExInterlockedRemoveHeadList(&cddata->TimerIrpList,
05911                                                 &cddata->TimerIrpSpinLock);
05912     }
05913 
05914     //
05915     // Move all held IRPs back onto the timer list.
05916     //
05917 
05918     while (heldIrpList) {
05919 
05920         //
05921         // Save the single list pointer before queueing this IRP.
05922         //
05923 
05924         nextIrp = (PIRP) heldIrpList->AssociatedIrp.MasterIrp;
05925         heldIrpList->AssociatedIrp.MasterIrp = NULL;
05926 
05927         //
05928         // Return the held IRP to the timer list.
05929         //
05930 
05931         ExInterlockedInsertTailList(&cddata->TimerIrpList,
05932                                     &heldIrpList->Tail.Overlay.ListEntry,
05933                                     &cddata->TimerIrpSpinLock);
05934 
05935         //
05936         // Continue processing the held IRPs
05937         //
05938 
05939         heldIrpList = nextIrp;
05940     }
05941 }
05942 
05943 BOOLEAN
05944 NTAPI
05945 CdRomCheckRegistryForMediaChangeValue(
05946     IN PUNICODE_STRING RegistryPath,
05947     IN ULONG DeviceNumber
05948     )
05949 
05950 /*++
05951 
05952 Routine Description:
05953 
05954     The user must specify that AutoPlay is to run on the platform
05955     by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
05956     Services\Cdrom\Autorun:REG_DWORD:1.
05957 
05958     The user can override the global setting to enable or disable Autorun on a
05959     specific cdrom device by setting the key HKEY_LOCAL_MACHINE\System\
05960     CurrentControlSet\Services\Cdrom\Device<N>\Autorun:REG_DWORD to one or zero.
05961     (CURRENTLY UNIMPLEMENTED)
05962 
05963     If this registry value does not exist or contains the value zero then
05964     the timer to check for media change does not run.
05965 
05966 Arguments:
05967 
05968     RegistryPath - pointer to the unicode string inside
05969                    ...\CurrentControlSet\Services\Cdrom
05970     DeviceNumber - The number of the device object
05971 
05972 Return Value:
05973 
05974     TRUE - Autorun is enabled.
05975     FALSE - no autorun.
05976 
05977 --*/
05978 
05979 {
05980 #define ITEMS_TO_QUERY 2 /* always 1 greater than what is searched */
05981     PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
05982     NTSTATUS          status;
05983     LONG              zero = 0;
05984 
05985     LONG              tmp = 0;
05986     LONG              doRun = 0;
05987 
05988     CHAR              buf[32];
05989     ANSI_STRING       paramNum;
05990 
05991     UNICODE_STRING    paramStr;
05992 
05993     UNICODE_STRING    paramSuffix;
05994     UNICODE_STRING    paramPath;
05995     UNICODE_STRING    paramDevPath;
05996 
05997     //
05998     // First append \Parameters to the passed in registry path
05999     //
06000 
06001     RtlInitUnicodeString(&paramStr, L"\\Parameters");
06002 
06003     RtlInitUnicodeString(&paramPath, NULL);
06004 
06005     paramPath.MaximumLength = RegistryPath->Length +
06006                               paramStr.Length +
06007                               sizeof(WCHAR);
06008 
06009     paramPath.Buffer = ExAllocatePool(PagedPool, paramPath.MaximumLength);
06010 
06011     if(!paramPath.Buffer) {
06012 
06013         DebugPrint((1,"CdRomCheckRegAP: couldn't allocate paramPath\n"));
06014 
06015         return FALSE;
06016     }
06017 
06018     RtlZeroMemory(paramPath.Buffer, paramPath.MaximumLength);
06019     RtlAppendUnicodeToString(&paramPath, RegistryPath->Buffer);
06020     RtlAppendUnicodeToString(&paramPath, paramStr.Buffer);
06021 
06022     DebugPrint((2, "CdRomCheckRegAP: paramPath [%d] = %ws\n",
06023                 paramPath.Length,
06024                 paramPath.Buffer));
06025 
06026     //
06027     // build a counted ANSI string that contains
06028     // the suffix for the path
06029     //
06030 
06031     sprintf(buf, "\\Device%lu", DeviceNumber);
06032     RtlInitAnsiString(&paramNum, buf);
06033 
06034     //
06035     // Next convert this into a unicode string
06036     //
06037 
06038     status = RtlAnsiStringToUnicodeString(&paramSuffix, &paramNum, TRUE);
06039 
06040     if(!NT_SUCCESS(status)) {
06041         DebugPrint((1,"CdRomCheckRegAP: couldn't convert paramNum to paramSuffix\n"));
06042         ExFreePool(paramPath.Buffer);
06043         return FALSE;
06044     }
06045 
06046     RtlInitUnicodeString(&paramDevPath, NULL);
06047 
06048     //
06049     // now build the device specific path
06050     //
06051 
06052     paramDevPath.MaximumLength = paramPath.Length +
06053                                  paramSuffix.Length +
06054                                  sizeof(WCHAR);
06055     paramDevPath.Buffer = ExAllocatePool(PagedPool, paramDevPath.MaximumLength);
06056 
06057     if(!paramDevPath.Buffer) {
06058         RtlFreeUnicodeString(&paramSuffix);
06059         ExFreePool(paramPath.Buffer);
06060         return FALSE;
06061     }
06062 
06063     RtlZeroMemory(paramDevPath.Buffer, paramDevPath.MaximumLength);
06064     RtlAppendUnicodeToString(&paramDevPath, paramPath.Buffer);
06065     RtlAppendUnicodeToString(&paramDevPath, paramSuffix.Buffer);
06066 
06067     DebugPrint((2, "CdRomCheckRegAP: paramDevPath [%d] = %ws\n",
06068                 paramPath.Length,
06069                 paramPath.Buffer));
06070 
06071     parameters = ExAllocatePool(NonPagedPool,
06072                                 sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY);
06073 
06074     if (parameters) {
06075 
06076         //
06077         // Check for the Autorun value.
06078         //
06079 
06080         RtlZeroMemory(parameters,
06081                       (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY));
06082 
06083         parameters[0].Flags         = RTL_QUERY_REGISTRY_DIRECT;
06084         parameters[0].Name          = L"Autorun";
06085         parameters[0].EntryContext  = &doRun;
06086         parameters[0].DefaultType   = REG_DWORD;
06087         parameters[0].DefaultData   = &zero;
06088         parameters[0].DefaultLength = sizeof(ULONG);
06089 
06090         status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
06091                                         RegistryPath->Buffer,
06092                                         parameters,
06093                                         NULL,
06094                                         NULL);
06095 
06096         DebugPrint((2, "CdRomCheckRegAP: cdrom/Autorun flag = %d\n", doRun));
06097 
06098         RtlZeroMemory(parameters,
06099                       (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY));
06100 
06101         parameters[0].Flags         = RTL_QUERY_REGISTRY_DIRECT;
06102         parameters[0].Name          = L"Autorun";
06103         parameters[0].EntryContext  = &tmp;
06104         parameters[0].DefaultType   = REG_DWORD;
06105         parameters[0].DefaultData   = &doRun;
06106         parameters[0].DefaultLength = sizeof(ULONG);
06107 
06108         status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
06109                                         paramPath.Buffer,
06110                                         parameters,
06111                                         NULL,
06112                                         NULL);
06113 
06114         DebugPrint((2, "CdRomCheckRegAP: cdrom/parameters/autorun flag = %d\n", tmp));
06115 
06116         RtlZeroMemory(parameters,
06117                       (sizeof(RTL_QUERY_REGISTRY_TABLE) * ITEMS_TO_QUERY));
06118 
06119         parameters[0].Flags         = RTL_QUERY_REGISTRY_DIRECT;
06120         parameters[0].Name          = L"Autorun";
06121         parameters[0].EntryContext  = &doRun;
06122         parameters[0].DefaultType   = REG_DWORD;
06123         parameters[0].DefaultData   = &tmp;
06124         parameters[0].DefaultLength = sizeof(ULONG);
06125 
06126         status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
06127                                         paramDevPath.Buffer,
06128                                         parameters,
06129                                         NULL,
06130                                         NULL);
06131 
06132         DebugPrint((1, "CdRomCheckRegAP: cdrom/parameters/device%d/autorun flag = %d\n", DeviceNumber, doRun));
06133 
06134         ExFreePool(parameters);
06135 
06136     }
06137 
06138     ExFreePool(paramPath.Buffer);
06139     ExFreePool(paramDevPath.Buffer);
06140     RtlFreeUnicodeString(&paramSuffix);
06141 
06142     DebugPrint((1, "CdRomCheckRegAP: Autoplay for device %d is %s\n",
06143                 DeviceNumber,
06144                 (doRun ? "on" : "off")));
06145 
06146     if(doRun) {
06147         return TRUE;
06148     }
06149 
06150     return FALSE;
06151 }
06152 
06153 
06154 BOOLEAN
06155 NTAPI
06156 IsThisASanyo(
06157     IN  PDEVICE_OBJECT DeviceObject,
06158     IN  UCHAR          PathId,
06159     IN  UCHAR          TargetId
06160     )
06161 
06162 /*++
06163 
06164 Routine Description:
06165 
06166     This routine is called by DriverEntry to determine whether a Sanyo 3-CD
06167     changer device is present.
06168 
06169 Arguments:
06170 
06171     DeviceObject - Supplies the device object for the 'real' device.
06172 
06173     PathId       -
06174 
06175 Return Value:
06176 
06177     TRUE - if an Atapi changer device is found.
06178 
06179 --*/
06180 
06181 {
06182     KEVENT                 event;
06183     PIRP                   irp;
06184     PCHAR                  inquiryBuffer;
06185     IO_STATUS_BLOCK        ioStatus;
06186     NTSTATUS               status;
06187     PSCSI_ADAPTER_BUS_INFO adapterInfo;
06188     ULONG                  scsiBus;
06189     PINQUIRYDATA           inquiryData;
06190     PSCSI_INQUIRY_DATA     lunInfo;
06191 
06192     inquiryBuffer = ExAllocatePool(NonPagedPool, 2048);
06193     KeInitializeEvent(&event, NotificationEvent, FALSE);
06194     irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
06195                                         DeviceObject,
06196                                         NULL,
06197                                         0,
06198                                         inquiryBuffer,
06199                                         2048,
06200                                         FALSE,
06201                                         &event,
06202                                         &ioStatus);
06203     if (!irp) {
06204         return FALSE;
06205     }
06206 
06207     status = IoCallDriver(DeviceObject, irp);
06208 
06209     if (status == STATUS_PENDING) {
06210         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
06211         status = ioStatus.Status;
06212     }
06213 
06214     if (!NT_SUCCESS(status)) {
06215         return FALSE;
06216     }
06217 
06218     adapterInfo = (PVOID) inquiryBuffer;
06219 
06220     for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) {
06221 
06222         //
06223         // Get the SCSI bus scan data for this bus.
06224         //
06225 
06226         lunInfo = (PVOID) (inquiryBuffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
06227 
06228         for (;;) {
06229 
06230             if (lunInfo->PathId == PathId && lunInfo->TargetId == TargetId) {
06231 
06232                 inquiryData = (PVOID) lunInfo->InquiryData;
06233 
06234                 if (RtlCompareMemory(inquiryData->VendorId, "TORiSAN CD-ROM CDR-C", 20) == 20) {
06235                     ExFreePool(inquiryBuffer);
06236                     return TRUE;
06237                 }
06238 
06239                 ExFreePool(inquiryBuffer);
06240                 return FALSE;
06241             }
06242 
06243             if (!lunInfo->NextInquiryDataOffset) {
06244                 break;
06245             }
06246 
06247             lunInfo = (PVOID) (inquiryBuffer + lunInfo->NextInquiryDataOffset);
06248         }
06249     }
06250 
06251     ExFreePool(inquiryBuffer);
06252     return FALSE;
06253 }
06254 
06255 BOOLEAN
06256 NTAPI
06257 IsThisAnAtapiChanger(
06258     IN  PDEVICE_OBJECT DeviceObject,
06259     OUT PULONG         DiscsPresent
06260     )
06261 
06262 /*++
06263 
06264 Routine Description:
06265 
06266     This routine is called by DriverEntry to determine whether an Atapi
06267     changer device is present.
06268 
06269 Arguments:
06270 
06271     DeviceObject    - Supplies the device object for the 'real' device.
06272 
06273     DiscsPresent    - Supplies a pointer to the number of Discs supported by the changer.
06274 
06275 Return Value:
06276 
06277     TRUE - if an Atapi changer device is found.
06278 
06279 --*/
06280 
06281 {
06282     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
06283     PMECHANICAL_STATUS_INFORMATION_HEADER mechanicalStatusBuffer;
06284     NTSTATUS            status;
06285     SCSI_REQUEST_BLOCK  srb;
06286     PCDB                cdb = (PCDB) &srb.Cdb[0];
06287     BOOLEAN             retVal = FALSE;
06288 
06289     *DiscsPresent = 0;
06290 
06291     //
06292     // Some devices can't handle 12 byte CDB's gracefully
06293     //
06294 
06295     if(deviceExtension->DeviceFlags & DEV_NO_12BYTE_CDB) {
06296 
06297         return FALSE;
06298 
06299     }
06300 
06301     //
06302     // Build and issue the mechanical status command.
06303     //
06304 
06305     mechanicalStatusBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
06306                                             sizeof(MECHANICAL_STATUS_INFORMATION_HEADER));
06307 
06308     if (!mechanicalStatusBuffer) {
06309         retVal = FALSE;
06310     } else {
06311 
06312         //
06313         // Build and send the Mechanism status CDB.
06314         //
06315 
06316         RtlZeroMemory(&srb, sizeof(srb));
06317 
06318         srb.CdbLength = 12;
06319         srb.TimeOutValue = 20;
06320 
06321         cdb->MECH_STATUS.OperationCode = SCSIOP_MECHANISM_STATUS;
06322         cdb->MECH_STATUS.AllocationLength[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
06323 
06324         status = ScsiClassSendSrbSynchronous(DeviceObject,
06325                                              &srb,
06326                                              mechanicalStatusBuffer,
06327                                              sizeof(MECHANICAL_STATUS_INFORMATION_HEADER),
06328                                              FALSE);
06329 
06330 
06331         if (status == STATUS_SUCCESS) {
06332 
06333             //
06334             // Indicate number of slots available
06335             //
06336 
06337             *DiscsPresent = mechanicalStatusBuffer->NumberAvailableSlots;
06338             if (*DiscsPresent > 1) {
06339                 retVal = TRUE;
06340             } else {
06341 
06342                 //
06343                 // If only one disc, no need for this driver.
06344                 //
06345 
06346                 retVal = FALSE;
06347             }
06348         } else {
06349 
06350             //
06351             // Device doesn't support this command.
06352             //
06353 
06354             retVal = FALSE;
06355         }
06356 
06357         ExFreePool(mechanicalStatusBuffer);
06358     }
06359 
06360     return retVal;
06361 }
06362 
06363 BOOLEAN
06364 NTAPI
06365 IsThisAMultiLunDevice(
06366     IN PDEVICE_OBJECT DeviceObject,
06367     IN PDEVICE_OBJECT PortDeviceObject
06368     )
06369 /*++
06370 
06371 Routine Description:
06372 
06373     This routine is called to determine whether a multi-lun
06374     device is present.
06375 
06376 Arguments:
06377 
06378     DeviceObject    - Supplies the device object for the 'real' device.
06379 
06380 Return Value:
06381 
06382     TRUE - if a Multi-lun device is found.
06383 
06384 --*/
06385 {
06386     PCHAR buffer;
06387     PSCSI_INQUIRY_DATA lunInfo;
06388     PSCSI_ADAPTER_BUS_INFO  adapterInfo;
06389     PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
06390     PINQUIRYDATA inquiryData;
06391     ULONG scsiBus;
06392     NTSTATUS status;
06393     UCHAR lunCount = 0;
06394 
06395     status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
06396 
06397     if (!NT_SUCCESS(status)) {
06398         DebugPrint((1,"IsThisAMultiLunDevice: ScsiClassGetInquiryData failed\n"));
06399         return FALSE;
06400     }
06401 
06402     adapterInfo = (PVOID) buffer;
06403 
06404     //
06405     // For each SCSI bus this adapter supports ...
06406     //
06407 
06408     for (scsiBus=0; scsiBus < adapterInfo->NumberOfBuses; scsiBus++) {
06409 
06410         //
06411         // Get the SCSI bus scan data for this bus.
06412         //
06413 
06414         lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
06415 
06416         while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
06417 
06418             inquiryData = (PVOID)lunInfo->InquiryData;
06419 
06420             if ((lunInfo->PathId == deviceExtension->PathId) &&
06421                 (lunInfo->TargetId == deviceExtension->TargetId) &&
06422                 (inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE)) {
06423 
06424                 DebugPrint((1,"IsThisAMultiLunDevice: Vendor string is %.24s\n",
06425                             inquiryData->VendorId));
06426 
06427                 //
06428                 // If this device has more than one cdrom-type lun then we
06429                 // won't support autoplay on it
06430                 //
06431 
06432                 if (lunCount++) {
06433                     ExFreePool(buffer);
06434                     return TRUE;
06435                 }
06436             }
06437 
06438             //
06439             // Get next LunInfo.
06440             //
06441 
06442             if (lunInfo->NextInquiryDataOffset == 0) {
06443                 break;
06444             }
06445 
06446             lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
06447         }
06448     }
06449 
06450     ExFreePool(buffer);
06451     return FALSE;
06452 
06453 }
06454 
06455 IO_COMPLETION_ROUTINE CdRomUpdateGeometryCompletion;
06456 NTSTATUS
06457 NTAPI
06458 CdRomUpdateGeometryCompletion(
06459     PDEVICE_OBJECT DeviceObject,
06460     PIRP Irp,
06461     PVOID Context
06462     )
06463 
06464 /*++
06465 
06466 Routine Description:
06467 
06468     This routine andles the completion of the test unit ready irps
06469     used to determine if the media has changed.  If the media has
06470     changed, this code signals the named event to wake up other
06471     system services that react to media change (aka AutoPlay).
06472 
06473 Arguments:
06474 
06475     DeviceObject - the object for the completion
06476     Irp - the IRP being completed
06477     Context - the SRB from the IRP
06478 
06479 Return Value:
06480 
06481     NTSTATUS
06482 
06483 --*/
06484 
06485 {
06486     PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK) Context;
06487     PREAD_CAPACITY_DATA readCapacityBuffer;
06488     PDEVICE_EXTENSION   deviceExtension;
06489     PIO_STACK_LOCATION  irpStack;
06490     NTSTATUS            status;
06491     BOOLEAN             retry;
06492     ULONG_PTR           retryCount;
06493     ULONG               lastSector;
06494     PIRP                originalIrp;
06495     PCDROM_DATA         cddata;
06496 
06497     //
06498     // Get items saved in the private IRP stack location.
06499     //
06500 
06501     irpStack = IoGetCurrentIrpStackLocation(Irp);
06502     retryCount = (ULONG_PTR) irpStack->Parameters.Others.Argument1;
06503     originalIrp = (PIRP) irpStack->Parameters.Others.Argument2;
06504 
06505     if (!DeviceObject) {
06506         DeviceObject = irpStack->DeviceObject;
06507     }
06508     ASSERT(DeviceObject);
06509 
06510     deviceExtension = DeviceObject->DeviceExtension;
06511     cddata = (PCDROM_DATA) (deviceExtension + 1);
06512     readCapacityBuffer = srb->DataBuffer;
06513 
06514     if ((NT_SUCCESS(Irp->IoStatus.Status)) && (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)) {
06515         PFOUR_BYTE from;
06516         PFOUR_BYTE to;
06517 
06518         DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] successful completion of buddy-irp %lx\n", originalIrp, Irp));
06519         //
06520         // Copy sector size from read capacity buffer to device extension
06521         // in reverse byte order.
06522         //
06523 
06524         from = (PFOUR_BYTE) &readCapacityBuffer->BytesPerBlock;
06525         to = (PFOUR_BYTE) &deviceExtension->DiskGeometry->Geometry.BytesPerSector;
06526         to->Byte0 = from->Byte3;
06527         to->Byte1 = from->Byte2;
06528         to->Byte2 = from->Byte1;
06529         to->Byte3 = from->Byte0;
06530 
06531         //
06532         // Using the new BytesPerBlock, calculate and store the SectorShift.
06533         //
06534 
06535         WHICH_BIT(deviceExtension->DiskGeometry->Geometry.BytesPerSector, deviceExtension->SectorShift);
06536 
06537         //
06538         // Copy last sector in reverse byte order.
06539         //
06540 
06541         from = (PFOUR_BYTE) &readCapacityBuffer->LogicalBlockAddress;
06542         to = (PFOUR_BYTE) &lastSector;
06543         to->Byte0 = from->Byte3;
06544         to->Byte1 = from->Byte2;
06545         to->Byte2 = from->Byte1;
06546         to->Byte3 = from->Byte0;
06547         deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
06548 
06549         //
06550         // Calculate number of cylinders.
06551         //
06552 
06553         deviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64));
06554         deviceExtension->PartitionLength.QuadPart =
06555             (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
06556         deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia;
06557 
06558         //
06559         // Assume sectors per track are 32;
06560         //
06561 
06562         deviceExtension->DiskGeometry->Geometry.SectorsPerTrack = 32;
06563 
06564         //
06565         // Assume tracks per cylinder (number of heads) is 64.
06566         //
06567 
06568         deviceExtension->DiskGeometry->Geometry.TracksPerCylinder = 64;
06569 
06570     } else {
06571 
06572         DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] unsuccessful completion of buddy-irp %lx (status - %lx)\n", originalIrp, Irp, Irp->IoStatus.Status));
06573 
06574         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
06575             ScsiClassReleaseQueue(DeviceObject);
06576         }
06577 
06578         retry = ScsiClassInterpretSenseInfo(DeviceObject,
06579                                             srb,
06580                                             IRP_MJ_SCSI,
06581                                             0,
06582                                             retryCount,
06583                                             &status);
06584         if (retry) {
06585             retryCount--;
06586             if (retryCount) {
06587                 PCDB cdb;
06588 
06589                 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] Retrying request %lx .. thread is %lx\n", originalIrp, Irp, Irp->Tail.Overlay.Thread));
06590                 //
06591                 // set up a one shot timer to get this process started over
06592                 //
06593 
06594                 irpStack->Parameters.Others.Argument1 = (PVOID) retryCount;
06595                 irpStack->Parameters.Others.Argument2 = (PVOID) originalIrp;
06596                 irpStack->Parameters.Others.Argument3 = (PVOID) 2;
06597 
06598                 //
06599                 // Setup the IRP to be submitted again in the timer routine.
06600                 //
06601 
06602                 irpStack = IoGetNextIrpStackLocation(Irp);
06603                 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
06604                 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
06605                 irpStack->Parameters.Scsi.Srb = srb;
06606                 IoSetCompletionRoutine(Irp,
06607                                        CdRomUpdateGeometryCompletion,
06608                                        srb,
06609                                        TRUE,
06610                                        TRUE,
06611                                        TRUE);
06612 
06613                 //
06614                 // Set up the SRB for read capacity.
06615                 //
06616 
06617                 srb->CdbLength = 10;
06618                 srb->TimeOutValue = deviceExtension->TimeOutValue;
06619                 srb->SrbStatus = srb->ScsiStatus = 0;
06620                 srb->NextSrb = 0;
06621                 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
06622                 srb->PathId = deviceExtension->PathId;
06623                 srb->TargetId = deviceExtension->TargetId;
06624                 srb->Lun = deviceExtension->Lun;
06625                 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
06626                 srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
06627                 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
06628 
06629                 //
06630                 // Set up the CDB
06631                 //
06632 
06633                 cdb = (PCDB) &srb->Cdb[0];
06634                 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
06635                 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
06636 
06637                 //
06638                 // Requests queued onto this list will be sent to the
06639                 // lower level driver during CdRomTickHandler
06640                 //
06641 
06642                 ExInterlockedInsertHeadList(&cddata->TimerIrpList,
06643                                             &Irp->Tail.Overlay.ListEntry,
06644                                             &cddata->TimerIrpSpinLock);
06645 
06646                 return STATUS_MORE_PROCESSING_REQUIRED;
06647             } else {
06648 
06649                 //
06650                 // This has been bounced for a number of times.  Error the
06651                 // original request.
06652                 //
06653 
06654                 originalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
06655                 RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY_EX));
06656                 deviceExtension->DiskGeometry->Geometry.BytesPerSector = 2048;
06657                 deviceExtension->SectorShift = 11;
06658                 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
06659                 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia;
06660             }
06661         } else {
06662 
06663             //
06664             // Set up reasonable defaults
06665             //
06666 
06667             RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY_EX));
06668             deviceExtension->DiskGeometry->Geometry.BytesPerSector = 2048;
06669             deviceExtension->SectorShift = 11;
06670             deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
06671             deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia;
06672         }
06673     }
06674 
06675     //
06676     // Free resources held.
06677     //
06678 
06679     ExFreePool(srb->SenseInfoBuffer);
06680     ExFreePool(srb->DataBuffer);
06681     ExFreePool(srb);
06682     if (Irp->MdlAddress) {
06683         IoFreeMdl(Irp->MdlAddress);
06684     }
06685     IoFreeIrp(Irp);
06686     if (originalIrp->Tail.Overlay.Thread) {
06687 
06688         DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] completing original IRP\n", originalIrp));
06689         IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
06690 
06691     } else {
06692         DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] original irp has "
06693                        "no thread\n",
06694                     originalIrp
06695                   ));
06696     }
06697 
06698     //
06699     // It's now safe to either start the next request or let the waiting ioctl
06700     // request continue along it's merry way
06701     //
06702 
06703     IoStartNextPacket(DeviceObject, FALSE);
06704 
06705     return STATUS_MORE_PROCESSING_REQUIRED;
06706 }
06707 
06708 NTSTATUS
06709 NTAPI
06710 CdRomUpdateCapacity(
06711     IN PDEVICE_EXTENSION DeviceExtension,
06712     IN PIRP IrpToComplete,
06713     IN OPTIONAL PKEVENT IoctlEvent
06714     )
06715 
06716 /*++
06717 
06718 Routine Description:
06719 
06720     This routine updates the capacity of the disk as recorded in the device extension.
06721     It also completes the IRP given with STATUS_VERIFY_REQUIRED.  This routine is called
06722     when a media change has occurred and it is necessary to determine the capacity of the
06723     new media prior to the next access.
06724 
06725 Arguments:
06726 
06727     DeviceExtension - the device to update
06728     IrpToComplete - the request that needs to be completed when done.
06729 
06730 Return Value:
06731 
06732     NTSTATUS
06733 
06734 --*/
06735 
06736 {
06737     PCDB                cdb;
06738     PIRP                irp;
06739     PSCSI_REQUEST_BLOCK srb;
06740     PREAD_CAPACITY_DATA capacityBuffer;
06741     PIO_STACK_LOCATION  irpStack;
06742     PUCHAR              senseBuffer;
06743 
06744     irp = IoAllocateIrp((CCHAR)(DeviceExtension->DeviceObject->StackSize+1),
06745                         FALSE);
06746 
06747     if (irp) {
06748 
06749         srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
06750         if (srb) {
06751             capacityBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
06752                                             sizeof(READ_CAPACITY_DATA));
06753 
06754             if (capacityBuffer) {
06755 
06756 
06757                 senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
06758 
06759                 if (senseBuffer) {
06760 
06761                     irp->MdlAddress = IoAllocateMdl(capacityBuffer,
06762                                                     sizeof(READ_CAPACITY_DATA),
06763                                                     FALSE,
06764                                                     FALSE,
06765                                                     (PIRP) NULL);
06766 
06767                     if (irp->MdlAddress) {
06768 
06769                         //
06770                         // Have all resources.  Set up the IRP to send for the capacity.
06771                         //
06772 
06773                         IoSetNextIrpStackLocation(irp);
06774                         irp->IoStatus.Status = STATUS_SUCCESS;
06775                         irp->IoStatus.Information = 0;
06776                         irp->Flags = 0;
06777                         irp->UserBuffer = NULL;
06778 
06779                         //
06780                         // Save the device object and retry count in a private stack location.
06781                         //
06782 
06783                         irpStack = IoGetCurrentIrpStackLocation(irp);
06784                         irpStack->DeviceObject = DeviceExtension->DeviceObject;
06785                         irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
06786                         irpStack->Parameters.Others.Argument2 = (PVOID) IrpToComplete;
06787 
06788                         //
06789                         // Construct the IRP stack for the lower level driver.
06790                         //
06791 
06792                         irpStack = IoGetNextIrpStackLocation(irp);
06793                         irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
06794                         irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
06795                         irpStack->Parameters.Scsi.Srb = srb;
06796                         IoSetCompletionRoutine(irp,
06797                                                CdRomUpdateGeometryCompletion,
06798                                                srb,
06799                                                TRUE,
06800                                                TRUE,
06801                                                TRUE);
06802                         //
06803                         // Prepare the MDL
06804                         //
06805 
06806                         MmBuildMdlForNonPagedPool(irp->MdlAddress);
06807 
06808 
06809                         //
06810                         // Set up the SRB for read capacity.
06811                         //
06812 
06813                         RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
06814                         RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);
06815                         srb->CdbLength = 10;
06816                         srb->TimeOutValue = DeviceExtension->TimeOutValue;
06817                         srb->SrbStatus = srb->ScsiStatus = 0;
06818                         srb->NextSrb = 0;
06819                         srb->Length = SCSI_REQUEST_BLOCK_SIZE;
06820                         srb->PathId = DeviceExtension->PathId;
06821                         srb->TargetId = DeviceExtension->TargetId;
06822                         srb->Lun = DeviceExtension->Lun;
06823                         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
06824                         srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
06825                         srb->DataBuffer = capacityBuffer;
06826                         srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
06827                         srb->OriginalRequest = irp;
06828                         srb->SenseInfoBuffer = senseBuffer;
06829                         srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
06830 
06831                         //
06832                         // Set up the CDB
06833                         //
06834 
06835                         cdb = (PCDB) &srb->Cdb[0];
06836                         cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
06837                         cdb->CDB10.LogicalUnitNumber = DeviceExtension->Lun;
06838 
06839                         //
06840                         // Set the return value in the IRP that will be completed
06841                         // upon completion of the read capacity.
06842                         //
06843 
06844                         IrpToComplete->IoStatus.Status = STATUS_VERIFY_REQUIRED;
06845                         IoMarkIrpPending(IrpToComplete);
06846 
06847                         IoCallDriver(DeviceExtension->PortDeviceObject, irp);
06848 
06849                         //
06850                         // status is not checked because the completion routine for this
06851                         // IRP will always get called and it will free the resources.
06852                         //
06853 
06854                         return STATUS_PENDING;
06855 
06856                     } else {
06857                         ExFreePool(senseBuffer);
06858                         ExFreePool(capacityBuffer);
06859                         ExFreePool(srb);
06860                         IoFreeIrp(irp);
06861                     }
06862                 } else {
06863                     ExFreePool(capacityBuffer);
06864                     ExFreePool(srb);
06865                     IoFreeIrp(irp);
06866                 }
06867             } else {
06868                 ExFreePool(srb);
06869                 IoFreeIrp(irp);
06870             }
06871         } else {
06872             IoFreeIrp(irp);
06873         }
06874     }
06875 
06876     return STATUS_INSUFFICIENT_RESOURCES;
06877 }
06878 
06879 NTSTATUS
06880 NTAPI
06881 CdRomClassIoctlCompletion(
06882     IN PDEVICE_OBJECT DeviceObject,
06883     IN PIRP Irp,
06884     IN PVOID Context
06885     )
06886 
06887 /*++
06888 
06889 Routine Description:
06890 
06891     This routine signals the event used by CdRomDeviceControl to synchronize
06892     class driver (and lower level driver) ioctls with cdrom's startio routine.
06893     The irp completion is short-circuited so that CdRomDeviceControl can
06894     reissue it once it wakes up.
06895 
06896 Arguments:
06897 
06898     DeviceObject - the device object
06899     Irp - the request we are synchronizing
06900     Context - a PKEVENT that we need to signal
06901 
06902 Return Value:
06903 
06904     NTSTATUS
06905 
06906 --*/
06907 
06908 {
06909     PKEVENT syncEvent = (PKEVENT) Context;
06910 
06911     DebugPrint((2, "CdRomClassIoctlCompletion: setting event for irp %#08lx\n",
06912                 Irp
06913                 ));
06914 
06915     KeSetEvent(syncEvent, IO_DISK_INCREMENT, FALSE);
06916 
06917     return STATUS_MORE_PROCESSING_REQUIRED;
06918 }

Generated on Thu May 24 2012 04:28:45 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.