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

class2.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/class2/class2.c
00005  * PURPOSE:         SCSI Class driver routines
00006  * PROGRAMMERS:     Based on a source code sample from Microsoft NT4 DDK
00007  */
00008 
00009 #include <ntddk.h>
00010 #include <ntdddisk.h>
00011 #include <scsi.h>
00012 #include <include/class2.h>
00013 #include <stdio.h>
00014 
00015 /* Part of the drive letter hack */
00016 #include <ntifs.h>
00017 #include <ketypes.h>
00018 
00019 //#define NDEBUG
00020 #include <debug.h>
00021 
00022 #ifdef ALLOC_PRAGMA
00023 #pragma alloc_text(PAGE, ScsiClassGetInquiryData)
00024 #pragma alloc_text(PAGE, ScsiClassInitialize)
00025 #pragma alloc_text(PAGE, ScsiClassGetCapabilities)
00026 #pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous)
00027 #pragma alloc_text(PAGE, ScsiClassClaimDevice)
00028 #pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous)
00029 #endif
00030 
00031 
00032 #define INQUIRY_DATA_SIZE 2048
00033 #define START_UNIT_TIMEOUT  30
00034 
00035 /* Disk layout used by Windows NT4 and earlier versions. */
00036 //#define DEFAULT_SECTORS_PER_TRACK    32
00037 //#define DEFAULT_TRACKS_PER_CYLINDER  64
00038 
00039 /* Disk layout used by Windows 2000 and later versions. */
00040 #define DEFAULT_SECTORS_PER_TRACK    63
00041 #define DEFAULT_TRACKS_PER_CYLINDER 255
00042 
00043 NTSTATUS
00044 NTAPI
00045 ScsiClassCreateClose(
00046     IN PDEVICE_OBJECT DeviceObject,
00047     IN PIRP Irp
00048     );
00049 
00050 NTSTATUS
00051 NTAPI
00052 ScsiClassReadWrite(
00053     IN PDEVICE_OBJECT DeviceObject,
00054     IN PIRP Irp
00055     );
00056 
00057 NTSTATUS
00058 NTAPI
00059 ScsiClassDeviceControlDispatch(
00060     PDEVICE_OBJECT DeviceObject,
00061     PIRP Irp
00062     );
00063 
00064 NTSTATUS
00065 NTAPI
00066 ScsiClassDeviceControl(
00067     PDEVICE_OBJECT DeviceObject,
00068     PIRP Irp
00069     );
00070 
00071 NTSTATUS
00072 NTAPI
00073 ScsiClassInternalIoControl (
00074     IN PDEVICE_OBJECT DeviceObject,
00075     IN PIRP Irp
00076     );
00077 
00078 NTSTATUS
00079 NTAPI
00080 ScsiClassShutdownFlush(
00081     IN PDEVICE_OBJECT DeviceObject,
00082     IN PIRP Irp
00083     );
00084 
00085 NTSTATUS
00086 NTAPI
00087 DriverEntry(
00088     IN PDRIVER_OBJECT DriverObject,
00089     IN PUNICODE_STRING RegistryPath
00090     );
00091 
00092 //
00093 // Class internal routines
00094 //
00095 
00096 
00097 VOID
00098 NTAPI
00099 RetryRequest(
00100     PDEVICE_OBJECT DeviceObject,
00101     PIRP Irp,
00102     PSCSI_REQUEST_BLOCK Srb,
00103     BOOLEAN Associated
00104     );
00105 
00106 VOID
00107 NTAPI
00108 StartUnit(
00109     IN PDEVICE_OBJECT DeviceObject
00110     );
00111 
00112 NTSTATUS
00113 NTAPI
00114 ClassIoCompletion(
00115     IN PDEVICE_OBJECT DeviceObject,
00116     IN PIRP Irp,
00117     IN PVOID Context
00118     );
00119 
00120 NTSTATUS
00121 NTAPI
00122 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
00123                        IN PIRP Irp,
00124                        IN PVOID Context);
00125 
00126 
00127 NTSTATUS
00128 NTAPI
00129 DriverEntry(
00130     IN PDRIVER_OBJECT DriverObject,
00131     IN PUNICODE_STRING RegistryPath
00132     )
00133 {
00134     return STATUS_SUCCESS;
00135 }
00136 
00137 /* The following hack to assign drive letters with a non-PnP storage stack */
00138 
00139 typedef struct _CLASS_DEVICE_INFO {
00140   ULONG Partitions;
00141   ULONG DeviceNumber;
00142   ULONG DriveNumber;
00143   PDEVICE_OBJECT LowerDevice;
00144 } CLASS_DEVICE_INFO, *PCLASS_DEVICE_INFO;
00145 
00146 typedef struct _CLASS_DRIVER_EXTENSION {
00147   ULONG PortNumber;
00148   UNICODE_STRING RegistryPath;
00149   CLASS_INIT_DATA InitializationData;
00150 } CLASS_DRIVER_EXTENSION, *PCLASS_DRIVER_EXTENSION;
00151 
00152 VOID
00153 NTAPI
00154 ScsiClassRemoveDriveLetter(PCLASS_DEVICE_INFO DeviceInfo)
00155 {
00156     WCHAR Buffer1[100];
00157     UNICODE_STRING DriveLetterU;
00158     ULONG Index;
00159 
00160     DriveLetterU.Buffer = Buffer1;
00161     DriveLetterU.MaximumLength = sizeof(Buffer1);
00162 
00163     /* Delete the symbolic link to PhysicalDriveX */
00164     DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\PhysicalDrive%d", DeviceInfo->DriveNumber) * sizeof(WCHAR);
00165     IoDeleteSymbolicLink(&DriveLetterU);
00166 
00167     DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU);
00168 
00169     for (Index = 0; Index < sizeof(ULONG) * 8; Index++)
00170     {
00171         if (DeviceInfo->Partitions & (1 << Index))
00172         {
00173             DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\%C:", ('C' + Index)) * sizeof(WCHAR);
00174             IoDeleteSymbolicLink(&DriveLetterU);
00175             DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU);
00176         }
00177     }
00178 }
00179 
00180 NTSTATUS
00181 NTAPI
00182 ScsiClassAssignDriveLetter(PCLASS_DEVICE_INFO DeviceInfo)
00183 {
00184     WCHAR Buffer1[100];
00185     WCHAR Buffer2[100];
00186     UNICODE_STRING DriveLetterU, PartitionU;
00187     NTSTATUS Status;
00188     ULONG Index, PartitionNumber, DeviceNumber, DriveNumber;
00189     OBJECT_ATTRIBUTES ObjectAttributes;
00190     IO_STATUS_BLOCK Iosb;
00191     HANDLE PartitionHandle;
00192 
00193     /* We assume this device does not current have a drive letter */
00194 
00195     Index = 0;
00196     DeviceNumber = 0;
00197     DriveNumber = 0;
00198     PartitionNumber = 1;
00199     DriveLetterU.Buffer = Buffer1;
00200     DriveLetterU.MaximumLength = sizeof(Buffer1);
00201     PartitionU.Buffer = Buffer2;
00202     PartitionU.MaximumLength = sizeof(Buffer2);
00203 
00204     /* Determine the correct disk number */
00205     do
00206     {
00207         /* Check that the disk exists */
00208         PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\HardDisk%d\\Partition0", DeviceNumber) * sizeof(WCHAR);
00209         InitializeObjectAttributes(&ObjectAttributes,
00210                                    &PartitionU,
00211                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
00212                                    NULL,
00213                                    NULL);
00214         Status = ZwOpenFile(&PartitionHandle,
00215                             FILE_READ_ATTRIBUTES,
00216                             &ObjectAttributes,
00217                             &Iosb,
00218                             0,
00219                             0);
00220         if (!NT_SUCCESS(Status))
00221         {
00222             /* Return the last one that worked */
00223             DeviceNumber--;
00224         }
00225         else
00226         {
00227             ZwClose(PartitionHandle);
00228             DeviceNumber++;
00229         }
00230     } while (Status == STATUS_SUCCESS);
00231 
00232     /* Determine the correct drive number */
00233     do
00234     {
00235         /* Check that the drive exists */
00236         PartitionU.Length = swprintf(PartitionU.Buffer, L"\\??\\PhysicalDrive%d", DriveNumber) * sizeof(WCHAR);
00237         InitializeObjectAttributes(&ObjectAttributes,
00238                                    &PartitionU,
00239                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
00240                                    NULL,
00241                                    NULL);
00242         Status = ZwOpenFile(&PartitionHandle,
00243                             FILE_READ_ATTRIBUTES,
00244                             &ObjectAttributes,
00245                             &Iosb,
00246                             0,
00247                             0);
00248         if (NT_SUCCESS(Status))
00249         {
00250             ZwClose(PartitionHandle);
00251             DriveNumber++;
00252         }
00253     } while (Status == STATUS_SUCCESS);
00254 
00255     /* Create the symbolic link to PhysicalDriveX */
00256     PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\Harddisk%d\\Partition0", DeviceNumber) * sizeof(WCHAR);
00257     DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\PhysicalDrive%d", DriveNumber) * sizeof(WCHAR);
00258 
00259     Status = IoCreateSymbolicLink(&DriveLetterU, &PartitionU);
00260     if (!NT_SUCCESS(Status))
00261     {
00262         /* Failed to create symbolic link */
00263         return Status;
00264     }
00265 
00266     DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU, &DriveLetterU);
00267 
00268     while (TRUE)
00269     {
00270         /* Check that the disk exists */
00271         PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\Harddisk%d\\Partition%d", DeviceNumber, PartitionNumber) * sizeof(WCHAR);
00272         InitializeObjectAttributes(&ObjectAttributes,
00273                                    &PartitionU,
00274                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
00275                                    NULL,
00276                                    NULL);
00277         Status = ZwOpenFile(&PartitionHandle,
00278                             FILE_READ_ATTRIBUTES,
00279                             &ObjectAttributes,
00280                             &Iosb,
00281                             0,
00282                             0);
00283         if (!NT_SUCCESS(Status))
00284             break;
00285         else
00286         {
00287             ZwClose(PartitionHandle);
00288 
00289             /* Assign it a drive letter */
00290             do
00291             {
00292                 DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\%C:", ('C' + Index)) * sizeof(WCHAR);
00293 
00294                 Status = IoCreateSymbolicLink(&DriveLetterU, &PartitionU);
00295 
00296                 Index++;
00297             } while (Status != STATUS_SUCCESS);
00298 
00299             DeviceInfo->Partitions |= (1 << (Index - 1));
00300 
00301             DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU, &DriveLetterU);
00302             PartitionNumber++;
00303         }
00304     }
00305 
00306     DeviceInfo->DeviceNumber = DeviceNumber;
00307     DeviceInfo->DriveNumber = DriveNumber;
00308 
00309     return STATUS_SUCCESS;
00310 }
00311 
00312 NTSTATUS
00313 NTAPI
00314 ScsiClassPlugPlay(
00315     IN PDEVICE_OBJECT DeviceObject,
00316     IN PIRP Irp)
00317 {
00318     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
00319 
00320     if (IrpSp->MinorFunction == IRP_MN_START_DEVICE)
00321     {
00322         IoSkipCurrentIrpStackLocation(Irp);
00323         return STATUS_SUCCESS;
00324     }
00325     else if (IrpSp->MinorFunction == IRP_MN_REMOVE_DEVICE)
00326     {
00327         PCLASS_DEVICE_INFO DeviceInfo = DeviceObject->DeviceExtension;
00328 
00329         ScsiClassRemoveDriveLetter(DeviceInfo);
00330 
00331         Irp->IoStatus.Status = STATUS_SUCCESS;
00332         IoCompleteRequest(Irp, IO_NO_INCREMENT);
00333 
00334         IoDetachDevice(DeviceInfo->LowerDevice);
00335         IoDeleteDevice(DeviceObject);
00336         return STATUS_SUCCESS;
00337     }
00338     else
00339     {
00340         Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
00341         IoCompleteRequest(Irp, IO_NO_INCREMENT);
00342         return STATUS_NOT_SUPPORTED;
00343     }
00344 }
00345 
00346 NTSTATUS
00347 NTAPI
00348 ScsiClassAddDevice(
00349     IN PDRIVER_OBJECT DriverObject,
00350     IN PDEVICE_OBJECT PhysicalDeviceObject)
00351 {
00352     PCLASS_DRIVER_EXTENSION DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
00353     PCLASS_DEVICE_INFO DeviceInfo;
00354     PDEVICE_OBJECT DeviceObject;
00355     NTSTATUS Status;
00356 
00357     if (DriverExtension->InitializationData.ClassFindDevices(DriverObject, &DriverExtension->RegistryPath, &DriverExtension->InitializationData,
00358                                                              PhysicalDeviceObject, DriverExtension->PortNumber))
00359     {
00360         /* Create a device object */
00361         Status = IoCreateDevice(DriverObject,
00362                                 sizeof(CLASS_DEVICE_INFO),
00363                                 NULL,
00364                                 FILE_DEVICE_DISK,
00365                                 0,
00366                                 FALSE,
00367                                 &DeviceObject);
00368         if (!NT_SUCCESS(Status))
00369         {
00370             return Status;
00371         }
00372 
00373         DeviceInfo = DeviceObject->DeviceExtension;
00374         RtlZeroMemory(DeviceInfo, sizeof(CLASS_DEVICE_INFO));
00375 
00376         /* Attach it to the PDO */
00377         DeviceInfo->LowerDevice = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
00378 
00379         /* Check that the kernel has already assigned drive letters */
00380         if (KeLoaderBlock == NULL)
00381         {
00382             /* Assign a drive letter */
00383             ScsiClassAssignDriveLetter(DeviceInfo);
00384         }
00385         else
00386         {
00387             /* The kernel will handle it */
00388         }
00389 
00390         /* Move to the next port number */
00391         DriverExtension->PortNumber++;
00392     }
00393     else
00394     {
00395         /* Failed to find device */
00396         DbgPrint("FAILED TO FIND DEVICE!\n");
00397     }
00398 
00399     return STATUS_SUCCESS;
00400 }
00401 /* ---- End hack ---- */
00402 
00403 
00404 
00405 ULONG
00406 NTAPI
00407 ScsiClassInitialize(
00408     IN  PVOID            Argument1,
00409     IN  PVOID            Argument2,
00410     IN  PCLASS_INIT_DATA InitializationData
00411     )
00412 
00413 /*++
00414 
00415 Routine Description:
00416 
00417     This routine is called by a class driver during its
00418     DriverEntry routine to initialize the driver.
00419 
00420 Arguments:
00421 
00422     Argument1          - Driver Object.
00423     Argument2          - Registry Path.
00424     InitializationData - Device-specific driver's initialization data.
00425 
00426 Return Value:
00427 
00428     A valid return code for a DriverEntry routine.
00429 
00430 --*/
00431 
00432 {
00433 
00434 
00435     PDRIVER_OBJECT  DriverObject = Argument1;
00436     PDEVICE_OBJECT  portDeviceObject;
00437     NTSTATUS        status;
00438     STRING          deviceNameString;
00439     UNICODE_STRING  unicodeDeviceName;
00440     PFILE_OBJECT    fileObject;
00441     CCHAR           deviceNameBuffer[256];
00442     BOOLEAN         deviceFound = FALSE;
00443     PCLASS_DRIVER_EXTENSION DriverExtension;
00444     PUNICODE_STRING RegistryPath = Argument2;
00445 
00446     DebugPrint((3,"\n\nSCSI Class Driver\n"));
00447 
00448     //
00449     // Validate the length of this structure. This is effectively a
00450     // version check.
00451     //
00452 
00453     if (InitializationData->InitializationDataSize > sizeof(CLASS_INIT_DATA)) {
00454 
00455         DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n"));
00456         return (ULONG) STATUS_REVISION_MISMATCH;
00457     }
00458 
00459     //
00460     // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
00461     // are not required entry points.
00462     //
00463 
00464     if ((!InitializationData->ClassFindDevices) ||
00465         (!InitializationData->ClassDeviceControl) ||
00466         (!((InitializationData->ClassReadWriteVerification) ||
00467            (InitializationData->ClassStartIo)))) {
00468 
00469         DebugPrint((0,
00470             "ScsiClassInitialize: Class device-specific driver missing required entry\n"));
00471 
00472         return (ULONG) STATUS_REVISION_MISMATCH;
00473     }
00474 
00475     status = IoAllocateDriverObjectExtension(DriverObject,
00476                                              DriverObject,
00477                                              sizeof(CLASS_DRIVER_EXTENSION),
00478                                              (PVOID *)&DriverExtension);
00479     if (!NT_SUCCESS(status))
00480         return status;
00481 
00482     RtlCopyMemory(&DriverExtension->InitializationData, InitializationData, sizeof(CLASS_INIT_DATA));
00483     DriverExtension->PortNumber = 0;
00484 
00485     DriverExtension->RegistryPath.Buffer = ExAllocatePool(PagedPool, RegistryPath->MaximumLength);
00486     if (!DriverExtension->RegistryPath.Buffer)
00487         return STATUS_NO_MEMORY;
00488 
00489     DriverExtension->RegistryPath.Length = RegistryPath->Length;
00490     DriverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
00491 
00492     RtlCopyMemory(DriverExtension->RegistryPath.Buffer,
00493                   RegistryPath->Buffer,
00494                   RegistryPath->Length);
00495 
00496     //
00497     // Update driver object with entry points.
00498     //
00499 
00500     DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiClassCreateClose;
00501     DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiClassCreateClose;
00502     DriverObject->MajorFunction[IRP_MJ_READ] = ScsiClassReadWrite;
00503     DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiClassReadWrite;
00504     DriverObject->MajorFunction[IRP_MJ_PNP] = ScsiClassPlugPlay;
00505     DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassInternalIoControl;
00506     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiClassDeviceControlDispatch;
00507     DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ScsiClassShutdownFlush;
00508     DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ScsiClassShutdownFlush;
00509     DriverObject->DriverExtension->AddDevice = ScsiClassAddDevice;
00510 
00511     if (InitializationData->ClassStartIo) {
00512         DriverObject->DriverStartIo = InitializationData->ClassStartIo;
00513     }
00514 
00515     //
00516     // Open port driver controller device objects by name.
00517     //
00518 
00519     do {
00520 
00521         sprintf(deviceNameBuffer, "\\Device\\ScsiPort%lu", DriverExtension->PortNumber);
00522 
00523         DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer));
00524 
00525         RtlInitString(&deviceNameString, deviceNameBuffer);
00526 
00527         status = RtlAnsiStringToUnicodeString(&unicodeDeviceName,
00528                                               &deviceNameString,
00529                                               TRUE);
00530 
00531         if (!NT_SUCCESS(status)){
00532             break;
00533         }
00534 
00535         status = IoGetDeviceObjectPointer(&unicodeDeviceName,
00536                                            FILE_READ_ATTRIBUTES,
00537                                            &fileObject,
00538                                            &portDeviceObject);
00539 
00540         if (NT_SUCCESS(status)) {
00541 
00542             //
00543             // Call the device-specific driver's FindDevice routine.
00544             //
00545 
00546             if (InitializationData->ClassFindDevices(DriverObject, Argument2, InitializationData,
00547                                                      portDeviceObject, DriverExtension->PortNumber)) {
00548 
00549                 deviceFound = TRUE;
00550             }
00551         }
00552 
00553         //
00554         // Check next SCSI adapter.
00555         //
00556 
00557         DriverExtension->PortNumber++;
00558 
00559     } while(NT_SUCCESS(status));
00560 
00561     /* We don't want to fail init just because we don't have devices right now */
00562     return STATUS_SUCCESS; /*deviceFound ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE;*/
00563 }
00564 
00565 
00566 NTSTATUS
00567 NTAPI
00568 ScsiClassCreateClose(
00569     IN PDEVICE_OBJECT DeviceObject,
00570     IN PIRP Irp
00571     )
00572 
00573 /*++
00574 
00575 Routine Description:
00576 
00577     SCSI class driver create and close routine.  This is called by the I/O system
00578     when the device is opened or closed.
00579 
00580 Arguments:
00581 
00582     DriverObject - Pointer to driver object created by system.
00583 
00584     Irp - IRP involved.
00585 
00586 Return Value:
00587 
00588     Device-specific drivers return value or STATUS_SUCCESS.
00589 
00590 --*/
00591 
00592 {
00593     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
00594 
00595     //
00596     // Invoke the device-specific routine, if one exists. Otherwise complete
00597     // with SUCCESS
00598     //
00599 
00600     if (deviceExtension->ClassCreateClose) {
00601 
00602         return deviceExtension->ClassCreateClose(DeviceObject, Irp);
00603 
00604     } else {
00605         Irp->IoStatus.Status = STATUS_SUCCESS;
00606 
00607         IoCompleteRequest(Irp, IO_NO_INCREMENT);
00608         return(STATUS_SUCCESS);
00609     }
00610 }
00611 
00612 
00613 
00614 NTSTATUS
00615 NTAPI
00616 ScsiClassReadWrite(
00617     IN PDEVICE_OBJECT DeviceObject,
00618     IN PIRP Irp
00619     )
00620 
00621 /*++
00622 
00623 Routine Description:
00624 
00625     This is the system entry point for read and write requests. The device-specific handler is invoked
00626     to perform any validation necessary. The number of bytes in the request are
00627     checked against the maximum byte counts that the adapter supports and requests are broken up into
00628     smaller sizes if necessary.
00629 
00630 Arguments:
00631 
00632     DeviceObject
00633     Irp - IO request
00634 
00635 Return Value:
00636 
00637     NT Status
00638 
00639 --*/
00640 
00641 {
00642     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
00643     PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
00644     ULONG               transferPages;
00645     ULONG               transferByteCount = currentIrpStack->Parameters.Read.Length;
00646     ULONG               maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
00647     NTSTATUS            status;
00648 
00649     if (DeviceObject->Flags & DO_VERIFY_VOLUME &&
00650         !(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
00651 
00652         //
00653         // if DO_VERIFY_VOLUME bit is set
00654         // in device object flags, fail request.
00655         //
00656 
00657         IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
00658 
00659         Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
00660         Irp->IoStatus.Information = 0;
00661 
00662         IoCompleteRequest(Irp, 0);
00663         return STATUS_VERIFY_REQUIRED;
00664     }
00665 
00666     //
00667     // Invoke the device specific routine to do whatever it needs to verify
00668     // this request.
00669     //
00670 
00671     ASSERT(deviceExtension->ClassReadWriteVerification);
00672 
00673     status = deviceExtension->ClassReadWriteVerification(DeviceObject,Irp);
00674 
00675     if (!NT_SUCCESS(status)) {
00676 
00677         //
00678         // It is up to the device specific driver to set the Irp status.
00679         //
00680 
00681         IoCompleteRequest (Irp, IO_NO_INCREMENT);
00682         return status;
00683     } else if (status == STATUS_PENDING) {
00684 
00685         IoMarkIrpPending(Irp);
00686         return STATUS_PENDING;
00687     }
00688 
00689     //
00690     // Check for a zero length IO, as several macros will turn this into
00691     // seemingly a 0xffffffff length request.
00692     //
00693 
00694     if (transferByteCount == 0) {
00695         Irp->IoStatus.Status = STATUS_SUCCESS;
00696         Irp->IoStatus.Information = 0;
00697         IoCompleteRequest(Irp, IO_NO_INCREMENT);
00698         return STATUS_SUCCESS;
00699 
00700     }
00701 
00702     if (deviceExtension->ClassStartIo) {
00703 
00704         IoMarkIrpPending(Irp);
00705 
00706         IoStartPacket(DeviceObject,
00707                       Irp,
00708                       NULL,
00709                       NULL);
00710 
00711         return STATUS_PENDING;
00712     }
00713 
00714     //
00715     // Mark IRP with status pending.
00716     //
00717 
00718     IoMarkIrpPending(Irp);
00719 
00720     //
00721     // Add partition byte offset to make starting byte relative to
00722     // beginning of disk. In addition, add in skew for DM Driver, if any.
00723     //
00724 
00725     currentIrpStack->Parameters.Read.ByteOffset.QuadPart += (deviceExtension->StartingOffset.QuadPart +
00726                                                              deviceExtension->DMByteSkew);
00727 
00728     //
00729     // Calculate number of pages in this transfer.
00730     //
00731 
00732     transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
00733                                                    currentIrpStack->Parameters.Read.Length);
00734 
00735     //
00736     // Check if request length is greater than the maximum number of
00737     // bytes that the hardware can transfer.
00738     //
00739 
00740     if (currentIrpStack->Parameters.Read.Length > maximumTransferLength ||
00741         transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
00742 
00743          DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n"));
00744          DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n",
00745                      maximumTransferLength));
00746          DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n",
00747                      currentIrpStack->Parameters.Read.Length));
00748 
00749          transferPages =
00750             deviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
00751 
00752          if (maximumTransferLength > transferPages << PAGE_SHIFT ) {
00753              maximumTransferLength = transferPages << PAGE_SHIFT;
00754          }
00755 
00756         //
00757         // Check that maximum transfer size is not zero.
00758         //
00759 
00760         if (maximumTransferLength == 0) {
00761             maximumTransferLength = PAGE_SIZE;
00762         }
00763 
00764         //
00765         // Mark IRP with status pending.
00766         //
00767 
00768         IoMarkIrpPending(Irp);
00769 
00770         //
00771         // Request greater than port driver maximum.
00772         // Break up into smaller routines.
00773         //
00774 
00775         ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength);
00776 
00777 
00778         return STATUS_PENDING;
00779     }
00780 
00781     //
00782     // Build SRB and CDB for this IRP.
00783     //
00784 
00785     ScsiClassBuildRequest(DeviceObject, Irp);
00786 
00787     //
00788     // Return the results of the call to the port driver.
00789     //
00790 
00791     return IoCallDriver(deviceExtension->PortDeviceObject, Irp);
00792 
00793 } // end ScsiClassReadWrite()
00794 
00795 
00796 NTSTATUS
00797 NTAPI
00798 ScsiClassGetCapabilities(
00799     IN PDEVICE_OBJECT PortDeviceObject,
00800     OUT PIO_SCSI_CAPABILITIES *PortCapabilities
00801     )
00802 
00803 /*++
00804 
00805 Routine Description:
00806 
00807     This routine builds and sends a request to the port driver to
00808     get a pointer to a structure that describes the adapter's
00809     capabilities/limitations. This routine is sychronous.
00810 
00811 Arguments:
00812 
00813     PortDeviceObject - Port driver device object representing the HBA.
00814 
00815     PortCapabilities - Location to store pointer to capabilities structure.
00816 
00817 Return Value:
00818 
00819     Nt status indicating the results of the operation.
00820 
00821 Notes:
00822 
00823     This routine should only be called at initialization time.
00824 
00825 --*/
00826 
00827 {
00828     PIRP            irp;
00829     IO_STATUS_BLOCK ioStatus;
00830     KEVENT          event;
00831     NTSTATUS        status;
00832 
00833     PAGED_CODE();
00834 
00835     //
00836     // Create notification event object to be used to signal the
00837     // request completion.
00838     //
00839 
00840     KeInitializeEvent(&event, NotificationEvent, FALSE);
00841 
00842     //
00843     // Build the synchronous request  to be sent to the port driver
00844     // to perform the request.
00845     //
00846 
00847     irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES,
00848                                         PortDeviceObject,
00849                                         NULL,
00850                                         0,
00851                                         PortCapabilities,
00852                                         sizeof(PVOID),
00853                                         FALSE,
00854                                         &event,
00855                                         &ioStatus);
00856 
00857     if (irp == NULL) {
00858         return STATUS_INSUFFICIENT_RESOURCES;
00859     }
00860 
00861     //
00862     // Pass request to port driver and wait for request to complete.
00863     //
00864 
00865     status = IoCallDriver(PortDeviceObject, irp);
00866 
00867     if (status == STATUS_PENDING) {
00868         KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
00869         return(ioStatus.Status);
00870     }
00871 
00872     return status;
00873 
00874 } // end ScsiClassGetCapabilities()
00875 
00876 
00877 NTSTATUS
00878 NTAPI
00879 ScsiClassGetInquiryData(
00880     IN PDEVICE_OBJECT PortDeviceObject,
00881     OUT PSCSI_ADAPTER_BUS_INFO *ConfigInfo
00882     )
00883 
00884 /*++
00885 
00886 Routine Description:
00887 
00888     This routine sends a request to a port driver to return
00889     configuration information. Space for the information is
00890     allocated by this routine. The caller is responsible for
00891     freeing the configuration information. This routine is
00892     synchronous.
00893 
00894 Arguments:
00895 
00896     PortDeviceObject - Port driver device object representing the HBA.
00897 
00898     ConfigInfo - Returns a pointer to the configuration information.
00899 
00900 Return Value:
00901 
00902     Nt status indicating the results of the operation.
00903 
00904 Notes:
00905 
00906     This routine should be called only at initialization time.
00907 
00908 --*/
00909 
00910 {
00911     PIRP                   irp;
00912     IO_STATUS_BLOCK        ioStatus;
00913     KEVENT                 event;
00914     NTSTATUS               status;
00915     PSCSI_ADAPTER_BUS_INFO buffer;
00916 
00917     PAGED_CODE();
00918 
00919     buffer = ExAllocatePool(PagedPool, INQUIRY_DATA_SIZE);
00920     *ConfigInfo = buffer;
00921 
00922     if (buffer == NULL) {
00923         return(STATUS_INSUFFICIENT_RESOURCES);
00924     }
00925 
00926     //
00927     // Create notification event object to be used to signal the inquiry
00928     // request completion.
00929     //
00930 
00931     KeInitializeEvent(&event, NotificationEvent, FALSE);
00932 
00933     //
00934     // Build the synchronous request to be sent to the port driver
00935     // to perform the inquiries.
00936     //
00937 
00938     irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
00939                                         PortDeviceObject,
00940                                         NULL,
00941                                         0,
00942                                         buffer,
00943                                         INQUIRY_DATA_SIZE,
00944                                         FALSE,
00945                                         &event,
00946                                         &ioStatus);
00947 
00948     if (irp == NULL) {
00949         return(STATUS_INSUFFICIENT_RESOURCES);
00950     }
00951 
00952     //
00953     // Pass request to port driver and wait for request to complete.
00954     //
00955 
00956     status = IoCallDriver(PortDeviceObject, irp);
00957 
00958     if (status == STATUS_PENDING) {
00959         KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
00960         status = ioStatus.Status;
00961     }
00962 
00963     if (!NT_SUCCESS(status)) {
00964 
00965         //
00966         // Free the buffer on an error.
00967         //
00968 
00969         ExFreePool(buffer);
00970         *ConfigInfo = NULL;
00971 
00972     }
00973 
00974     return status;
00975 
00976 } // end ScsiClassGetInquiryData()
00977 
00978 
00979 NTSTATUS
00980 NTAPI
00981 ScsiClassReadDriveCapacity(
00982     IN PDEVICE_OBJECT DeviceObject
00983     )
00984 
00985 /*++
00986 
00987 Routine Description:
00988 
00989     This routine sends a READ CAPACITY to the requested device, updates
00990     the geometry information in the device object and returns
00991     when it is complete.  This routine is synchronous.
00992 
00993 Arguments:
00994 
00995     DeviceObject - Supplies a pointer to the device object that represents
00996         the device whose capacity is to be read.
00997 
00998 Return Value:
00999 
01000     Status is returned.
01001 
01002 --*/
01003 {
01004     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
01005     ULONG               retries = 1;
01006     ULONG               lastSector;
01007     PCDB                cdb;
01008     PREAD_CAPACITY_DATA readCapacityBuffer;
01009     SCSI_REQUEST_BLOCK  srb;
01010     NTSTATUS            status;
01011 
01012     //
01013     // Allocate read capacity buffer from nonpaged pool.
01014     //
01015 
01016     readCapacityBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
01017                                         sizeof(READ_CAPACITY_DATA));
01018 
01019     if (!readCapacityBuffer) {
01020         return(STATUS_INSUFFICIENT_RESOURCES);
01021     }
01022 
01023     RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
01024 
01025     //
01026     // Build the read capacity CDB.
01027     //
01028 
01029     srb.CdbLength = 10;
01030     cdb = (PCDB)srb.Cdb;
01031 
01032     //
01033     // Set timeout value from device extension.
01034     //
01035 
01036     srb.TimeOutValue = deviceExtension->TimeOutValue;
01037 
01038     cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
01039 
01040 Retry:
01041 
01042     status = ScsiClassSendSrbSynchronous(DeviceObject,
01043                                 &srb,
01044                                 readCapacityBuffer,
01045                                 sizeof(READ_CAPACITY_DATA),
01046                                 FALSE);
01047 
01048     if (NT_SUCCESS(status)) {
01049 
01050         //
01051         // Copy sector size from read capacity buffer to device extension
01052         // in reverse byte order.
01053         //
01054 
01055         ((PFOUR_BYTE)&deviceExtension->DiskGeometry->Geometry.BytesPerSector)->Byte0 =
01056             ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte3;
01057 
01058         ((PFOUR_BYTE)&deviceExtension->DiskGeometry->Geometry.BytesPerSector)->Byte1 =
01059             ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte2;
01060 
01061         ((PFOUR_BYTE)&deviceExtension->DiskGeometry->Geometry.BytesPerSector)->Byte2 =
01062             ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte1;
01063 
01064         ((PFOUR_BYTE)&deviceExtension->DiskGeometry->Geometry.BytesPerSector)->Byte3 =
01065             ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte0;
01066 
01067         //
01068         // Copy last sector in reverse byte order.
01069         //
01070 
01071         ((PFOUR_BYTE)&lastSector)->Byte0 =
01072             ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte3;
01073 
01074         ((PFOUR_BYTE)&lastSector)->Byte1 =
01075             ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte2;
01076 
01077         ((PFOUR_BYTE)&lastSector)->Byte2 =
01078             ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte1;
01079 
01080         ((PFOUR_BYTE)&lastSector)->Byte3 =
01081             ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte0;
01082 
01083         //
01084         // Calculate sector to byte shift.
01085         //
01086 
01087         WHICH_BIT(deviceExtension->DiskGeometry->Geometry.BytesPerSector, deviceExtension->SectorShift);
01088 
01089         DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
01090             deviceExtension->DiskGeometry->Geometry.BytesPerSector));
01091 
01092         DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
01093             lastSector + 1));
01094 
01095         //
01096         // Calculate media capacity in bytes.
01097         //
01098 
01099         deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
01100 
01101         //
01102         // Calculate number of cylinders.
01103         //
01104 
01105         deviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(DEFAULT_SECTORS_PER_TRACK * DEFAULT_TRACKS_PER_CYLINDER));
01106 
01107         deviceExtension->PartitionLength.QuadPart =
01108             (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
01109 
01110         if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
01111 
01112             //
01113             // This device supports removable media.
01114             //
01115 
01116             deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia;
01117 
01118         } else {
01119 
01120             //
01121             // Assume media type is fixed disk.
01122             //
01123 
01124             deviceExtension->DiskGeometry->Geometry.MediaType = FixedMedia;
01125         }
01126 
01127         //
01128         // Assume sectors per track are DEFAULT_SECTORS_PER_TRACK;
01129         //
01130 
01131         deviceExtension->DiskGeometry->Geometry.SectorsPerTrack = DEFAULT_SECTORS_PER_TRACK;
01132 
01133         //
01134         // Assume tracks per cylinder (number of heads) is DEFAULT_TRACKS_PER_CYLINDER.
01135         //
01136 
01137         deviceExtension->DiskGeometry->Geometry.TracksPerCylinder = DEFAULT_TRACKS_PER_CYLINDER;
01138     }
01139 
01140     if (status == STATUS_VERIFY_REQUIRED) {
01141 
01142         //
01143         // Routine ScsiClassSendSrbSynchronous does not retry
01144         // requests returned with this status.
01145         // Read Capacities should be retried
01146         // anyway.
01147         //
01148 
01149         if (retries--) {
01150 
01151             //
01152             // Retry request.
01153             //
01154 
01155             goto Retry;
01156         }
01157     }
01158 
01159     if (!NT_SUCCESS(status)) {
01160 
01161         //
01162         // If the read capacity fails, set the geometry to reasonable parameter
01163         // so things don't fail at unexpected places.  Zero the geometry
01164         // except for the bytes per sector and sector shift.
01165         //
01166 
01167         RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY_EX));
01168         deviceExtension->DiskGeometry->Geometry.BytesPerSector = 512;
01169         deviceExtension->SectorShift = 9;
01170         deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0;
01171 
01172         if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
01173 
01174             //
01175             // This device supports removable media.
01176             //
01177 
01178             deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia;
01179 
01180         } else {
01181 
01182             //
01183             // Assume media type is fixed disk.
01184             //
01185 
01186             deviceExtension->DiskGeometry->Geometry.MediaType = FixedMedia;
01187         }
01188     }
01189 
01190     //
01191     // Deallocate read capacity buffer.
01192     //
01193 
01194     ExFreePool(readCapacityBuffer);
01195 
01196     return status;
01197 
01198 } // end ScsiClassReadDriveCapacity()
01199 
01200 
01201 VOID
01202 NTAPI
01203 ScsiClassReleaseQueue(
01204     IN PDEVICE_OBJECT DeviceObject
01205     )
01206 
01207 /*++
01208 
01209 Routine Description:
01210 
01211     This routine issues an internal device control command
01212     to the port driver to release a frozen queue. The call
01213     is issued asynchronously as ScsiClassReleaseQueue will be invoked
01214     from the IO completion DPC (and will have no context to
01215     wait for a synchronous call to complete).
01216 
01217 Arguments:
01218 
01219     DeviceObject - The device object for the logical unit with
01220         the frozen queue.
01221 
01222 Return Value:
01223 
01224     None.
01225 
01226 --*/
01227 {
01228     PIO_STACK_LOCATION irpStack;
01229     PIRP irp;
01230     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
01231     PCOMPLETION_CONTEXT context;
01232     PSCSI_REQUEST_BLOCK srb;
01233     KIRQL currentIrql;
01234 
01235     //
01236     // Allocate context from nonpaged pool.
01237     //
01238 
01239     context = ExAllocatePool(NonPagedPoolMustSucceed,
01240                              sizeof(COMPLETION_CONTEXT));
01241 
01242     //
01243     // Save the device object in the context for use by the completion
01244     // routine.
01245     //
01246 
01247     context->DeviceObject = DeviceObject;
01248     srb = &context->Srb;
01249 
01250     //
01251     // Zero out srb.
01252     //
01253 
01254     RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
01255 
01256     //
01257     // Write length to SRB.
01258     //
01259 
01260     srb->Length = SCSI_REQUEST_BLOCK_SIZE;
01261 
01262     //
01263     // Set up SCSI bus address.
01264     //
01265 
01266     srb->PathId = deviceExtension->PathId;
01267     srb->TargetId = deviceExtension->TargetId;
01268     srb->Lun = deviceExtension->Lun;
01269 
01270     //
01271     // If this device is removable then flush the queue.  This will also
01272     // release it.
01273     //
01274 
01275     if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
01276 
01277        srb->Function = SRB_FUNCTION_FLUSH_QUEUE;
01278 
01279     } else {
01280 
01281        srb->Function = SRB_FUNCTION_RELEASE_QUEUE;
01282 
01283     }
01284 
01285     //
01286     // Build the asynchronous request to be sent to the port driver.
01287     //
01288 
01289     irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
01290 
01291     if(irp == NULL) {
01292 
01293         //
01294         // We have no better way of dealing with this at the moment
01295         //
01296 
01297         KeBugCheck((ULONG)0x0000002DL);
01298 
01299     }
01300 
01301     IoSetCompletionRoutine(irp,
01302                            (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
01303                            context,
01304                            TRUE,
01305                            TRUE,
01306                            TRUE);
01307 
01308     irpStack = IoGetNextIrpStackLocation(irp);
01309 
01310     irpStack->MajorFunction = IRP_MJ_SCSI;
01311 
01312     srb->OriginalRequest = irp;
01313 
01314     //
01315     // Store the SRB address in next stack for port driver.
01316     //
01317 
01318     irpStack->Parameters.Scsi.Srb = srb;
01319 
01320     //
01321     // Since this routine can cause outstanding requests to be completed, and
01322     // calling a completion routine at < DISPATCH_LEVEL is dangerous (if they
01323     // call IoStartNextPacket we will bugcheck) raise up to dispatch level before
01324     // issuing the request
01325     //
01326 
01327     currentIrql = KeGetCurrentIrql();
01328 
01329     if(currentIrql < DISPATCH_LEVEL) {
01330         KeRaiseIrql(DISPATCH_LEVEL, &currentIrql);
01331         IoCallDriver(deviceExtension->PortDeviceObject, irp);
01332         KeLowerIrql(currentIrql);
01333     } else {
01334         IoCallDriver(deviceExtension->PortDeviceObject, irp);
01335     }
01336 
01337     return;
01338 
01339 } // end ScsiClassReleaseQueue()
01340 
01341 
01342 VOID
01343 NTAPI
01344 StartUnit(
01345     IN PDEVICE_OBJECT DeviceObject
01346     )
01347 
01348 /*++
01349 
01350 Routine Description:
01351 
01352     Send command to SCSI unit to start or power up.
01353     Because this command is issued asynchronounsly, that is, without
01354     waiting on it to complete, the IMMEDIATE flag is not set. This
01355     means that the CDB will not return until the drive has powered up.
01356     This should keep subsequent requests from being submitted to the
01357     device before it has completely spun up.
01358     This routine is called from the InterpretSense routine, when a
01359     request sense returns data indicating that a drive must be
01360     powered up.
01361 
01362 Arguments:
01363 
01364     DeviceObject - The device object for the logical unit with
01365         the frozen queue.
01366 
01367 Return Value:
01368 
01369     None.
01370 
01371 --*/
01372 {
01373     PIO_STACK_LOCATION irpStack;
01374     PIRP irp;
01375     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
01376     PSCSI_REQUEST_BLOCK srb;
01377     PCOMPLETION_CONTEXT context;
01378     PCDB cdb;
01379 
01380     //
01381     // Allocate Srb from nonpaged pool.
01382     //
01383 
01384     context = ExAllocatePool(NonPagedPoolMustSucceed,
01385                              sizeof(COMPLETION_CONTEXT));
01386 
01387     //
01388     // Save the device object in the context for use by the completion
01389     // routine.
01390     //
01391 
01392     context->DeviceObject = DeviceObject;
01393     srb = &context->Srb;
01394 
01395     //
01396     // Zero out srb.
01397     //
01398 
01399     RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
01400 
01401     //
01402     // Write length to SRB.
01403     //
01404 
01405     srb->Length = SCSI_REQUEST_BLOCK_SIZE;
01406 
01407     //
01408     // Set up SCSI bus address.
01409     //
01410 
01411     srb->PathId = deviceExtension->PathId;
01412     srb->TargetId = deviceExtension->TargetId;
01413     srb->Lun = deviceExtension->Lun;
01414 
01415     srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
01416 
01417     //
01418     // Set timeout value large enough for drive to spin up.
01419     //
01420 
01421     srb->TimeOutValue = START_UNIT_TIMEOUT;
01422 
01423     //
01424     // Set the transfer length.
01425     //
01426 
01427     srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
01428 
01429     //
01430     // Build the start unit CDB.
01431     //
01432 
01433     srb->CdbLength = 6;
01434     cdb = (PCDB)srb->Cdb;
01435 
01436     cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
01437     cdb->START_STOP.Start = 1;
01438     cdb->START_STOP.LogicalUnitNumber = srb->Lun;
01439 
01440     //
01441     // Build the asynchronous request to be sent to the port driver.
01442     // Since this routine is called from a DPC the IRP should always be
01443     // available.
01444     //
01445 
01446     irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
01447     IoSetCompletionRoutine(irp,
01448                            (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
01449                            context,
01450                            TRUE,
01451                            TRUE,
01452                            TRUE);
01453 
01454     irpStack = IoGetNextIrpStackLocation(irp);
01455     irpStack->MajorFunction = IRP_MJ_SCSI;
01456     srb->OriginalRequest = irp;
01457 
01458     //
01459     // Store the SRB address in next stack for port driver.
01460     //
01461 
01462     irpStack->Parameters.Scsi.Srb = srb;
01463 
01464     //
01465     // Call the port driver with the IRP.
01466     //
01467 
01468     IoCallDriver(deviceExtension->PortDeviceObject, irp);
01469 
01470     return;
01471 
01472 } // end StartUnit()
01473 
01474 
01475 NTSTATUS
01476 NTAPI
01477 ScsiClassAsynchronousCompletion(
01478     PDEVICE_OBJECT DeviceObject,
01479     PIRP Irp,
01480     PVOID Context
01481     )
01482 /*++
01483 
01484 Routine Description:
01485 
01486     This routine is called when an asynchronous I/O request
01487     which was issused by the class driver completes.  Examples of such requests
01488     are release queue or START UNIT. This routine releases the queue if
01489     necessary.  It then frees the context and the IRP.
01490 
01491 Arguments:
01492 
01493     DeviceObject - The device object for the logical unit; however since this
01494         is the top stack location the value is NULL.
01495 
01496     Irp - Supplies a pointer to the Irp to be processed.
01497 
01498     Context - Supplies the context to be used to process this request.
01499 
01500 Return Value:
01501 
01502     None.
01503 
01504 --*/
01505 
01506 {
01507     PCOMPLETION_CONTEXT context = Context;
01508     PSCSI_REQUEST_BLOCK srb;
01509 
01510     srb = &context->Srb;
01511 
01512     //
01513     // If this is an execute srb, then check the return status and make sure.
01514     // the queue is not frozen.
01515     //
01516 
01517     if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
01518 
01519         //
01520         // Check for a frozen queue.
01521         //
01522 
01523         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
01524 
01525             //
01526             // Unfreeze the queue getting the device object from the context.
01527             //
01528 
01529             ScsiClassReleaseQueue(context->DeviceObject);
01530         }
01531     }
01532 
01533     //
01534     // Free the context and the Irp.
01535     //
01536 
01537     if (Irp->MdlAddress != NULL) {
01538         MmUnlockPages(Irp->MdlAddress);
01539         IoFreeMdl(Irp->MdlAddress);
01540 
01541         Irp->MdlAddress = NULL;
01542     }
01543 
01544     ExFreePool(context);
01545     IoFreeIrp(Irp);
01546 
01547     //
01548     // Indicate the I/O system should stop processing the Irp completion.
01549     //
01550 
01551     return STATUS_MORE_PROCESSING_REQUIRED;
01552 
01553 } // ScsiClassAsynchronousCompletion()
01554 
01555 
01556 VOID
01557 NTAPI
01558 ScsiClassSplitRequest(
01559     IN PDEVICE_OBJECT DeviceObject,
01560     IN PIRP Irp,
01561     IN ULONG MaximumBytes
01562     )
01563 
01564 /*++
01565 
01566 Routine Description:
01567 
01568     Break request into smaller requests.  Each new request will be the
01569     maximum transfer size that the port driver can handle or if it
01570     is the final request, it may be the residual size.
01571 
01572     The number of IRPs required to process this request is written in the
01573     current stack of the original IRP. Then as each new IRP completes
01574     the count in the original IRP is decremented. When the count goes to
01575     zero, the original IRP is completed.
01576 
01577 Arguments:
01578 
01579     DeviceObject - Pointer to the class device object to be addressed.
01580 
01581     Irp - Pointer to Irp the orginal request.
01582 
01583 Return Value:
01584 
01585     None.
01586 
01587 --*/
01588 
01589 {
01590     PDEVICE_EXTENSION  deviceExtension = DeviceObject->DeviceExtension;
01591     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
01592     PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
01593     ULONG              transferByteCount = currentIrpStack->Parameters.Read.Length;
01594     LARGE_INTEGER      startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
01595     PVOID              dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
01596     ULONG              dataLength = MaximumBytes;
01597     ULONG              irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes;
01598     ULONG              i;
01599     PSCSI_REQUEST_BLOCK srb;
01600 
01601     DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount));
01602     DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp));
01603 
01604     //
01605     // If all partial transfers complete successfully then the status and
01606     // bytes transferred are already set up. Failing a partial-transfer IRP
01607     // will set status to error and bytes transferred to 0 during
01608     // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
01609     // asynchronous partial transfers. This is an optimization for the
01610     // successful case.
01611     //
01612 
01613     Irp->IoStatus.Status = STATUS_SUCCESS;
01614     Irp->IoStatus.Information = transferByteCount;
01615 
01616     //
01617     // Save number of IRPs to complete count on current stack
01618     // of original IRP.
01619     //
01620 
01621     nextIrpStack->Parameters.Others.Argument1 = (PVOID)(ULONG_PTR) irpCount;
01622 
01623     for (i = 0; i < irpCount; i++) {
01624 
01625         PIRP newIrp;
01626         PIO_STACK_LOCATION newIrpStack;
01627 
01628         //
01629         // Allocate new IRP.
01630         //
01631 
01632         newIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
01633 
01634         if (newIrp == NULL) {
01635 
01636             DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
01637 
01638             //
01639             // If an Irp can't be allocated then the orginal request cannot
01640             // be executed.  If this is the first request then just fail the
01641             // orginal request; otherwise just return.  When the pending
01642             // requests complete, they will complete the original request.
01643             // In either case set the IRP status to failure.
01644             //
01645 
01646             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01647             Irp->IoStatus.Information = 0;
01648 
01649             if (i == 0) {
01650                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
01651             }
01652 
01653             return;
01654         }
01655 
01656         DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp));
01657 
01658         //
01659         // Write MDL address to new IRP. In the port driver the SRB data
01660         // buffer field is used as an offset into the MDL, so the same MDL
01661         // can be used for each partial transfer. This saves having to build
01662         // a new MDL for each partial transfer.
01663         //
01664 
01665         newIrp->MdlAddress = Irp->MdlAddress;
01666 
01667         //
01668         // At this point there is no current stack. IoSetNextIrpStackLocation
01669         // will make the first stack location the current stack so that the
01670         // SRB address can be written there.
01671         //
01672 
01673         IoSetNextIrpStackLocation(newIrp);
01674         newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
01675 
01676         newIrpStack->MajorFunction = currentIrpStack->MajorFunction;
01677         newIrpStack->Parameters.Read.Length = dataLength;
01678         newIrpStack->Parameters.Read.ByteOffset = startingOffset;
01679         newIrpStack->DeviceObject = DeviceObject;
01680 
01681         //
01682         // Build SRB and CDB.
01683         //
01684 
01685         ScsiClassBuildRequest(DeviceObject, newIrp);
01686 
01687         //
01688         // Adjust SRB for this partial transfer.
01689         //
01690 
01691         newIrpStack = IoGetNextIrpStackLocation(newIrp);
01692 
01693         srb = newIrpStack->Parameters.Others.Argument1;
01694         srb->DataBuffer = dataBuffer;
01695 
01696         //
01697         // Write original IRP address to new IRP.
01698         //
01699 
01700         newIrp->AssociatedIrp.MasterIrp = Irp;
01701 
01702         //
01703         // Set the completion routine to ScsiClassIoCompleteAssociated.
01704         //
01705 
01706         IoSetCompletionRoutine(newIrp,
01707                                ScsiClassIoCompleteAssociated,
01708                                srb,
01709                                TRUE,
01710                                TRUE,
01711                                TRUE);
01712 
01713         //
01714         // Call port driver with new request.
01715         //
01716 
01717         IoCallDriver(deviceExtension->PortDeviceObject, newIrp);
01718 
01719         //
01720         // Set up for next request.
01721         //
01722 
01723         dataBuffer = (PCHAR)dataBuffer + MaximumBytes;
01724 
01725         transferByteCount -= MaximumBytes;
01726 
01727         if (transferByteCount > MaximumBytes) {
01728 
01729             dataLength = MaximumBytes;
01730 
01731         } else {
01732 
01733             dataLength = transferByteCount;
01734         }
01735 
01736         //
01737         // Adjust disk byte offset.
01738         //
01739 
01740         startingOffset.QuadPart = startingOffset.QuadPart + MaximumBytes;
01741     }
01742 
01743     return;
01744 
01745 } // end ScsiClassSplitRequest()
01746 
01747 
01748 NTSTATUS
01749 NTAPI
01750 ScsiClassIoComplete(
01751     IN PDEVICE_OBJECT DeviceObject,
01752     IN PIRP Irp,
01753     IN PVOID Context
01754     )
01755 
01756 /*++
01757 
01758 Routine Description:
01759 
01760     This routine executes when the port driver has completed a request.
01761     It looks at the SRB status in the completing SRB and if not success
01762     it checks for valid request sense buffer information. If valid, the
01763     info is used to update status with more precise message of type of
01764     error. This routine deallocates the SRB.
01765 
01766 Arguments:
01767 
01768     DeviceObject - Supplies the device object which represents the logical
01769         unit.
01770 
01771     Irp - Supplies the Irp which has completed.
01772 
01773     Context - Supplies a pointer to the SRB.
01774 
01775 Return Value:
01776 
01777     NT status
01778 
01779 --*/
01780 
01781 {
01782     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
01783     PSCSI_REQUEST_BLOCK srb = Context;
01784     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
01785     NTSTATUS status;
01786     BOOLEAN retry;
01787 
01788     //
01789     // Check SRB status for success of completing request.
01790     //
01791 
01792     if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
01793 
01794         DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp, srb));
01795 
01796         //
01797         // Release the queue if it is frozen.
01798         //
01799 
01800         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
01801             ScsiClassReleaseQueue(DeviceObject);
01802         }
01803 
01804         retry = ScsiClassInterpretSenseInfo(
01805             DeviceObject,
01806             srb,
01807             irpStack->MajorFunction,
01808             irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
01809             MAXIMUM_RETRIES - PtrToUlong(irpStack->Parameters.Others.Argument4),
01810             &status);
01811 
01812         //
01813         // If the status is verified required and the this request
01814         // should bypass verify required then retry the request.
01815         //
01816 
01817         if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
01818             status == STATUS_VERIFY_REQUIRED) {
01819 
01820             status = STATUS_IO_DEVICE_ERROR;
01821             retry = TRUE;
01822         }
01823 
01824         if (retry && (irpStack->Parameters.Others.Argument4 = (PVOID)((ULONG_PTR)irpStack->Parameters.Others.Argument4-1))) {
01825 
01826             //
01827             // Retry request.
01828             //
01829 
01830             DebugPrint((1, "Retry request %lx\n", Irp));
01831             RetryRequest(DeviceObject, Irp, srb, FALSE);
01832             return STATUS_MORE_PROCESSING_REQUIRED;
01833         }
01834     } else {
01835 
01836         //
01837         // Set status for successful request.
01838         //
01839 
01840         status = STATUS_SUCCESS;
01841 
01842     } // end if (SRB_STATUS(srb->SrbStatus) ...
01843 
01844     //
01845     // Return SRB to list.
01846     //
01847 
01848     ExFreeToNPagedLookasideList(&deviceExtension->SrbLookasideListHead,
01849                                 srb);
01850 
01851     //
01852     // Set status in completing IRP.
01853     //
01854 
01855     Irp->IoStatus.Status = status;
01856     if ((NT_SUCCESS(status)) && (Irp->Flags & IRP_PAGING_IO)) {
01857         ASSERT(Irp->IoStatus.Information);
01858     }
01859 
01860     //
01861     // Set the hard error if necessary.
01862     //
01863 
01864     if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
01865 
01866         //
01867         // Store DeviceObject for filesystem, and clear
01868         // in IoStatus.Information field.
01869         //
01870 
01871         IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
01872         Irp->IoStatus.Information = 0;
01873     }
01874 
01875     //
01876     // If pending has be returned for this irp then mark the current stack as
01877     // pending.
01878     //
01879 
01880     if (Irp->PendingReturned) {
01881       IoMarkIrpPending(Irp);
01882     }
01883 
01884     if (deviceExtension->ClassStartIo) {
01885         if (irpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL) {
01886             IoStartNextPacket(DeviceObject, FALSE);
01887         }
01888     }
01889 
01890     return status;
01891 
01892 } // end ScsiClassIoComplete()
01893 
01894 
01895 NTSTATUS
01896 NTAPI
01897 ScsiClassIoCompleteAssociated(
01898     IN PDEVICE_OBJECT DeviceObject,
01899     IN PIRP Irp,
01900     IN PVOID Context
01901     )
01902 
01903 /*++
01904 
01905 Routine Description:
01906 
01907     This routine executes when the port driver has completed a request.
01908     It looks at the SRB status in the completing SRB and if not success
01909     it checks for valid request sense buffer information. If valid, the
01910     info is used to update status with more precise message of type of
01911     error. This routine deallocates the SRB.  This routine is used for
01912     requests which were build by split request.  After it has processed
01913     the request it decrements the Irp count in the master Irp.  If the
01914     count goes to zero then the master Irp is completed.
01915 
01916 Arguments:
01917 
01918     DeviceObject - Supplies the device object which represents the logical
01919         unit.
01920 
01921     Irp - Supplies the Irp which has completed.
01922 
01923     Context - Supplies a pointer to the SRB.
01924 
01925 Return Value:
01926 
01927     NT status
01928 
01929 --*/
01930 
01931 {
01932     PIO_STACK_LOCATION  irpStack = IoGetCurrentIrpStackLocation(Irp);
01933     PSCSI_REQUEST_BLOCK srb = Context;
01934     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
01935     PIRP                originalIrp = Irp->AssociatedIrp.MasterIrp;
01936     LONG                irpCount;
01937     NTSTATUS            status;
01938     BOOLEAN             retry;
01939 
01940     //
01941     // Check SRB status for success of completing request.
01942     //
01943 
01944     if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
01945 
01946         DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp, srb));
01947 
01948         //
01949         // Release the queue if it is frozen.
01950         //
01951 
01952         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
01953             ScsiClassReleaseQueue(DeviceObject);
01954         }
01955 
01956         retry = ScsiClassInterpretSenseInfo(
01957             DeviceObject,
01958             srb,
01959             irpStack->MajorFunction,
01960             irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
01961             MAXIMUM_RETRIES - PtrToUlong(irpStack->Parameters.Others.Argument4),
01962             &status);
01963 
01964         //
01965         // If the status is verified required and the this request
01966         // should bypass verify required then retry the request.
01967         //
01968 
01969         if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
01970             status == STATUS_VERIFY_REQUIRED) {
01971 
01972             status = STATUS_IO_DEVICE_ERROR;
01973             retry = TRUE;
01974         }
01975 
01976         if (retry && (irpStack->Parameters.Others.Argument4 = (PVOID)((ULONG_PTR)irpStack->Parameters.Others.Argument4-1))) {
01977 
01978             //
01979             // Retry request. If the class driver has supplied a StartIo,
01980             // call it directly for retries.
01981             //
01982 
01983             DebugPrint((1, "Retry request %lx\n", Irp));
01984 
01985             /*
01986             if (!deviceExtension->ClassStartIo) {
01987                 RetryRequest(DeviceObject, Irp, srb, TRUE);
01988             } else {
01989                 deviceExtension->ClassStartIo(DeviceObject, Irp);
01990             }
01991             */
01992 
01993             RetryRequest(DeviceObject, Irp, srb, TRUE);
01994 
01995             return STATUS_MORE_PROCESSING_REQUIRED;
01996         }
01997 
01998 
01999 
02000     } else {
02001 
02002         //
02003         // Set status for successful request.
02004         //
02005 
02006         status = STATUS_SUCCESS;
02007 
02008     } // end if (SRB_STATUS(srb->SrbStatus) ...
02009 
02010     //
02011     // Return SRB to list.
02012     //
02013 
02014     ExFreeToNPagedLookasideList(&deviceExtension->SrbLookasideListHead,
02015                                 srb);
02016 
02017     //
02018     // Set status in completing IRP.
02019     //
02020 
02021     Irp->IoStatus.Status = status;
02022 
02023     DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp));
02024 
02025     //
02026     // Get next stack location. This original request is unused
02027     // except to keep track of the completing partial IRPs so the
02028     // stack location is valid.
02029     //
02030 
02031     irpStack = IoGetNextIrpStackLocation(originalIrp);
02032 
02033     //
02034     // Update status only if error so that if any partial transfer
02035     // completes with error, then the original IRP will return with
02036     // error. If any of the asynchronous partial transfer IRPs fail,
02037     // with an error then the original IRP will return 0 bytes transfered.
02038     // This is an optimization for successful transfers.
02039     //
02040 
02041     if (!NT_SUCCESS(status)) {
02042 
02043         originalIrp->IoStatus.Status = status;
02044         originalIrp->IoStatus.Information = 0;
02045 
02046         //
02047         // Set the hard error if necessary.
02048         //
02049 
02050         if (IoIsErrorUserInduced(status)) {
02051 
02052             //
02053             // Store DeviceObject for filesystem.
02054             //
02055 
02056             IoSetHardErrorOrVerifyDevice(originalIrp, DeviceObject);
02057         }
02058     }
02059 
02060     //
02061     // Decrement and get the count of remaining IRPs.
02062     //
02063 
02064     irpCount = InterlockedDecrement((PLONG)&irpStack->Parameters.Others.Argument1);
02065 
02066     DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n",
02067                 irpCount));
02068 
02069     //
02070     // Old bug could cause irp count to negative
02071     //
02072 
02073     ASSERT(irpCount >= 0);
02074 
02075     if (irpCount == 0) {
02076 
02077         //
02078         // All partial IRPs have completed.
02079         //
02080 
02081         DebugPrint((2,
02082                  "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n",
02083                  originalIrp));
02084 
02085         IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
02086 
02087         //
02088         // If the class driver has supplied a startio, start the
02089         // next request.
02090         //
02091 
02092         if (deviceExtension->ClassStartIo) {
02093             IoStartNextPacket(DeviceObject, FALSE);
02094         }
02095     }
02096 
02097     //
02098     // Deallocate IRP and indicate the I/O system should not attempt any more
02099     // processing.
02100     //
02101 
02102     IoFreeIrp(Irp);
02103     return STATUS_MORE_PROCESSING_REQUIRED;
02104 
02105 } // end ScsiClassIoCompleteAssociated()
02106 
02107 
02108 NTSTATUS
02109 NTAPI
02110 ScsiClassSendSrbSynchronous(
02111     PDEVICE_OBJECT DeviceObject,
02112     PSCSI_REQUEST_BLOCK Srb,
02113     PVOID BufferAddress,
02114     ULONG BufferLength,
02115     BOOLEAN WriteToDevice
02116     )
02117 
02118 /*++
02119 
02120 Routine Description:
02121 
02122     This routine is called by SCSI device controls to complete an
02123     SRB and send it to the port driver synchronously (ie wait for
02124     completion). The CDB is already completed along with the SRB CDB
02125     size and request timeout value.
02126 
02127 Arguments:
02128 
02129     DeviceObject - Supplies the device object which represents the logical
02130         unit.
02131 
02132     Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
02133 
02134     BufferAddress - Supplies the address of the buffer.
02135 
02136     BufferLength - Supplies the length in bytes of the buffer.
02137 
02138     WriteToDevice - Indicates the data should be transfer to the device.
02139 
02140 Return Value:
02141 
02142     Nt status indicating the final results of the operation.
02143 
02144 --*/
02145 
02146 {
02147     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
02148     IO_STATUS_BLOCK ioStatus;
02149     ULONG controlType, mjFunction;
02150     PIRP irp;
02151     PIO_STACK_LOCATION irpStack;
02152     KEVENT event;
02153     PUCHAR senseInfoBuffer;
02154     ULONG retryCount = MAXIMUM_RETRIES;
02155     NTSTATUS status;
02156     BOOLEAN retry;
02157     LARGE_INTEGER dummy;
02158 
02159     PAGED_CODE();
02160 
02161     dummy.QuadPart = 0;
02162 
02163     //
02164     // Write length to SRB.
02165     //
02166 
02167     Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
02168 
02169     //
02170     // Set SCSI bus address.
02171     //
02172 
02173     Srb->PathId = deviceExtension->PathId;
02174     Srb->TargetId = deviceExtension->TargetId;
02175     Srb->Lun = deviceExtension->Lun;
02176     Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
02177 
02178     //
02179     // NOTICE:  The SCSI-II specification indicates that this field should be
02180     // zero; however, some target controllers ignore the logical unit number
02181     // in the INDENTIFY message and only look at the logical unit number field
02182     // in the CDB.
02183     //
02184 
02185     Srb->Cdb[1] |= deviceExtension->Lun << 5;
02186 
02187     //
02188     // Enable auto request sense.
02189     //
02190 
02191     Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
02192 
02193     //
02194     // Sense buffer is in aligned nonpaged pool.
02195     //
02196 
02197     senseInfoBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
02198 
02199     if (senseInfoBuffer == NULL) {
02200 
02201         DebugPrint((1,
02202             "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n"));
02203         return(STATUS_INSUFFICIENT_RESOURCES);
02204     }
02205 
02206     Srb->SenseInfoBuffer = senseInfoBuffer;
02207     Srb->DataBuffer = BufferAddress;
02208 
02209     //
02210     // Start retries here.
02211     //
02212 
02213 retry:
02214 
02215     //
02216     // Set the event object to the unsignaled state.
02217     // It will be used to signal request completion.
02218     //
02219 
02220     KeInitializeEvent(&event, NotificationEvent, FALSE);
02221 
02222     //
02223     // Set controlType and Srb direction flags.
02224     //
02225 
02226     if (BufferAddress != NULL) {
02227 
02228         if (WriteToDevice) {
02229 
02230             controlType = IOCTL_SCSI_EXECUTE_OUT;
02231             Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
02232             mjFunction = IRP_MJ_WRITE;
02233 
02234         } else {
02235 
02236             controlType = IOCTL_SCSI_EXECUTE_IN;
02237             Srb->SrbFlags = SRB_FLAGS_DATA_IN;
02238             mjFunction = IRP_MJ_READ;
02239         }
02240 
02241     } else {
02242 
02243         BufferLength = 0;
02244         controlType = IOCTL_SCSI_EXECUTE_NONE;
02245         Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
02246         mjFunction = IRP_MJ_FLUSH_BUFFERS;
02247     }
02248 
02249     //
02250     // Build device I/O control request with data transfer.
02251     //
02252     irp = IoBuildAsynchronousFsdRequest(
02253             mjFunction,
02254             deviceExtension->DeviceObject,
02255             BufferAddress,
02256             (BufferAddress) ? BufferLength : 0,
02257             &dummy,
02258             &ioStatus);
02259 
02260     if (irp == NULL) {
02261         ExFreePool(senseInfoBuffer);
02262         DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
02263         return(STATUS_INSUFFICIENT_RESOURCES);
02264     }
02265 
02266     // Set event field
02267     irp->UserEvent = &event;
02268 
02269     //
02270     // Disable synchronous transfer for these requests.
02271     //
02272 
02273     Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
02274 
02275     //
02276     // Set the transfer length.
02277     //
02278 
02279     Srb->DataTransferLength = BufferLength;
02280 
02281     //
02282     // Zero out status.
02283     //
02284 
02285     Srb->ScsiStatus = Srb->SrbStatus = 0;
02286     Srb->NextSrb = 0;
02287 
02288     // Set completion routine
02289     IoSetCompletionRoutine(
02290         irp,
02291         ClassCompletionRoutine,
02292         NULL,
02293         TRUE,
02294         TRUE,
02295         TRUE);
02296 
02297     //
02298     // Get next stack location.
02299     //
02300 
02301     irpStack = IoGetNextIrpStackLocation(irp);
02302 
02303     irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
02304     irpStack->Parameters.DeviceIoControl.IoControlCode = controlType;
02305 
02306     //
02307     // Set up SRB for execute scsi request. Save SRB address in next stack
02308     // for the port driver.
02309     //
02310 
02311     irpStack->Parameters.Scsi.Srb = Srb;
02312 
02313     //
02314     // Set up IRP Address.
02315     //
02316 
02317     Srb->OriginalRequest = irp;
02318 
02319     //
02320     // Call the port driver with the request and wait for it to complete.
02321     //
02322 
02323     status = IoCallDriver(deviceExtension->PortDeviceObject, irp);
02324 
02325     if (status == STATUS_PENDING) {
02326         KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
02327     }
02328 
02329     //
02330     // Check that request completed without error.
02331     //
02332 
02333     if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
02334 
02335         //
02336         // Release the queue if it is frozen.
02337         //
02338 
02339         if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
02340             ScsiClassReleaseQueue(DeviceObject);
02341         }
02342 
02343         //
02344         // Update status and determine if request should be retried.
02345         //
02346 
02347         retry = ScsiClassInterpretSenseInfo(DeviceObject,
02348                                             Srb,
02349                                             IRP_MJ_SCSI,
02350                                             0,
02351                                             MAXIMUM_RETRIES  - retryCount,
02352                                             &status);
02353 
02354         if (retry) {
02355 
02356             if ((status == STATUS_DEVICE_NOT_READY && ((PSENSE_DATA) senseInfoBuffer)
02357                 ->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) ||
02358                 SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT) {
02359 
02360                 LARGE_INTEGER delay;
02361 
02362                 //
02363                 // Delay for 2 seconds.
02364                 //
02365 
02366                 delay.QuadPart = (LONGLONG)( - 10 * 1000 * 1000 * 2 );
02367 
02368                 //
02369                 // Stall for a while to let the controller spinup.
02370                 //
02371 
02372                 KeDelayExecutionThread(KernelMode,
02373                                        FALSE,
02374                                        &delay);
02375 
02376             }
02377 
02378             //
02379             // If retries are not exhausted then retry this operation.
02380             //
02381 
02382             if (retryCount--) {
02383                 goto retry;
02384             }
02385         }
02386 
02387     } else {
02388 
02389         status = STATUS_SUCCESS;
02390     }
02391 
02392     ExFreePool(senseInfoBuffer);
02393     return status;
02394 
02395 } // end ScsiClassSendSrbSynchronous()
02396 
02397 
02398 BOOLEAN
02399 NTAPI
02400 ScsiClassInterpretSenseInfo(
02401     IN PDEVICE_OBJECT DeviceObject,
02402     IN PSCSI_REQUEST_BLOCK Srb,
02403     IN UCHAR MajorFunctionCode,
02404     IN ULONG IoDeviceCode,
02405     IN ULONG RetryCount,
02406     OUT NTSTATUS *Status
02407     )
02408 
02409 /*++
02410 
02411 Routine Description:
02412 
02413     This routine interprets the data returned from the SCSI
02414     request sense. It determines the status to return in the
02415     IRP and whether this request can be retried.
02416 
02417 Arguments:
02418 
02419     DeviceObject - Supplies the device object associated with this request.
02420 
02421     Srb - Supplies the scsi request block which failed.
02422 
02423     MajorFunctionCode - Supplies the function code to be used for logging.
02424 
02425     IoDeviceCode - Supplies the device code to be used for logging.
02426 
02427     Status - Returns the status for the request.
02428 
02429 Return Value:
02430 
02431     BOOLEAN TRUE: Drivers should retry this request.
02432             FALSE: Drivers should not retry this request.
02433 
02434 --*/
02435 
02436 {
02437     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
02438     PDEVICE_EXTENSION physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension;
02439     PSENSE_DATA       senseBuffer = Srb->SenseInfoBuffer;
02440     BOOLEAN           retry = TRUE;
02441     BOOLEAN           logError = FALSE;
02442     ULONG             badSector = 0;
02443     ULONG             uniqueId = 0;
02444     NTSTATUS          logStatus;
02445     ULONG             readSector;
02446     ULONG             index;
02447     PIO_ERROR_LOG_PACKET errorLogEntry;
02448 #if DBG
02449     ULONG             i;
02450 #endif
02451 
02452 
02453     //
02454     // Check that request sense buffer is valid.
02455     //
02456 
02457 #if DBG
02458     DebugPrint((3, "Opcode %x\nParameters: ",Srb->Cdb[0]));
02459     for (i = 1; i < 12; i++) {
02460         DebugPrint((3,"%x ",Srb->Cdb[i]));
02461     }
02462     DebugPrint((3,"\n"));
02463 #endif
02464 
02465     if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID &&
02466         Srb->SenseInfoBufferLength >= FIELD_OFFSET(SENSE_DATA, CommandSpecificInformation)) {
02467 
02468         DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n",
02469                     senseBuffer->ErrorCode));
02470         DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n",
02471                     senseBuffer->SenseKey));
02472         DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n",
02473                     senseBuffer->AdditionalSenseCode));
02474         DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n",
02475                   senseBuffer->AdditionalSenseCodeQualifier));
02476 
02477         //
02478         // Zero the additional sense code and additional sense code qualifier
02479         // if they were not returned by the device.
02480         //
02481 
02482         readSector = senseBuffer->AdditionalSenseLength +
02483             FIELD_OFFSET(SENSE_DATA, AdditionalSenseLength);
02484 
02485         if (readSector > Srb->SenseInfoBufferLength) {
02486             readSector = Srb->SenseInfoBufferLength;
02487         }
02488 
02489         if (readSector <= FIELD_OFFSET(SENSE_DATA, AdditionalSenseCode)) {
02490             senseBuffer->AdditionalSenseCode = 0;
02491         }
02492 
02493         if (readSector <= FIELD_OFFSET(SENSE_DATA, AdditionalSenseCodeQualifier)) {
02494             senseBuffer->AdditionalSenseCodeQualifier = 0;
02495         }
02496 
02497         switch (senseBuffer->SenseKey & 0xf) {
02498 
02499         case SCSI_SENSE_NOT_READY:
02500 
02501             DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n"));
02502             *Status = STATUS_DEVICE_NOT_READY;
02503 
02504             switch (senseBuffer->AdditionalSenseCode) {
02505 
02506             case SCSI_ADSENSE_LUN_NOT_READY:
02507 
02508                 DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n"));
02509 
02510                 switch (senseBuffer->AdditionalSenseCodeQualifier) {
02511 
02512                 case SCSI_SENSEQ_BECOMING_READY:
02513 
02514                     DebugPrint((1, "ScsiClassInterpretSenseInfo:"
02515                                 " In process of becoming ready\n"));
02516                     break;
02517 
02518                 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
02519 
02520                     DebugPrint((1, "ScsiClassInterpretSenseInfo:"
02521                                 " Manual intervention required\n"));
02522                     *Status = STATUS_NO_MEDIA_IN_DEVICE;
02523                     retry = FALSE;
02524                     break;
02525 
02526                 case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
02527 
02528                     DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n"));
02529                     retry = FALSE;
02530                     break;
02531 
02532                 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
02533 
02534                 default:
02535 
02536                     DebugPrint((1, "ScsiClassInterpretSenseInfo:"
02537                                 " Initializing command required\n"));
02538 
02539                     //
02540                     // This sense code/additional sense code
02541                     // combination may indicate that the device
02542                     // needs to be started.  Send an start unit if this
02543                     // is a disk device.
02544                     //
02545 
02546                     if (deviceExtension->DeviceFlags & DEV_SAFE_START_UNIT) {
02547                         StartUnit(DeviceObject);
02548                     }
02549 
02550                     break;
02551 
02552                 } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
02553 
02554                 break;
02555 
02556             case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
02557 
02558                 DebugPrint((1,
02559                             "ScsiClassInterpretSenseInfo:"
02560                             " No Media in device.\n"));
02561                 *Status = STATUS_NO_MEDIA_IN_DEVICE;
02562                 retry = FALSE;
02563 
02564                 //
02565                 // signal autorun that there isn't any media in the device
02566                 //
02567 
02568                 if((deviceExtension->MediaChangeEvent != NULL)&&
02569                    (!deviceExtension->MediaChangeNoMedia)) {
02570                     KeSetEvent(deviceExtension->MediaChangeEvent,
02571                            (KPRIORITY) 0,
02572                            FALSE);
02573                     DebugPrint((0, "ScsiClassInterpretSenseInfo:"
02574                                    "Detected No Media In Device "
02575                                    "[irp = 0x%lx]\n", Srb->OriginalRequest));
02576                     deviceExtension->MediaChangeNoMedia = TRUE;
02577                 }
02578 
02579                 break;
02580             } // end switch (senseBuffer->AdditionalSenseCode)
02581 
02582             break;
02583 
02584         case SCSI_SENSE_DATA_PROTECT:
02585 
02586             DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n"));
02587             *Status = STATUS_MEDIA_WRITE_PROTECTED;
02588             retry = FALSE;
02589             break;
02590 
02591         case SCSI_SENSE_MEDIUM_ERROR:
02592 
02593             DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n"));
02594             *Status = STATUS_DEVICE_DATA_ERROR;
02595 
02596             retry = FALSE;
02597             logError = TRUE;
02598             uniqueId = 256;
02599             logStatus = 0;//IO_ERR_BAD_BLOCK;
02600             break;
02601 
02602         case SCSI_SENSE_HARDWARE_ERROR:
02603 
02604             DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n"));
02605             *Status = STATUS_IO_DEVICE_ERROR;
02606 
02607             logError = TRUE;
02608             uniqueId = 257;
02609             logStatus = 0;//IO_ERR_CONTROLLER_ERROR;
02610 
02611             break;
02612 
02613         case SCSI_SENSE_ILLEGAL_REQUEST:
02614 
02615             DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n"));
02616             *Status = STATUS_INVALID_DEVICE_REQUEST;
02617 
02618             switch (senseBuffer->AdditionalSenseCode) {
02619 
02620             case SCSI_ADSENSE_ILLEGAL_COMMAND:
02621                 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n"));
02622                 retry = FALSE;
02623                 break;
02624 
02625             case SCSI_ADSENSE_ILLEGAL_BLOCK:
02626                 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n"));
02627                 *Status = STATUS_NONEXISTENT_SECTOR;
02628                 retry = FALSE;
02629                 break;
02630 
02631             case SCSI_ADSENSE_INVALID_LUN:
02632                 DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n"));
02633                 *Status = STATUS_NO_SUCH_DEVICE;
02634                 retry = FALSE;
02635                 break;
02636 
02637             case SCSI_ADSENSE_MUSIC_AREA:
02638                 DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n"));
02639                 retry = FALSE;
02640                 break;
02641 
02642             case SCSI_ADSENSE_DATA_AREA:
02643                 DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n"));
02644                 retry = FALSE;
02645                 break;
02646 
02647             case SCSI_ADSENSE_VOLUME_OVERFLOW:
02648                 DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n"));
02649                 retry = FALSE;
02650                 break;
02651 
02652             case SCSI_ADSENSE_INVALID_CDB:
02653                 DebugPrint((1, "ScsiClassInterpretSenseInfo: Invalid CDB\n"));
02654 
02655                 //
02656                 // Check if write cache enabled.
02657                 //
02658 
02659                 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
02660 
02661                     //
02662                     // Assume FUA is not supported.
02663                     //
02664 
02665                     deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
02666                     retry = TRUE;
02667 
02668                 } else {
02669                     retry = FALSE;
02670                 }
02671 
02672                 break;
02673 
02674             } // end switch (senseBuffer->AdditionalSenseCode)
02675 
02676             break;
02677 
02678         case SCSI_SENSE_UNIT_ATTENTION:
02679 
02680             switch (senseBuffer->AdditionalSenseCode) {
02681             case SCSI_ADSENSE_MEDIUM_CHANGED:
02682                 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n"));
02683 
02684                 if(deviceExtension->MediaChangeEvent != NULL) {
02685 
02686                     KeSetEvent(deviceExtension->MediaChangeEvent,
02687                            (KPRIORITY) 0,
02688                            FALSE);
02689                     DebugPrint((0, "ScsiClassInterpretSenseInfo:"
02690                                    "New Media Found - Setting MediaChanged event"
02691                                    " [irp = 0x%lx]\n", Srb->OriginalRequest));
02692                     deviceExtension->MediaChangeNoMedia = FALSE;
02693 
02694                 }
02695                 break;
02696 
02697             case SCSI_ADSENSE_BUS_RESET:
02698                 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n"));
02699                 break;
02700 
02701             default:
02702                 DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n"));
02703                 break;
02704 
02705             } // end  switch (senseBuffer->AdditionalSenseCode)
02706 
02707             if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
02708                 DeviceObject->Vpb->Flags & VPB_MOUNTED) {
02709 
02710                 //
02711                 // Set bit to indicate that media may have changed
02712                 // and volume needs verification.
02713                 //
02714 
02715                 DeviceObject->Flags |= DO_VERIFY_VOLUME;
02716 
02717                 *Status = STATUS_VERIFY_REQUIRED;
02718                 retry = FALSE;
02719 
02720             } else {
02721 
02722                 *Status = STATUS_IO_DEVICE_ERROR;
02723 
02724             }
02725 
02726             //
02727             // A media change may have occured so increment the change
02728             // count for the physical device
02729             //
02730 
02731             physicalExtension->MediaChangeCount++;
02732 
02733             DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change "
02734                            "count for device %d is %d\n",
02735                         physicalExtension->DeviceNumber,
02736                         physicalExtension->MediaChangeCount));
02737 
02738             break;
02739 
02740         case SCSI_SENSE_ABORTED_COMMAND:
02741 
02742             DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n"));
02743             *Status = STATUS_IO_DEVICE_ERROR;
02744             break;
02745 
02746         case SCSI_SENSE_RECOVERED_ERROR:
02747 
02748             DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n"));
02749             *Status = STATUS_SUCCESS;
02750             retry = FALSE;
02751             logError = TRUE;
02752             uniqueId = 258;
02753 
02754             switch(senseBuffer->AdditionalSenseCode) {
02755             case SCSI_ADSENSE_SEEK_ERROR:
02756             case SCSI_ADSENSE_TRACK_ERROR:
02757                 logStatus = 0;//IO_ERR_SEEK_ERROR;
02758                 break;
02759 
02760             case SCSI_ADSENSE_REC_DATA_NOECC:
02761             case SCSI_ADSENSE_REC_DATA_ECC:
02762                 logStatus = 0;//IO_RECOVERED_VIA_ECC;
02763                 break;
02764 
02765             default:
02766                 logStatus = 0;//IO_ERR_CONTROLLER_ERROR;
02767                 break;
02768 
02769             } // end switch(senseBuffer->AdditionalSenseCode)
02770 
02771             if (senseBuffer->IncorrectLength) {
02772 
02773                 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
02774                 *Status = STATUS_INVALID_BLOCK_LENGTH ;
02775             }
02776 
02777             break;
02778 
02779         case SCSI_SENSE_NO_SENSE:
02780 
02781             //
02782             // Check other indicators.
02783             //
02784 
02785             if (senseBuffer->IncorrectLength) {
02786 
02787                 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
02788                 *Status = STATUS_INVALID_BLOCK_LENGTH ;
02789                 retry   = FALSE;
02790 
02791             } else {
02792 
02793                 DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n"));
02794                 *Status = STATUS_IO_DEVICE_ERROR;
02795                 retry   = TRUE;
02796             }
02797 
02798             break;
02799 
02800         default:
02801 
02802             DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n"));
02803             *Status = STATUS_IO_DEVICE_ERROR;
02804             break;
02805 
02806         } // end switch (senseBuffer->SenseKey & 0xf)
02807 
02808         //
02809         // Try to determine the bad sector from the inquiry data.
02810         //
02811 
02812         if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_READ ||
02813             ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY ||
02814             ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_WRITE)) {
02815 
02816             for (index = 0; index < 4; index++) {
02817                 badSector = (badSector << 8) | senseBuffer->Information[index];
02818             }
02819 
02820             readSector = 0;
02821             for (index = 0; index < 4; index++) {
02822                 readSector = (readSector << 8) | Srb->Cdb[index+2];
02823             }
02824 
02825             index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) |
02826                 ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb;
02827 
02828             //
02829             // Make sure the bad sector is within the read sectors.
02830             //
02831 
02832             if (!(badSector >= readSector && badSector < readSector + index)) {
02833                 badSector = readSector;
02834             }
02835         }
02836 
02837     } else {
02838 
02839         //
02840         // Request sense buffer not valid. No sense information
02841         // to pinpoint the error. Return general request fail.
02842         //
02843 
02844         DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n",
02845                     SRB_STATUS(Srb->SrbStatus)));
02846         retry = TRUE;
02847 
02848         switch (SRB_STATUS(Srb->SrbStatus)) {
02849         case SRB_STATUS_INVALID_LUN:
02850         case SRB_STATUS_INVALID_TARGET_ID:
02851         case SRB_STATUS_NO_DEVICE:
02852         case SRB_STATUS_NO_HBA:
02853         case SRB_STATUS_INVALID_PATH_ID:
02854             *Status = STATUS_NO_SUCH_DEVICE;
02855             retry = FALSE;
02856             break;
02857 
02858         case SRB_STATUS_COMMAND_TIMEOUT:
02859         case SRB_STATUS_ABORTED:
02860         case SRB_STATUS_TIMEOUT:
02861 
02862             //
02863             // Update the error count for the device.
02864             //
02865 
02866             deviceExtension->ErrorCount++;
02867             *Status = STATUS_IO_TIMEOUT;
02868             break;
02869 
02870         case SRB_STATUS_SELECTION_TIMEOUT:
02871             logError = TRUE;
02872             logStatus = 0;//IO_ERR_NOT_READY;
02873             uniqueId = 260;
02874             *Status = STATUS_DEVICE_NOT_CONNECTED;
02875             retry = FALSE;
02876             break;
02877 
02878         case SRB_STATUS_DATA_OVERRUN:
02879             *Status = STATUS_DATA_OVERRUN;
02880             retry = FALSE;
02881             break;
02882 
02883         case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
02884 
02885             //
02886             // Update the error count for the device.
02887             //
02888 
02889             deviceExtension->ErrorCount++;
02890             *Status = STATUS_IO_DEVICE_ERROR;
02891 
02892             //
02893             // If there was  phase sequence error then limit the number of
02894             // retries.
02895             //
02896 
02897             if (RetryCount > 1 ) {
02898                 retry = FALSE;
02899             }
02900 
02901             break;
02902 
02903         case SRB_STATUS_REQUEST_FLUSHED:
02904 
02905             //
02906             // If the status needs verification bit is set.  Then set
02907             // the status to need verification and no retry; otherwise,
02908             // just retry the request.
02909             //
02910 
02911             if (DeviceObject->Flags & DO_VERIFY_VOLUME ) {
02912 
02913                 *Status = STATUS_VERIFY_REQUIRED;
02914                 retry = FALSE;
02915             } else {
02916                 *Status = STATUS_IO_DEVICE_ERROR;
02917             }
02918 
02919             break;
02920 
02921         case SRB_STATUS_INVALID_REQUEST:
02922 
02923             //
02924             // An invalid request was attempted.
02925             //
02926 
02927             *Status = STATUS_INVALID_DEVICE_REQUEST;
02928             retry = FALSE;
02929             break;
02930 
02931         case SRB_STATUS_UNEXPECTED_BUS_FREE:
02932         case SRB_STATUS_PARITY_ERROR:
02933 
02934             //
02935             // Update the error count for the device.
02936             //
02937 
02938             deviceExtension->ErrorCount++;
02939 
02940             //
02941             // Fall through to below.
02942             //
02943 
02944         case SRB_STATUS_BUS_RESET:
02945             *Status = STATUS_IO_DEVICE_ERROR;
02946             break;
02947 
02948         case SRB_STATUS_ERROR:
02949 
02950             *Status = STATUS_IO_DEVICE_ERROR;
02951             if (Srb->ScsiStatus == 0) {
02952 
02953                 //
02954                 // This is some strange return code.  Update the error
02955                 // count for the device.
02956                 //
02957 
02958                 deviceExtension->ErrorCount++;
02959 
02960             } if (Srb->ScsiStatus == SCSISTAT_BUSY) {
02961 
02962                 *Status = STATUS_DEVICE_NOT_READY;
02963 
02964             } if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT) {
02965 
02966                 *Status = STATUS_DEVICE_BUSY;
02967                 retry = FALSE;
02968 
02969             }
02970 
02971             break;
02972 
02973         default:
02974             logError = TRUE;
02975             logStatus = 0;//IO_ERR_CONTROLLER_ERROR;
02976             uniqueId = 259;
02977             *Status = STATUS_IO_DEVICE_ERROR;
02978             break;
02979 
02980         }
02981 
02982         //
02983         // If the error count has exceeded the error limit, then disable
02984         // any tagged queuing, multiple requests per lu queueing
02985         // and sychronous data transfers.
02986         //
02987 
02988         if (deviceExtension->ErrorCount == 4) {
02989 
02990             //
02991             // Clearing the no queue freeze flag prevents the port driver
02992             // from sending multiple requests per logical unit.
02993             //
02994 
02995             deviceExtension->SrbFlags &= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE |
02996                                             SRB_FLAGS_NO_QUEUE_FREEZE);
02997 
02998             deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
02999             DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n"));
03000 
03001         } else if (deviceExtension->ErrorCount == 8) {
03002 
03003             //
03004             // If a second threshold is reached, disable disconnects.
03005             //
03006 
03007             deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
03008             DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n"));
03009         }
03010     }
03011 
03012     //
03013     // If there is a class specific error handler call it.
03014     //
03015 
03016     if (deviceExtension->ClassError != NULL) {
03017 
03018         deviceExtension->ClassError(DeviceObject,
03019                                     Srb,
03020                                     Status,
03021                                     &retry);
03022     }
03023 
03024     //
03025     // Log an error if necessary.
03026     //
03027 
03028     if (logError) {
03029 
03030         errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
03031             DeviceObject,
03032             sizeof(IO_ERROR_LOG_PACKET) + 5 * sizeof(ULONG));
03033 
03034         if (errorLogEntry == NULL) {
03035 
03036             //
03037             // Return if no packet could be allocated.
03038             //
03039 
03040             return retry;
03041 
03042         }
03043 
03044         if (retry && RetryCount < MAXIMUM_RETRIES) {
03045             errorLogEntry->FinalStatus = STATUS_SUCCESS;
03046         } else {
03047             errorLogEntry->FinalStatus = *Status;
03048         }
03049 
03050         //
03051         // Calculate the device offset if there is a geometry.
03052         //
03053 
03054         if (deviceExtension->DiskGeometry != NULL) {
03055 
03056             errorLogEntry->DeviceOffset.QuadPart = (LONGLONG) badSector;
03057             errorLogEntry->DeviceOffset = RtlExtendedIntegerMultiply(
03058                                errorLogEntry->DeviceOffset,
03059                                deviceExtension->DiskGeometry->Geometry.BytesPerSector);
03060         }
03061 
03062         errorLogEntry->ErrorCode = logStatus;
03063         errorLogEntry->SequenceNumber = 0;
03064         errorLogEntry->MajorFunctionCode = MajorFunctionCode;
03065         errorLogEntry->IoControlCode = IoDeviceCode;
03066         errorLogEntry->RetryCount = (UCHAR) RetryCount;
03067         errorLogEntry->UniqueErrorValue = uniqueId;
03068         errorLogEntry->DumpDataSize = 6 * sizeof(ULONG);
03069         errorLogEntry->DumpData[0] = Srb->PathId;
03070         errorLogEntry->DumpData[1] = Srb->TargetId;
03071         errorLogEntry->DumpData[2] = Srb->Lun;
03072         errorLogEntry->DumpData[3] = 0;
03073         errorLogEntry->DumpData[4] = Srb->SrbStatus << 8 | Srb->ScsiStatus;
03074 
03075         if (senseBuffer != NULL) {
03076             errorLogEntry->DumpData[5] = senseBuffer->SenseKey << 16 |
03077                                      senseBuffer->AdditionalSenseCode << 8 |
03078                                      senseBuffer->AdditionalSenseCodeQualifier;
03079 
03080         }
03081 
03082         //
03083         // Write the error log packet.
03084         //
03085 
03086         IoWriteErrorLogEntry(errorLogEntry);
03087     }
03088 
03089     return retry;
03090 
03091 } // end ScsiClassInterpretSenseInfo()
03092 
03093 
03094 VOID
03095 NTAPI
03096 RetryRequest(
03097     PDEVICE_OBJECT DeviceObject,
03098     PIRP Irp,
03099     PSCSI_REQUEST_BLOCK Srb,
03100     BOOLEAN Associated
03101     )
03102 
03103 /*++
03104 
03105 Routine Description:
03106 
03107     This routine reinitalizes the necessary fields, and sends the request
03108     to the port driver.
03109 
03110 Arguments:
03111 
03112     DeviceObject - Supplies the device object associated with this request.
03113 
03114     Irp - Supplies the request to be retried.
03115 
03116     Srb - Supplies a Pointer to the SCSI request block to be retied.
03117 
03118     Assocaiated - Indicates this is an assocatied Irp created by split request.
03119 
03120 Return Value:
03121 
03122     None
03123 
03124 --*/
03125 
03126 {
03127     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
03128     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
03129     PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
03130     ULONG transferByteCount;
03131 
03132     //
03133     // Determine the transfer count of the request.  If this is a read or a
03134     // write then the transfer count is in the Irp stack.  Otherwise assume
03135     // the MDL contains the correct length.  If there is no MDL then the
03136     // transfer length must be zero.
03137     //
03138 
03139     if (currentIrpStack->MajorFunction == IRP_MJ_READ ||
03140         currentIrpStack->MajorFunction == IRP_MJ_WRITE) {
03141 
03142         transferByteCount = currentIrpStack->Parameters.Read.Length;
03143 
03144     } else if (Irp->MdlAddress != NULL) {
03145 
03146         //
03147         // Note this assumes that only read and write requests are spilt and
03148         // other request do not need to be.  If the data buffer address in
03149         // the MDL and the SRB don't match then transfer length is most
03150         // likely incorrect.
03151         //
03152 
03153         ASSERT(Srb->DataBuffer == MmGetMdlVirtualAddress(Irp->MdlAddress));
03154         transferByteCount = Irp->MdlAddress->ByteCount;
03155 
03156     } else {
03157 
03158         transferByteCount = 0;
03159     }
03160 
03161     //
03162     // Reset byte count of transfer in SRB Extension.
03163     //
03164 
03165     Srb->DataTransferLength = transferByteCount;
03166 
03167     //
03168     // Zero SRB statuses.
03169     //
03170 
03171     Srb->SrbStatus = Srb->ScsiStatus = 0;
03172 
03173     //
03174     // Set the no disconnect flag, disable synchronous data transfers and
03175     // disable tagged queuing. This fixes some errors.
03176     //
03177 
03178     Srb->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT |
03179                      SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
03180 
03181     Srb->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE;
03182     Srb->QueueTag = SP_UNTAGGED;
03183 
03184     //
03185     // Set up major SCSI function.
03186     //
03187 
03188     nextIrpStack->MajorFunction = IRP_MJ_SCSI;
03189 
03190     //
03191     // Save SRB address in next stack for port driver.
03192     //
03193 
03194     nextIrpStack->Parameters.Scsi.Srb = Srb;
03195 
03196     //
03197     // Set up IoCompletion routine address.
03198     //
03199 
03200     if (Associated) {
03201 
03202         IoSetCompletionRoutine(Irp, ScsiClassIoCompleteAssociated, Srb, TRUE, TRUE, TRUE);
03203 
03204     } else {
03205 
03206         IoSetCompletionRoutine(Irp, ScsiClassIoComplete, Srb, TRUE, TRUE, TRUE);
03207     }
03208 
03209     //
03210     // Pass the request to the port driver.
03211     //
03212 
03213     (VOID)IoCallDriver(deviceExtension->PortDeviceObject, Irp);
03214 
03215 } // end RetryRequest()
03216 
03217 VOID
03218 NTAPI
03219 ScsiClassBuildRequest(
03220         PDEVICE_OBJECT DeviceObject,
03221         PIRP Irp
03222         )
03223 
03224 /*++
03225 
03226 Routine Description:
03227 
03228     This routine allocates and builds an Srb for a read or write request.
03229     The block address and length are supplied by the Irp. The retry count
03230     is stored in the current stack for use by ScsiClassIoComplete which
03231     processes these requests when they complete.  The Irp is ready to be
03232     passed to the port driver when this routine returns.
03233 
03234 Arguments:
03235 
03236     DeviceObject - Supplies the device object associated with this request.
03237 
03238     Irp - Supplies the request to be retried.
03239 
03240 Note:
03241 
03242     If the IRP is for a disk transfer, the byteoffset field
03243     will already have been adjusted to make it relative to
03244     the beginning of the disk.
03245 
03246 
03247 Return Value:
03248 
03249     None.
03250 
03251 --*/
03252 
03253 {
03254     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
03255     PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
03256     PIO_STACK_LOCATION  nextIrpStack = IoGetNextIrpStackLocation(Irp);
03257     LARGE_INTEGER       startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
03258     PSCSI_REQUEST_BLOCK srb;
03259     PCDB                cdb;
03260     ULONG               logicalBlockAddress;
03261     USHORT              transferBlocks;
03262 
03263     //
03264     // Calculate relative sector address.
03265     //
03266 
03267     logicalBlockAddress =  (ULONG)(Int64ShrlMod32(startingOffset.QuadPart, deviceExtension->SectorShift));
03268 
03269     //
03270     // Allocate an Srb.
03271     //
03272 
03273     srb = ExAllocateFromNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
03274 
03275     srb->SrbFlags = 0;
03276 
03277     //
03278     // Write length to SRB.
03279     //
03280 
03281     srb->Length = SCSI_REQUEST_BLOCK_SIZE;
03282 
03283     //
03284     // Set up IRP Address.
03285     //
03286 
03287     srb->OriginalRequest = Irp;
03288 
03289     //
03290     // Set up target ID and logical unit number.
03291     //
03292 
03293     srb->PathId = deviceExtension->PathId;
03294     srb->TargetId = deviceExtension->TargetId;
03295     srb->Lun = deviceExtension->Lun;
03296     srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
03297     srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
03298 
03299     //
03300     // Save byte count of transfer in SRB Extension.
03301     //
03302 
03303     srb->DataTransferLength = currentIrpStack->Parameters.Read.Length;
03304 
03305     //
03306     // Initialize the queue actions field.
03307     //
03308 
03309     srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
03310 
03311     //
03312     // Queue sort key is Relative Block Address.
03313     //
03314 
03315     srb->QueueSortKey = logicalBlockAddress;
03316 
03317     //
03318     // Indicate auto request sense by specifying buffer and size.
03319     //
03320 
03321     srb->SenseInfoBuffer = deviceExtension->SenseData;
03322     srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
03323 
03324     //
03325     // Set timeout value of one unit per 64k bytes of data.
03326     //
03327 
03328     srb->TimeOutValue = ((srb->DataTransferLength + 0xFFFF) >> 16) *
03329                         deviceExtension->TimeOutValue;
03330 
03331     //
03332     // Zero statuses.
03333     //
03334 
03335     srb->SrbStatus = srb->ScsiStatus = 0;
03336     srb->NextSrb = 0;
03337 
03338     //
03339     // Indicate that 10-byte CDB's will be used.
03340     //
03341 
03342     srb->CdbLength = 10;
03343 
03344     //
03345     // Fill in CDB fields.
03346     //
03347 
03348     cdb = (PCDB)srb->Cdb;
03349 
03350     //
03351     // Zero 12 bytes for Atapi Packets
03352     //
03353 
03354     RtlZeroMemory(cdb, MAXIMUM_CDB_SIZE);
03355 
03356     cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
03357     transferBlocks = (USHORT)(currentIrpStack->Parameters.Read.Length >> deviceExtension->SectorShift);
03358 
03359     //
03360     // Move little endian values into CDB in big endian format.
03361     //
03362 
03363     cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
03364     cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
03365     cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
03366     cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
03367 
03368     cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&transferBlocks)->Byte1;
03369     cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&transferBlocks)->Byte0;
03370 
03371     //
03372     // Set transfer direction flag and Cdb command.
03373     //
03374 
03375     if (currentIrpStack->MajorFunction == IRP_MJ_READ) {
03376 
03377         DebugPrint((3, "ScsiClassBuildRequest: Read Command\n"));
03378 
03379         srb->SrbFlags |= SRB_FLAGS_DATA_IN;
03380         cdb->CDB10.OperationCode = SCSIOP_READ;
03381 
03382     } else {
03383 
03384         DebugPrint((3, "ScsiClassBuildRequest: Write Command\n"));
03385 
03386         srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
03387         cdb->CDB10.OperationCode = SCSIOP_WRITE;
03388     }
03389 
03390     //
03391     // If this is not a write-through request, then allow caching.
03392     //
03393 
03394     if (!(currentIrpStack->Flags & SL_WRITE_THROUGH)) {
03395 
03396         srb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE;
03397 
03398     } else {
03399 
03400         //
03401         // If write caching is enable then force media access in the
03402         // cdb.
03403         //
03404 
03405         if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
03406             cdb->CDB10.ForceUnitAccess = TRUE;
03407         }
03408     }
03409 
03410     //
03411     // Or in the default flags from the device object.
03412     //
03413 
03414     srb->SrbFlags |= deviceExtension->SrbFlags;
03415 
03416     //
03417     // Set up major SCSI function.
03418     //
03419 
03420     nextIrpStack->MajorFunction = IRP_MJ_SCSI;
03421 
03422     //
03423     // Save SRB address in next stack for port driver.
03424     //
03425 
03426     nextIrpStack->Parameters.Scsi.Srb = srb;
03427 
03428     //
03429     // Save retry count in current IRP stack.
03430     //
03431 
03432     currentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
03433 
03434     //
03435     // Set up IoCompletion routine address.
03436     //
03437 
03438     IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
03439 
03440     return;
03441 
03442 } // end ScsiClassBuildRequest()
03443 
03444 ULONG
03445 NTAPI
03446 ScsiClassModeSense(
03447     IN PDEVICE_OBJECT DeviceObject,
03448     IN PCHAR ModeSenseBuffer,
03449     IN ULONG Length,
03450     IN UCHAR PageMode
03451     )
03452 
03453 /*++
03454 
03455 Routine Description:
03456 
03457     This routine sends a mode sense command to a target ID and returns
03458     when it is complete.
03459 
03460 Arguments:
03461 
03462     DeviceObject - Supplies the device object associated with this request.
03463 
03464     ModeSenseBuffer - Supplies a buffer to store the sense data.
03465 
03466     Length - Supplies the length in bytes of the mode sense buffer.
03467 
03468     PageMode - Supplies the page or pages of mode sense data to be retrived.
03469 
03470 Return Value:
03471 
03472     Length of the transferred data is returned.
03473 
03474 --*/
03475 {
03476     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
03477     PCDB cdb;
03478     SCSI_REQUEST_BLOCK srb;
03479     ULONG retries = 1;
03480     NTSTATUS status;
03481 
03482     RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
03483 
03484     //
03485     // Build the MODE SENSE CDB.
03486     //
03487 
03488     srb.CdbLength = 6;
03489     cdb = (PCDB)srb.Cdb;
03490 
03491     //
03492     // Set timeout value from device extension.
03493     //
03494 
03495     srb.TimeOutValue = deviceExtension->TimeOutValue;
03496 
03497     cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
03498     cdb->MODE_SENSE.PageCode = PageMode;
03499     cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
03500 
03501 Retry:
03502 
03503     status = ScsiClassSendSrbSynchronous(DeviceObject,
03504                                          &srb,
03505                                          ModeSenseBuffer,
03506                                          Length,
03507                                          FALSE);
03508 
03509 
03510     if (status == STATUS_VERIFY_REQUIRED) {
03511 
03512         //
03513         // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
03514         // this status. MODE SENSE commands should be retried anyway.
03515         //
03516 
03517         if (retries--) {
03518 
03519             //
03520             // Retry request.
03521             //
03522 
03523             goto Retry;
03524         }
03525 
03526     } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
03527         status = STATUS_SUCCESS;
03528     }
03529 
03530     if (NT_SUCCESS(status)) {
03531         return(srb.DataTransferLength);
03532     } else {
03533         return(0);
03534     }
03535 
03536 } // end ScsiClassModeSense()
03537 
03538 
03539 PVOID
03540 NTAPI
03541 ScsiClassFindModePage(
03542     IN PCHAR ModeSenseBuffer,
03543     IN ULONG Length,
03544     IN UCHAR PageMode,
03545     IN BOOLEAN Use6Byte
03546     )
03547 
03548 /*++
03549 
03550 Routine Description:
03551 
03552     This routine scans through the mode sense data and finds the requested
03553     mode sense page code.
03554 
03555 Arguments:
03556     ModeSenseBuffer - Supplies a pointer to the mode sense data.
03557 
03558     Length - Indicates the length of valid data.
03559 
03560     PageMode - Supplies the page mode to be searched for.
03561 
03562     Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
03563 
03564 Return Value:
03565 
03566     A pointer to the the requested mode page.  If the mode page was not found
03567     then NULL is return.
03568 
03569 --*/
03570 {
03571     PUCHAR limit;
03572     ULONG  parameterHeaderLength;
03573 
03574     limit = (PUCHAR)ModeSenseBuffer + Length;
03575     parameterHeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10);
03576 
03577 
03578     //
03579     // Skip the mode select header and block descriptors.
03580     //
03581 
03582     if (Length < parameterHeaderLength) {
03583         return(NULL);
03584     }
03585 
03586 
03587 
03588     ModeSenseBuffer += parameterHeaderLength + ((Use6Byte) ? ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength :
03589                        ((PMODE_PARAMETER_HEADER10) ModeSenseBuffer)->BlockDescriptorLength[1]);
03590 
03591     //
03592     // ModeSenseBuffer now points at pages.  Walk the pages looking for the
03593     // requested page until the limit is reached.
03594     //
03595 
03596 
03597     while ((PUCHAR)ModeSenseBuffer < limit) {
03598 
03599         if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) {
03600             return(ModeSenseBuffer);
03601         }
03602 
03603         //
03604         // Advance to the next page.
03605         //
03606 
03607         ModeSenseBuffer += ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength + 2;
03608     }
03609 
03610     return(NULL);
03611 }
03612 
03613 NTSTATUS
03614 NTAPI
03615 ScsiClassSendSrbAsynchronous(
03616         PDEVICE_OBJECT DeviceObject,
03617         PSCSI_REQUEST_BLOCK Srb,
03618         PIRP Irp,
03619         PVOID BufferAddress,
03620         ULONG BufferLength,
03621         BOOLEAN WriteToDevice
03622         )
03623 /*++
03624 
03625 Routine Description:
03626 
03627     This routine takes a partially built Srb and an Irp and sends it down to
03628     the port driver.
03629 
03630 Arguments:
03631     DeviceObject - Supplies the device object for the orginal request.
03632 
03633     Srb - Supplies a paritally build ScsiRequestBlock.  In particular, the
03634         CDB and the SRB timeout value must be filled in.  The SRB must not be
03635         allocated from zone.
03636 
03637     Irp - Supplies the requesting Irp.
03638 
03639     BufferAddress - Supplies a pointer to the buffer to be transfered.
03640 
03641     BufferLength - Supplies the length of data transfer.
03642 
03643     WriteToDevice - Indicates the data transfer will be from system memory to
03644         device.
03645 
03646 Return Value:
03647 
03648     Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver.
03649 
03650 --*/
03651 {
03652 
03653     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
03654     PIO_STACK_LOCATION irpStack;
03655 
03656     PAGED_CODE();
03657 
03658     //
03659     // Write length to SRB.
03660     //
03661 
03662     Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
03663 
03664     //
03665     // Set SCSI bus address.
03666     //
03667 
03668     Srb->PathId = deviceExtension->PathId;
03669     Srb->TargetId = deviceExtension->TargetId;
03670     Srb->Lun = deviceExtension->Lun;
03671 
03672     Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
03673 
03674     //
03675     // This is a violation of the SCSI spec but it is required for
03676     // some targets.
03677     //
03678 
03679     Srb->Cdb[1] |= deviceExtension->Lun << 5;
03680 
03681     //
03682     // Indicate auto request sense by specifying buffer and size.
03683     //
03684 
03685     Srb->SenseInfoBuffer = deviceExtension->SenseData;
03686     Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
03687     Srb->DataBuffer = BufferAddress;
03688 
03689     if (BufferAddress != NULL) {
03690 
03691         //
03692         // Build Mdl if necessary.
03693         //
03694 
03695         if (Irp->MdlAddress == NULL) {
03696 
03697             if (IoAllocateMdl(BufferAddress,
03698                               BufferLength,
03699                               FALSE,
03700                               FALSE,
03701                               Irp) == NULL) {
03702 
03703                 return(STATUS_INSUFFICIENT_RESOURCES);
03704             }
03705 
03706             MmBuildMdlForNonPagedPool(Irp->MdlAddress);
03707 
03708         } else {
03709 
03710             //
03711             // Make sure the buffer requested matches the MDL.
03712             //
03713 
03714             ASSERT(BufferAddress == MmGetMdlVirtualAddress(Irp->MdlAddress));
03715         }
03716 
03717         //
03718         // Set read flag.
03719         //
03720 
03721         Srb->SrbFlags = WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
03722 
03723     } else {
03724 
03725         //
03726         // Clear flags.
03727         //
03728 
03729         Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
03730     }
03731 
03732     //
03733     // Disable synchronous transfer for these requests.
03734     //
03735 
03736     Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
03737 
03738     //
03739     // Set the transfer length.
03740     //
03741 
03742     Srb->DataTransferLength = BufferLength;
03743 
03744     //
03745     // Zero out status.
03746     //
03747 
03748     Srb->ScsiStatus = Srb->SrbStatus = 0;
03749 
03750     Srb->NextSrb = 0;
03751 
03752     //
03753     // Save a few parameters in the current stack location.
03754     //
03755 
03756     irpStack = IoGetCurrentIrpStackLocation(Irp);
03757 
03758     //
03759     // Save retry count in current Irp stack.
03760     //
03761 
03762     irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
03763 
03764     //
03765     // Set up IoCompletion routine address.
03766     //
03767 
03768     IoSetCompletionRoutine(Irp, ScsiClassIoComplete, Srb, TRUE, TRUE, TRUE);
03769 
03770     //
03771     // Get next stack location and
03772     // set major function code.
03773     //
03774 
03775     irpStack = IoGetNextIrpStackLocation(Irp);
03776 
03777     irpStack->MajorFunction = IRP_MJ_SCSI;
03778 
03779     //
03780     // Save SRB address in next stack for port driver.
03781     //
03782 
03783     irpStack->Parameters.Scsi.Srb = Srb;
03784 
03785     //
03786     // Set up Irp Address.
03787     //
03788 
03789     Srb->OriginalRequest = Irp;
03790 
03791     //
03792     // Call the port driver to process the request.
03793     //
03794 
03795     return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
03796 
03797 }
03798 
03799 
03800 NTSTATUS
03801 NTAPI
03802 ScsiClassDeviceControlDispatch(
03803     PDEVICE_OBJECT DeviceObject,
03804     PIRP Irp
03805     )
03806 
03807 /*++
03808 
03809 Routine Description:
03810 
03811     The routine is the common class driver device control dispatch entry point.
03812     This routine is invokes the device-specific drivers DeviceControl routine,
03813     (which may call the Class driver's common DeviceControl routine).
03814 
03815 Arguments:
03816 
03817     DeviceObject - Supplies a pointer to the device object for this request.
03818 
03819     Irp - Supplies the Irp making the request.
03820 
03821 Return Value:
03822 
03823    Returns the status returned from the device-specific driver.
03824 
03825 --*/
03826 
03827 {
03828 
03829     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
03830 
03831 
03832     //
03833     // Call the class specific driver DeviceControl routine.
03834     // If it doesn't handle it, it will call back into ScsiClassDeviceControl.
03835     //
03836 
03837     ASSERT(deviceExtension->ClassDeviceControl);
03838 
03839     return deviceExtension->ClassDeviceControl(DeviceObject,Irp);
03840 }
03841 
03842 
03843 NTSTATUS
03844 NTAPI
03845 ScsiClassDeviceControl(
03846     PDEVICE_OBJECT DeviceObject,
03847     PIRP Irp
03848     )
03849 /*++
03850 
03851 Routine Description:
03852 
03853     The routine is the common class driver device control dispatch function.
03854     This routine is called by a class driver when it get an unrecognized
03855     device control request.  This routine will perform the correct action for
03856     common requests such as lock media.  If the device request is unknown it
03857     passed down to the next level.
03858 
03859 Arguments:
03860 
03861     DeviceObject - Supplies a pointer to the device object for this request.
03862 
03863     Irp - Supplies the Irp making the request.
03864 
03865 Return Value:
03866 
03867    Returns back a STATUS_PENDING or a completion status.
03868 
03869 --*/
03870 
03871 {
03872     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
03873     PIO_STACK_LOCATION nextStack;
03874     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
03875     PSCSI_REQUEST_BLOCK srb;
03876     PCDB cdb;
03877     NTSTATUS status;
03878     ULONG modifiedIoControlCode;
03879 
03880     if (irpStack->Parameters.DeviceIoControl.IoControlCode ==
03881         IOCTL_STORAGE_RESET_DEVICE) {
03882 
03883         Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
03884         IoCompleteRequest(Irp, IO_NO_INCREMENT);
03885         status = STATUS_UNSUCCESSFUL;
03886         goto SetStatusAndReturn;
03887     }
03888 
03889     //
03890     // If this is a pass through I/O control, set the minor function code
03891     // and device address and pass it to the port driver.
03892     //
03893 
03894     if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH
03895         || irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) {
03896 
03897         PSCSI_PASS_THROUGH scsiPass;
03898 
03899         nextStack = IoGetNextIrpStackLocation(Irp);
03900 
03901         //
03902         // Validiate the user buffer.
03903         //
03904 
03905         if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH)){
03906 
03907             Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
03908             IoCompleteRequest(Irp, IO_NO_INCREMENT);
03909             status = STATUS_INVALID_PARAMETER;
03910             goto SetStatusAndReturn;
03911         }
03912 
03913         //
03914         // Force the SCSI address to the correct value.
03915         //
03916 
03917         scsiPass = Irp->AssociatedIrp.SystemBuffer;
03918         scsiPass->PathId = deviceExtension->PathId;
03919         scsiPass->TargetId = deviceExtension->TargetId;
03920         scsiPass->Lun = deviceExtension->Lun;
03921 
03922         //
03923         // NOTICE:  The SCSI-II specificaiton indicates that this field
03924         // should be zero; however, some target controllers ignore the logical
03925         // unit number in the INDENTIFY message and only look at the logical
03926         // unit number field in the CDB.
03927         //
03928 
03929         scsiPass->Cdb[1] |= deviceExtension->Lun << 5;
03930 
03931         nextStack->Parameters = irpStack->Parameters;
03932         nextStack->MajorFunction = irpStack->MajorFunction;
03933         nextStack->MinorFunction = IRP_MN_SCSI_CLASS;
03934 
03935         status = IoCallDriver(deviceExtension->PortDeviceObject, Irp);
03936         goto SetStatusAndReturn;
03937     }
03938 
03939     if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_ADDRESS) {
03940 
03941         PSCSI_ADDRESS scsiAddress = Irp->AssociatedIrp.SystemBuffer;
03942 
03943         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
03944             sizeof(SCSI_ADDRESS)) {
03945 
03946             //
03947             // Indicate unsuccessful status and no data transferred.
03948             //
03949 
03950             Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
03951             Irp->IoStatus.Information = 0;
03952             IoCompleteRequest(Irp, IO_NO_INCREMENT);
03953             status = STATUS_BUFFER_TOO_SMALL;
03954             goto SetStatusAndReturn;
03955 
03956         }
03957 
03958         scsiAddress->Length = sizeof(SCSI_ADDRESS);
03959         scsiAddress->PortNumber = deviceExtension->PortNumber;
03960         scsiAddress->PathId = deviceExtension->PathId;
03961         scsiAddress->TargetId = deviceExtension->TargetId;
03962         scsiAddress->Lun = deviceExtension->Lun;
03963         Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
03964         Irp->IoStatus.Status = STATUS_SUCCESS;
03965         IoCompleteRequest(Irp, IO_NO_INCREMENT);
03966         status = STATUS_SUCCESS;
03967         goto SetStatusAndReturn;
03968     }
03969 
03970     srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
03971 
03972     if (srb == NULL) {
03973 
03974         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
03975         IoCompleteRequest(Irp, IO_NO_INCREMENT);
03976         status = STATUS_INSUFFICIENT_RESOURCES;
03977         goto SetStatusAndReturn;
03978     }
03979 
03980     //
03981     // Write zeros to Srb.
03982     //
03983 
03984     RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
03985 
03986     cdb = (PCDB)srb->Cdb;
03987 
03988     //
03989     // Change the device type to disk for the switch statement.
03990     //
03991 
03992     modifiedIoControlCode = (irpStack->Parameters.DeviceIoControl.IoControlCode
03993         & ~0xffff0000) | (IOCTL_DISK_BASE << 16);
03994 
03995     switch (modifiedIoControlCode) {
03996 
03997     case IOCTL_DISK_CHECK_VERIFY: {
03998 
03999         PIRP irp2 = NULL;
04000         PIO_STACK_LOCATION newStack;
04001 
04002         DebugPrint((1,"ScsiDeviceIoControl: Check verify\n"));
04003 
04004         //
04005         // If a buffer for a media change count was provided, make sure it's
04006         // big enough to hold the result
04007         //
04008 
04009         if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
04010 
04011             //
04012             // If the buffer is too small to hold the media change count
04013             // then return an error to the caller
04014             //
04015 
04016             if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
04017                sizeof(ULONG)) {
04018 
04019                 DebugPrint((3,"ScsiDeviceIoControl: media count "
04020                               "buffer too small\n"));
04021 
04022                 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
04023                 Irp->IoStatus.Information = 0;
04024                 ExFreePool(srb);
04025                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
04026                 status = STATUS_BUFFER_TOO_SMALL;
04027                 goto SetStatusAndReturn;
04028 
04029             }
04030 
04031             //
04032             // The caller has provided a valid buffer.  Allocate an additional
04033             // irp and stick the CheckVerify completion routine on it.  We will
04034             // then send this down to the port driver instead of the irp the
04035             // caller sent in
04036             //
04037 
04038             DebugPrint((2,"ScsiDeviceIoControl: Check verify wants "
04039                           "media count\n"));
04040 
04041             //
04042             // Allocate a new irp to send the TestUnitReady to the port driver
04043             //
04044 
04045             irp2 = IoAllocateIrp((CCHAR) (DeviceObject->StackSize + 3), FALSE);
04046 
04047             if(irp2 == NULL) {
04048                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
04049                 Irp->IoStatus.Information = 0;
04050                 ExFreePool(srb);
04051                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
04052                 status = STATUS_INSUFFICIENT_RESOURCES;
04053                 goto SetStatusAndReturn;
04054 
04055                 break;
04056             }
04057 
04058             irp2->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
04059             IoSetNextIrpStackLocation(irp2);
04060 
04061             //
04062             // Set the top stack location and shove the master Irp into the
04063             // top location
04064             //
04065 
04066             newStack = IoGetCurrentIrpStackLocation(irp2);
04067             newStack->Parameters.Others.Argument1 = Irp;
04068             newStack->DeviceObject = DeviceObject;
04069 
04070             //
04071             // Stick the check verify completion routine onto the stack
04072             // and prepare the irp for the port driver
04073             //
04074 
04075             IoSetCompletionRoutine(irp2,
04076                                    ScsiClassCheckVerifyComplete,
04077                                    NULL,
04078                                    TRUE,
04079                                    TRUE,
04080                                    TRUE);
04081 
04082             IoSetNextIrpStackLocation(irp2);
04083             newStack = IoGetCurrentIrpStackLocation(irp2);
04084             newStack->DeviceObject = DeviceObject;
04085 
04086             //
04087             // Mark the master irp as pending - whether the lower level
04088             // driver completes it immediately or not this should allow it
04089             // to go all the way back up.
04090             //
04091 
04092             IoMarkIrpPending(Irp);
04093 
04094             Irp = irp2;
04095 
04096         }
04097 
04098         //
04099         // Test Unit Ready
04100         //
04101 
04102         srb->CdbLength = 6;
04103         cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
04104 
04105         //
04106         // Set timeout value.
04107         //
04108 
04109         srb->TimeOutValue = deviceExtension->TimeOutValue;
04110 
04111         //
04112         // Since this routine will always hand the request to the
04113         // port driver if there isn't a data transfer to be done
04114         // we don't have to worry about completing the request here
04115         // on an error
04116         //
04117 
04118         status = ScsiClassSendSrbAsynchronous(DeviceObject,
04119                                               srb,
04120                                               Irp,
04121                                               NULL,
04122                                               0,
04123                                               FALSE);
04124 
04125         break;
04126     }
04127 
04128     case IOCTL_DISK_MEDIA_REMOVAL: {
04129 
04130         PPREVENT_MEDIA_REMOVAL MediaRemoval = Irp->AssociatedIrp.SystemBuffer;
04131 
04132         //
04133         // Prevent/Allow media removal.
04134         //
04135 
04136         DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n"));
04137 
04138         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
04139             sizeof(PREVENT_MEDIA_REMOVAL)) {
04140 
04141             //
04142             // Indicate unsuccessful status and no data transferred.
04143             //
04144 
04145             Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
04146             Irp->IoStatus.Information = 0;
04147             ExFreePool(srb);
04148             IoCompleteRequest(Irp, IO_NO_INCREMENT);
04149             status = STATUS_BUFFER_TOO_SMALL;
04150             goto SetStatusAndReturn;
04151         }
04152 
04153         //
04154         // Get physical device extension. This is where the
04155         // lock count is stored.
04156         //
04157 
04158         deviceExtension = deviceExtension->PhysicalDevice->DeviceExtension;
04159 
04160         //
04161         // If command succeeded then increment or decrement lock counter.
04162         //
04163 
04164         if (MediaRemoval->PreventMediaRemoval) {
04165 
04166             //
04167             // This is a lock command. Reissue the command in case bus or device
04168             // was reset and lock cleared.
04169             //
04170 
04171             InterlockedIncrement(&deviceExtension->LockCount);
04172 
04173             DebugPrint((1,
04174                        "ScsiClassDeviceControl: Lock media, lock count %x on disk %x\n",
04175                        deviceExtension->LockCount,
04176                        deviceExtension->DeviceNumber));
04177 
04178         } else {
04179 
04180             //
04181             // This is an unlock command.
04182             //
04183 
04184             if (!deviceExtension->LockCount ||
04185                 (InterlockedDecrement(&deviceExtension->LockCount) != 0)) {
04186 
04187                 DebugPrint((1,
04188                            "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
04189                            deviceExtension->LockCount,
04190                            deviceExtension->DeviceNumber));
04191 
04192                 //
04193                 // Don't unlock because someone still wants it locked.
04194                 //
04195 
04196                 Irp->IoStatus.Status = STATUS_SUCCESS;
04197                 ExFreePool(srb);
04198                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
04199                 status = STATUS_SUCCESS;
04200                 goto SetStatusAndReturn;
04201             }
04202 
04203             DebugPrint((1,
04204                        "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
04205                        deviceExtension->LockCount,
04206                        deviceExtension->DeviceNumber));
04207         }
04208 
04209         srb->CdbLength = 6;
04210 
04211         cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
04212 
04213         //
04214         // TRUE - prevent media removal.
04215         // FALSE - allow media removal.
04216         //
04217 
04218         cdb->MEDIA_REMOVAL.Prevent = MediaRemoval->PreventMediaRemoval;
04219 
04220         //
04221         // Set timeout value.
04222         //
04223 
04224         srb->TimeOutValue = deviceExtension->TimeOutValue;
04225         status = ScsiClassSendSrbAsynchronous(DeviceObject,
04226                                               srb,
04227                                               Irp,
04228                                               NULL,
04229                                               0,
04230                                               FALSE);
04231 
04232         //
04233         // Some devices will not support lock/unlock.
04234         // Pretend that it worked.
04235         //
04236 
04237         break;
04238    }
04239 
04240    case IOCTL_DISK_RESERVE: {
04241 
04242         //
04243         // Reserve logical unit.
04244         //
04245 
04246         srb->CdbLength = 6;
04247 
04248         cdb->CDB6GENERIC.OperationCode = SCSIOP_RESERVE_UNIT;
04249 
04250         //
04251         // Set timeout value.
04252         //
04253 
04254         srb->TimeOutValue = deviceExtension->TimeOutValue;
04255 
04256         status = ScsiClassSendSrbAsynchronous(DeviceObject,
04257                                               srb,
04258                                               Irp,
04259                                               NULL,
04260                                               0,
04261                                               FALSE);
04262 
04263         break;
04264     }
04265 
04266     case IOCTL_DISK_RELEASE: {
04267 
04268         //
04269         // Release logical unit.
04270         //
04271 
04272         srb->CdbLength = 6;
04273 
04274         cdb->CDB6GENERIC.OperationCode = SCSIOP_RELEASE_UNIT;
04275 
04276         //
04277         // Set timeout value.
04278         //
04279 
04280         srb->TimeOutValue = deviceExtension->TimeOutValue;
04281 
04282         status = ScsiClassSendSrbAsynchronous(DeviceObject,
04283                                               srb,
04284                                               Irp,
04285                                               NULL,
04286                                               0,
04287                                               FALSE);
04288 
04289         break;
04290     }
04291 
04292     case IOCTL_DISK_EJECT_MEDIA: {
04293 
04294         //
04295         // Eject media.
04296         //
04297 
04298         srb->CdbLength = 6;
04299 
04300         cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
04301         cdb->START_STOP.LoadEject = 1;
04302         cdb->START_STOP.Start     = 0;
04303 
04304         //
04305         // Set timeout value.
04306         //
04307 
04308         srb->TimeOutValue = deviceExtension->TimeOutValue;
04309         status = ScsiClassSendSrbAsynchronous(DeviceObject,
04310                                               srb,
04311                                               Irp,
04312                                               NULL,
04313                                               0,
04314                                               FALSE);
04315         break;
04316     }
04317 
04318     case IOCTL_DISK_LOAD_MEDIA: {
04319 
04320         //
04321         // Load media.
04322         //
04323 
04324         DebugPrint((3,"CdRomDeviceControl: Load media\n"));
04325 
04326         srb->CdbLength = 6;
04327 
04328         cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
04329         cdb->START_STOP.LoadEject = 1;
04330         cdb->START_STOP.Start     = 1;
04331 
04332         //
04333         // Set timeout value.
04334         //
04335 
04336         srb->TimeOutValue = deviceExtension->TimeOutValue;
04337         status = ScsiClassSendSrbAsynchronous(DeviceObject,
04338                                                srb,
04339                                                Irp,
04340                                                NULL,
04341                                                0,
04342                                                FALSE);
04343 
04344         break;
04345     }
04346 
04347     case IOCTL_DISK_FIND_NEW_DEVICES: {
04348 
04349         //
04350         // Search for devices that have been powered on since the last
04351         // device search or system initialization.
04352         //
04353 
04354         DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
04355         status = DriverEntry(DeviceObject->DriverObject,
04356                              NULL);
04357 
04358         Irp->IoStatus.Status = status;
04359         ExFreePool(srb);
04360         IoCompleteRequest(Irp, IO_NO_INCREMENT);
04361 
04362         break;
04363     }
04364 
04365     default: {
04366 
04367         DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
04368 
04369         //
04370         // Pass the device control to the next driver.
04371         //
04372 
04373         ExFreePool(srb);
04374 
04375         //
04376         // Copy the Irp stack parameters to the next stack location.
04377         //
04378 
04379         nextStack = IoGetNextIrpStackLocation(Irp);
04380         nextStack->Parameters = irpStack->Parameters;
04381         nextStack->MajorFunction = irpStack->MajorFunction;
04382         nextStack->MinorFunction = irpStack->MinorFunction;
04383 
04384         status =  IoCallDriver(deviceExtension->PortDeviceObject, Irp);
04385         break;
04386     }
04387 
04388     } // end switch( ...
04389 
04390 SetStatusAndReturn:
04391 
04392     return status;
04393 }
04394 
04395 
04396 NTSTATUS
04397 NTAPI
04398 ScsiClassShutdownFlush(
04399     IN PDEVICE_OBJECT DeviceObject,
04400     IN PIRP Irp
04401     )
04402 
04403 /*++
04404 
04405 Routine Description:
04406 
04407     This routine is called for a shutdown and flush IRPs.  These are sent by the
04408     system before it actually shuts down or when the file system does a flush.
04409     If it exists, the device-specific driver's routine will be invoked. If there
04410     wasn't one specified, the Irp will be completed with an Invalid device request.
04411 
04412 Arguments:
04413 
04414     DriverObject - Pointer to device object to being shutdown by system.
04415 
04416     Irp - IRP involved.
04417 
04418 Return Value:
04419 
04420     NT Status
04421 
04422 --*/
04423 
04424 {
04425     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
04426 
04427     if (deviceExtension->ClassShutdownFlush) {
04428 
04429         //
04430         // Call the device-specific driver's routine.
04431         //
04432 
04433         return deviceExtension->ClassShutdownFlush(DeviceObject, Irp);
04434     }
04435 
04436     //
04437     // Device-specific driver doesn't support this.
04438     //
04439 
04440     Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
04441     IoCompleteRequest(Irp, IO_NO_INCREMENT);
04442 
04443     return STATUS_INVALID_DEVICE_REQUEST;
04444 }
04445 
04446 
04447 ULONG
04448 NTAPI
04449 ScsiClassFindUnclaimedDevices(
04450     IN PCLASS_INIT_DATA InitializationData,
04451     IN PSCSI_ADAPTER_BUS_INFO  AdapterInformation
04452     )
04453 
04454 {
04455     ULONG scsiBus,deviceCount = 0;
04456     PCHAR buffer = (PCHAR)AdapterInformation;
04457     PSCSI_INQUIRY_DATA lunInfo;
04458     PINQUIRYDATA inquiryData;
04459 
04460     for (scsiBus=0; scsiBus < (ULONG)AdapterInformation->NumberOfBuses; scsiBus++) {
04461 
04462         //
04463         // Get the SCSI bus scan data for this bus.
04464         //
04465 
04466         lunInfo = (PVOID) (buffer + AdapterInformation->BusData[scsiBus].InquiryDataOffset);
04467 
04468         //
04469         // Search list for unclaimed disk devices.
04470         //
04471 
04472         while (AdapterInformation->BusData[scsiBus].InquiryDataOffset) {
04473 
04474             inquiryData = (PVOID)lunInfo->InquiryData;
04475 
04476             ASSERT(InitializationData->ClassFindDeviceCallBack);
04477 
04478             if ((InitializationData->ClassFindDeviceCallBack(inquiryData)) && (!lunInfo->DeviceClaimed)) {
04479 
04480                 deviceCount++;
04481             }
04482 
04483             if (lunInfo->NextInquiryDataOffset == 0) {
04484                 break;
04485             }
04486 
04487             lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
04488         }
04489     }
04490     return deviceCount;
04491 }
04492 
04493 
04494 
04495 NTSTATUS
04496 NTAPI
04497 ScsiClassCreateDeviceObject(
04498     IN PDRIVER_OBJECT          DriverObject,
04499     IN PCCHAR                  ObjectNameBuffer,
04500     IN OPTIONAL PDEVICE_OBJECT PhysicalDeviceObject,
04501     IN OUT PDEVICE_OBJECT      *DeviceObject,
04502     IN PCLASS_INIT_DATA        InitializationData
04503     )
04504 
04505 /*++
04506 
04507 Routine Description:
04508 
04509     This routine creates an object for the physical device specified and
04510     sets up the deviceExtension's function pointers for each entry point
04511     in the device-specific driver.
04512 
04513 Arguments:
04514 
04515     DriverObject - Pointer to driver object created by system.
04516 
04517     ObjectNameBuffer - Dir. name of the object to create.
04518 
04519     PhysicalDeviceObject - Pointer to the physical (class) device object for
04520                            this logical unit or NULL if this is it.
04521 
04522     DeviceObject - Pointer to the device object pointer we will return.
04523 
04524     InitializationData - Pointer to the init data created by the device-specific driver.
04525 
04526 Return Value:
04527 
04528     NTSTATUS
04529 
04530 --*/
04531 
04532 {
04533     STRING         ntNameString;
04534     UNICODE_STRING ntUnicodeString;
04535     NTSTATUS       status;
04536     PDEVICE_OBJECT deviceObject = NULL;
04537 
04538     *DeviceObject = NULL;
04539 
04540     DebugPrint((2,
04541                 "ScsiClassCreateDeviceObject: Create device object %s\n",
04542                 ObjectNameBuffer));
04543 
04544     RtlInitString(&ntNameString,
04545                   ObjectNameBuffer);
04546 
04547     status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
04548                                           &ntNameString,
04549                                           TRUE);
04550 
04551     if (!NT_SUCCESS(status)) {
04552 
04553         DebugPrint((1,
04554                     "CreateDiskDeviceObjects: Cannot convert string %s\n",
04555                     ObjectNameBuffer));
04556 
04557         ntUnicodeString.Buffer = NULL;
04558         return status;
04559     }
04560 
04561     status = IoCreateDevice(DriverObject,
04562                             InitializationData->DeviceExtensionSize,
04563                             &ntUnicodeString,
04564                             InitializationData->DeviceType,
04565                             InitializationData->DeviceCharacteristics,
04566                             FALSE,
04567                             &deviceObject);
04568 
04569 
04570     if (!NT_SUCCESS(status)) {
04571 
04572         DebugPrint((1,
04573                     "CreateDiskDeviceObjects: Can not create device object %s\n",
04574                     ObjectNameBuffer));
04575 
04576     } else {
04577 
04578         PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
04579 
04580         //
04581         // Fill in entry points
04582         //
04583 
04584         deviceExtension->ClassError                 = InitializationData->ClassError;
04585         deviceExtension->ClassReadWriteVerification = InitializationData->ClassReadWriteVerification;
04586         deviceExtension->ClassFindDevices           = InitializationData->ClassFindDevices;
04587         deviceExtension->ClassDeviceControl         = InitializationData->ClassDeviceControl;
04588         deviceExtension->ClassShutdownFlush         = InitializationData->ClassShutdownFlush;
04589         deviceExtension->ClassCreateClose           = InitializationData->ClassCreateClose;
04590         deviceExtension->ClassStartIo               = InitializationData->ClassStartIo;
04591 
04592         deviceExtension->MediaChangeCount = 0;
04593 
04594         //
04595         // If a pointer to the physical device object was passed in then use
04596         // that.  If the value was NULL, then this is the physical device so
04597         // use the pointer to the device we just created.
04598         //
04599 
04600         if(ARGUMENT_PRESENT(PhysicalDeviceObject)) {
04601             deviceExtension->PhysicalDevice = PhysicalDeviceObject;
04602         } else {
04603             deviceExtension->PhysicalDevice = deviceObject;
04604         }
04605     }
04606 
04607     deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
04608 
04609     *DeviceObject = deviceObject;
04610 
04611     RtlFreeUnicodeString(&ntUnicodeString);
04612 
04613     //
04614     // Indicate the ntUnicodeString is free.
04615     //
04616 
04617     ntUnicodeString.Buffer = NULL;
04618 
04619     return status;
04620 }
04621 
04622 
04623 NTSTATUS
04624 NTAPI
04625 ScsiClassClaimDevice(
04626     IN PDEVICE_OBJECT PortDeviceObject,
04627     IN PSCSI_INQUIRY_DATA LunInfo,
04628     IN BOOLEAN Release,
04629     OUT PDEVICE_OBJECT *NewPortDeviceObject OPTIONAL
04630     )
04631 /*++
04632 
04633 Routine Description:
04634 
04635     This function claims a device in the port driver.  The port driver object
04636     is updated with the correct driver object if the device is successfully
04637     claimed.
04638 
04639 Arguments:
04640 
04641     PortDeviceObject - Supplies the base port device object.
04642 
04643     LunInfo - Supplies the logical unit inforamtion of the device to be claimed.
04644 
04645     Release - Indicates the logical unit should be released rather than claimed.
04646 
04647     NewPortDeviceObject - Returns the updated port device object to be used
04648         for all future accesses.
04649 
04650 Return Value:
04651 
04652     Returns a status indicating success or failure of the operation.
04653 
04654 --*/
04655 
04656 {
04657     IO_STATUS_BLOCK    ioStatus;
04658     PIRP               irp;
04659     PIO_STACK_LOCATION irpStack;
04660     KEVENT             event;
04661     NTSTATUS           status;
04662     SCSI_REQUEST_BLOCK srb;
04663 
04664     PAGED_CODE();
04665 
04666     if (NewPortDeviceObject != NULL) {
04667         *NewPortDeviceObject = NULL;
04668     }
04669 
04670     //
04671     // Clear the SRB fields.
04672     //
04673 
04674     RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
04675 
04676     //
04677     // Write length to SRB.
04678     //
04679 
04680     srb.Length = SCSI_REQUEST_BLOCK_SIZE;
04681 
04682     //
04683     // Set SCSI bus address.
04684     //
04685 
04686     srb.PathId = LunInfo->PathId;
04687     srb.TargetId = LunInfo->TargetId;
04688     srb.Lun = LunInfo->Lun;
04689 
04690     srb.Function = Release ? SRB_FUNCTION_RELEASE_DEVICE :
04691         SRB_FUNCTION_CLAIM_DEVICE;
04692 
04693     //
04694     // Set the event object to the unsignaled state.
04695     // It will be used to signal request completion.
04696     //
04697 
04698     KeInitializeEvent(&event, NotificationEvent, FALSE);
04699 
04700     //
04701     // Build synchronous request with no transfer.
04702     //
04703 
04704     irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE,
04705                                         PortDeviceObject,
04706                                         NULL,
04707                                         0,
04708                                         NULL,
04709                                         0,
04710                                         TRUE,
04711                                         &event,
04712                                         &ioStatus);
04713 
04714     if (irp == NULL) {
04715 
04716         DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n"));
04717         return STATUS_INSUFFICIENT_RESOURCES;
04718     }
04719 
04720     irpStack = IoGetNextIrpStackLocation(irp);
04721 
04722     //
04723     // Save SRB address in next stack for port driver.
04724     //
04725 
04726     irpStack->Parameters.Scsi.Srb = &srb;
04727 
04728     //
04729     // Set up IRP Address.
04730     //
04731 
04732     srb.OriginalRequest = irp;
04733 
04734     //
04735     // Call the port driver with the request and wait for it to complete.
04736     //
04737 
04738     status = IoCallDriver(PortDeviceObject, irp);
04739     if (status == STATUS_PENDING) {
04740 
04741         KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
04742         status = ioStatus.Status;
04743     }
04744 
04745     //
04746     // If this is a release request, then just decrement the reference count
04747     // and return.  The status does not matter.
04748     //
04749 
04750     if (Release) {
04751 
04752         ObDereferenceObject(PortDeviceObject);
04753         return STATUS_SUCCESS;
04754     }
04755 
04756     if (!NT_SUCCESS(status)) {
04757         return status;
04758     }
04759 
04760     ASSERT(srb.DataBuffer != NULL);
04761 
04762     //
04763     // Reference the new port driver object so that it will not go away while
04764     // it is being used.
04765     //
04766 
04767     status = ObReferenceObjectByPointer(srb.DataBuffer,
04768                                         0,
04769                                         NULL,
04770                                         KernelMode );
04771 
04772     if (!NT_SUCCESS(status)) {
04773 
04774         return status;
04775     }
04776 
04777     //
04778     // Return the new port device object pointer.
04779     //
04780 
04781     if (NewPortDeviceObject != NULL) {
04782         *NewPortDeviceObject = srb.DataBuffer;
04783     }
04784 
04785     return status;
04786 }
04787 
04788 
04789 NTSTATUS
04790 NTAPI
04791 ScsiClassInternalIoControl (
04792     IN PDEVICE_OBJECT DeviceObject,
04793     IN PIRP Irp
04794     )
04795 
04796 /*++
04797 
04798 Routine Description:
04799 
04800     This routine passes internal device controls to the port driver.
04801     Internal device controls are used by higher level class drivers to
04802     send scsi requests to a device that are not normally sent by a generic
04803     class driver.
04804 
04805     The path ID, target ID and logical unit ID are set in the srb so the
04806     higher level driver does not have to figure out what values are actually
04807     used.
04808 
04809 Arguments:
04810 
04811     DeviceObject - Supplies a pointer to the device object for this request.
04812 
04813     Irp - Supplies the Irp making the request.
04814 
04815 Return Value:
04816 
04817    Returns back a STATUS_PENDING or a completion status.
04818 
04819 --*/
04820 {
04821     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
04822     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
04823     PSCSI_REQUEST_BLOCK srb;
04824 
04825     //
04826     // Get a pointer to the SRB.
04827     //
04828 
04829     srb = irpStack->Parameters.Scsi.Srb;
04830 
04831     //
04832     // Set SCSI bus address.
04833     //
04834 
04835     srb->PathId = deviceExtension->PathId;
04836     srb->TargetId = deviceExtension->TargetId;
04837     srb->Lun = deviceExtension->Lun;
04838 
04839     //
04840     // NOTICE:  The SCSI-II specificaiton indicates that this field should be
04841     // zero; however, some target controllers ignore the logical unit number
04842     // in the INDENTIFY message and only look at the logical unit number field
04843     // in the CDB.
04844     //
04845 
04846     srb->Cdb[1] |= deviceExtension->Lun << 5;
04847 
04848     //
04849     // Set the parameters in the next stack location.
04850     //
04851 
04852     irpStack = IoGetNextIrpStackLocation(Irp);
04853 
04854     irpStack->Parameters.Scsi.Srb = srb;
04855     irpStack->MajorFunction = IRP_MJ_SCSI;
04856     irpStack->MinorFunction = IRP_MN_SCSI_CLASS;
04857 
04858     IoSetCompletionRoutine(Irp, ClassIoCompletion, NULL, TRUE, TRUE, TRUE);
04859     return IoCallDriver(deviceExtension->PortDeviceObject, Irp);
04860 }
04861 
04862 NTSTATUS
04863 NTAPI
04864 ClassIoCompletion(
04865     IN PDEVICE_OBJECT DeviceObject,
04866     IN PIRP Irp,
04867     IN PVOID Context
04868     )
04869 
04870 /*++
04871 
04872 Routine Description:
04873 
04874     This routine is called when an internal device control I/O request
04875     has completed.  It marks the IRP pending if necessary and returns the
04876     status of the request.
04877 
04878 Arguments:
04879 
04880     DeviceObject - Target device object.
04881 
04882     Irp          - Completed request.
04883 
04884     Context      - not used.
04885 
04886 Return Value:
04887 
04888     Returns the status of the completed request.
04889 
04890 --*/
04891 
04892 {
04893     UNREFERENCED_PARAMETER(Context);
04894     UNREFERENCED_PARAMETER(DeviceObject);
04895 
04896     //
04897     // If pending is returned for this Irp then mark current stack
04898     // as pending
04899     //
04900 
04901     if (Irp->PendingReturned) {
04902 
04903         IoMarkIrpPending( Irp );
04904     }
04905 
04906     return Irp->IoStatus.Status;
04907 }
04908 
04909 
04910 VOID
04911 NTAPI
04912 ScsiClassInitializeSrbLookasideList(
04913     IN PDEVICE_EXTENSION DeviceExtension,
04914     IN ULONG NumberElements
04915     )
04916 
04917 /*++
04918 
04919 Routine Description:
04920 
04921     This routine sets up a lookaside listhead for srbs.
04922 
04923 Arguments:
04924 
04925     DeviceExtension - Pointer to the deviceExtension containing the listhead.
04926 
04927     NumberElements  - Supplies the maximum depth of the lookaside list.
04928 
04929 
04930 Return Value:
04931 
04932     None
04933 
04934 --*/
04935 
04936 {
04937     ExInitializeNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
04938                                     NULL,
04939                                     NULL,
04940                                     NonPagedPoolMustSucceed,
04941                                     SCSI_REQUEST_BLOCK_SIZE,
04942                                     'ScsH',
04943                                     (USHORT)NumberElements);
04944 
04945 }
04946 
04947 
04948 ULONG
04949 NTAPI
04950 ScsiClassQueryTimeOutRegistryValue(
04951     IN PUNICODE_STRING RegistryPath
04952     )
04953 
04954 /*++
04955 
04956 Routine Description:
04957 
04958     This routine determines whether a reg key for a user-specified timeout value exists.
04959 
04960 Arguments:
04961 
04962     RegistryPath - Pointer to the hardware reg. entry describing the key.
04963 
04964 Return Value:
04965 
04966     New default timeout for a class of devices.
04967 
04968 --*/
04969 
04970 {
04971     //
04972     // Find the appropriate reg. key
04973     //
04974 
04975     PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
04976     PWSTR path;
04977     NTSTATUS status;
04978     LONG     timeOut = 0;
04979     ULONG    zero = 0;
04980     ULONG    size;
04981 
04982     if (!RegistryPath) {
04983         return 0;
04984     }
04985 
04986     parameters = ExAllocatePool(NonPagedPool,
04987                                 sizeof(RTL_QUERY_REGISTRY_TABLE)*2);
04988 
04989     if (!parameters) {
04990         return 0;
04991     }
04992 
04993     size = RegistryPath->MaximumLength + sizeof(WCHAR);
04994     path = ExAllocatePool(NonPagedPool, size);
04995 
04996     if (!path) {
04997         ExFreePool(parameters);
04998         return 0;
04999     }
05000 
05001     RtlZeroMemory(path,size);
05002     RtlCopyMemory(path, RegistryPath->Buffer, size - sizeof(WCHAR));
05003 
05004 
05005     //
05006     // Check for the Timeout value.
05007     //
05008 
05009     RtlZeroMemory(parameters,
05010                   (sizeof(RTL_QUERY_REGISTRY_TABLE)*2));
05011 
05012     parameters[0].Flags         = RTL_QUERY_REGISTRY_DIRECT;
05013     parameters[0].Name          = L"TimeOutValue";
05014     parameters[0].EntryContext  = &timeOut;
05015     parameters[0].DefaultType   = REG_DWORD;
05016     parameters[0].DefaultData   = &zero;
05017     parameters[0].DefaultLength = sizeof(ULONG);
05018 
05019     status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
05020                                     path,
05021                                     parameters,
05022                                     NULL,
05023                                     NULL);
05024 
05025     if (!(NT_SUCCESS(status))) {
05026         timeOut = 0;
05027     }
05028 
05029     ExFreePool(parameters);
05030     ExFreePool(path);
05031 
05032     DebugPrint((2,
05033                 "ScsiClassQueryTimeOutRegistryValue: Timeout value %d\n",
05034                 timeOut));
05035 
05036 
05037     return timeOut;
05038 
05039 }
05040 
05041 NTSTATUS
05042 NTAPI
05043 ScsiClassCheckVerifyComplete(
05044     IN PDEVICE_OBJECT DeviceObject,
05045     IN PIRP Irp,
05046     IN PVOID Context
05047     )
05048 
05049 /*++
05050 
05051 Routine Description:
05052 
05053     This routine executes when the port driver has completed a check verify
05054     ioctl.  It will set the status of the master Irp, copy the media change
05055     count and complete the request.
05056 
05057 Arguments:
05058 
05059     DeviceObject - Supplies the device object which represents the logical
05060         unit.
05061 
05062     Irp - Supplies the Irp which has completed.
05063 
05064     Context - NULL
05065 
05066 Return Value:
05067 
05068     NT status
05069 
05070 --*/
05071 
05072 {
05073     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
05074     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
05075     PDEVICE_EXTENSION physicalExtension =
05076                         deviceExtension->PhysicalDevice->DeviceExtension;
05077     PIRP originalIrp;
05078 
05079     originalIrp = irpStack->Parameters.Others.Argument1;
05080 
05081     //
05082     // Copy the media change count and status
05083     //
05084 
05085     *((PULONG) (originalIrp->AssociatedIrp.SystemBuffer)) =
05086         physicalExtension->MediaChangeCount;
05087 
05088     DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change count for"
05089                    "device %d is %d\n",
05090                 physicalExtension->DeviceNumber,
05091                 physicalExtension->MediaChangeCount));
05092 
05093     originalIrp->IoStatus.Status = Irp->IoStatus.Status;
05094     originalIrp->IoStatus.Information = sizeof(ULONG);
05095 
05096     IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
05097 
05098     IoFreeIrp(Irp);
05099 
05100     return STATUS_MORE_PROCESSING_REQUIRED;
05101 }
05102 
05103 NTSTATUS
05104 NTAPI
05105 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
05106                        IN PIRP Irp,
05107                        IN PVOID Context)
05108 {
05109     PIO_STATUS_BLOCK IoStatusBlock = Irp->UserIosb;
05110     PKEVENT Event = Irp->UserEvent;
05111     PMDL Mdl;
05112 
05113     *IoStatusBlock = Irp->IoStatus;
05114     Irp->UserIosb = NULL;
05115     Irp->UserEvent = NULL;
05116 
05117     if(Irp->MdlAddress)
05118     {
05119         Mdl = Irp->MdlAddress;
05120 
05121         // if necessary - unlock pages
05122         if ((Mdl->MdlFlags & MDL_PAGES_LOCKED) &&
05123             !(Mdl->MdlFlags & MDL_PARTIAL_HAS_BEEN_MAPPED))
05124         {
05125                 MmUnlockPages(Mdl);
05126         }
05127 
05128         // free this mdl
05129         IoFreeMdl(Mdl);
05130     }
05131 
05132     // free irp and set event to unsignaled state
05133     IoFreeIrp(Irp);
05134     KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
05135 
05136     return STATUS_MORE_PROCESSING_REQUIRED;
05137 }

Generated on Fri May 25 2012 04:26:34 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.